0

I would like to reduce the number of rows in class definition and create __init __ attributes that have same name as __init __ arguments. Is this possible?

class Num():
    def __init__(self, arg1, arg2):
        self.arg3 = 'three'
        # some magic here

a = Num('one', 'two')  # instance

then

print(a.arg1)  # one
print(a.arg2)  # two
print(a.arg3)  # three
8
  • 1
    The current superclass of Num is object, whose __init__ method doesn't take any (non-self) parameters. Hence the error you didn't include in your post. I'm not entirely sure what you mean by the rest of the question. Commented Jan 7, 2022 at 15:17
  • 1
    Methods or attributes? Are you aware of dataclasses? When you say "inherit" do you mean inherit from another class? Commented Jan 7, 2022 at 15:17
  • 2
    @learning_python_self per your last edit, dataclasses are exactly what you are looking for. They generate an __init__ for you so you only need to specify the types of the arguments. You can also just add arg3: str = 'three' in the body to set your third arg. Commented Jan 7, 2022 at 15:37
  • 1
    There's little benefit to reducing the size of __init__ for its own sake. If you feel too many lines are taken up assigning arguments to attributes, that's possibly a sign that your class needs to be redesigned rather than needing to reduce boilerplate. Commented Jan 7, 2022 at 15:39
  • 1
    @learning_python_self The standard library has the same status as any other feature in Python. Commented Jan 7, 2022 at 15:39

1 Answer 1

1

If you wanted to infer it from the parameter list, you could do tricky stuff with locals():

class Num:
    def __init__(self, arg1, arg2):
        for var, val in locals().items():
            if var != 'self':
                self.__setattr__(var, val)
        self.arg3 = "three"


a = Num('one', 'two')  # instance
print(a.arg1)  # one
print(a.arg2)  # two
print(a.arg3)  # three

A better solution would be to use a dataclass:

from dataclasses import dataclass


@dataclass
class Num:
    arg1: str
    arg2: str
    arg3: str = "three"


a = Num('one', 'two')  # instance
print(a.arg1)  # one
print(a.arg2)  # two
print(a.arg3)  # three
Sign up to request clarification or add additional context in comments.

5 Comments

"mildly repetitive but much less confusing" -- don't most people often repeat argument names as class methods though, hence the use case?
Or just have a dataclass with a default for arg3, or post-init processing.
Wondering if something simpler than locals().items(), which otherwise works fine.... Dataclasses are a library, which I prefer to avoid but good to know nonetheless.
aha yes, dataclass with a default works as long as you don't need anything else in the init!
There is no reason to avoid modules in the standard library. Many of them incur no runtime overhead to import, because they are already baked into the interpreter. (dataclasses isn't one of those, but the overhead of importing it is negligible compared the time it takes the rest of a non-trivial script to execute.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.