4

I'm writing a class for something and I keep stumbling across the same tiresome to type out construction. Is there some simple way I can set up class so that all the parameters in the constructor get initialized as their own name, i.e. fish = 0 -> self.fish = fish?

class Example(object):
    def __init__(self, fish=0, birds=0, sheep=0):
        self.fish = fish
        self.birds = birds
        self.sheep = sheep
3
  • Why do you need such a strange pre-assignment? Commented Oct 20, 2013 at 13:31
  • So why don't you set the desired default as part of the default values specs in the constructor? Commented Oct 20, 2013 at 13:32
  • 3
    @user2799617 for new posters - sometimes the code formatting isn't always obvious... It certainly wouldn't hurt to include a link such as: stackoverflow.com/help/formatting so they have the resources to make an attempt to do so Commented Oct 20, 2013 at 13:33

3 Answers 3

5

For Python 3.7+, you can try using data classes in combination with type annotations.

https://docs.python.org/3/library/dataclasses.html

Import the module and use the decorator. Type-annotate your variables and there's no need to define an init method, because it will automatically be created for you.

from dataclasses import dataclass

@dataclass
class Example:
    fish: int = 0
    birds: int = 0
    sheep: int = 0
Sign up to request clarification or add additional context in comments.

Comments

4

Short answer: no. You are not required to initialize everything in the constructor (you could do it lazily), unless you need it immediately or expose it (meaning that you don't control access). But, since in Python you don't declare data fields, it will become difficult, much difficult, to track them all if they appear in different parts of the code.

More comprehensive answer: you could do some magic with **kwargs (which holds a dictionary of argument name/value pairs), but that is highly discouraged, because it makes documenting the changes almost impossible and difficult for users to check if a certain argument is accepted or not. Use it only for optional, internal flags. It could be useful when having 20 or more parameters to pass, but in that case I would suggest to rethink the design and cluster data.

In case you need a simple key/value storage, consider using a builtin, such as dict.

4 Comments

Okay, that's a shame. Yeah, I didn't want to use **kwargs for that reason. Thank you.
@JonClements, fair enough. Still, I wonder why someone downvoted. I don't see any blatant error here...
I'm guessing it's user2799617. I'm not allowed to upvote this comment because of my reputation level so I'm guessing I can't downvote either.
Don't worry Ashiataka, I was not concerned with the downvote per se. Instead, I think that he/she who downvotes should leave a comment saying what is wrong, so that the poster can fix (and learn from its own mistakes). This, unless the answer is completely wrong or misleading, of course. Downvoting is for serious errors, misinformation or wrong answers, not for people who disagree on different opinions...
3

You could use the inspect module:

import inspect

class Example(object):

    def __init__(self, fish=0, birds=0, sheep=0):
        frame = inspect.currentframe()
        args, _, _, values = inspect.getargvalues(frame)
        for i in args:
            setattr(self, i, values[i])

This works, but is more complicated that just setting them manually. It should be possible to hide this with a decorator:

@set_attributes
def __init__(self, fish=0, birds=0, sheep=0):
    pass

but defining set_attributes gets tricky because the decorator inserts another stack frame into the mix, and I can't quite get the details right.

1 Comment

it's terrible to do this, but +1 for answering the question

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.