I see patterns like
def __init__(self, x, y, z):
...
self.x = x
self.y = y
self.z = z
...
quite frequently, often with
You could also do:
locs = locals()
for arg in inspect.getargspec(self.__init__)[0][1:]:
setattr(self, arg, locs[arg])
Of course, you would have to import the inspect
module.
explicit is better than implicit ... so sure you could make it more concise:
def __init__(self,a,b,c):
for k,v in locals().items():
if k != "self":
setattr(self,k,v)
The better question is should you?
... that said if you want a named tuple I would recommend using a namedtuple (remember tuples have certain conditions attached to them) ... perhaps you want an ordereddict or even just a dict ...
To expand on gruszczy
s answer, I have used a pattern like:
class X:
x = None
y = None
z = None
def __init__(self, **kwargs):
for (k, v) in kwargs.items():
if hasattr(self, k):
setattr(self, k, v)
else:
raise TypeError('Unknown keyword argument: {:s}'.format(k))
I like this method because it:
super().__init(...)
)X.__init__
Prior to Python 3.6, this gives no control over the order in which the attributes are set, which could be a problem if some attributes are properties with setters that access other attributes.
It could probably be improved upon a bit, but I'm the only user of my own code so I am not worried about any form of input sanitation. Perhaps an AttributeError
would be more appropriate.
An interesting library that handles this (and avoids a lot of other boilerplate) is attrs. Your example, for instance, could be reduced to this (assume the class is called MyClass
):
import attr
@attr.s
class MyClass:
x = attr.ib()
y = attr.ib()
z = attr.ib()
You don't even need an __init__
method anymore, unless it does other stuff as well. Here's a nice introduction by Glyph Lefkowitz.
In Python 3.7, you may (ab)use the dataclass decorator, available from the dataclasses
module. From the documentation:
This module provides a decorator and functions for automatically adding generated special methods such as
__init__()
and__repr__()
to user-defined classes. It was originally described in PEP 557.The member variables to use in these generated methods are defined using PEP 526 type annotations. For example this code:
@dataclass class InventoryItem: '''Class for keeping track of an item in inventory.''' name: str unit_price: float quantity_on_hand: int = 0 def total_cost(self) -> float: return self.unit_price * self.quantity_on_hand
Will add, among other things, a
__init__()
that looks like:def __init__(self, name: str, unit_price: float, quantity_on_hand: int=0): self.name = name self.unit_price = unit_price self.quantity_on_hand = quantity_on_hand
Note that this method is automatically added to the class: it is not directly specified in the InventoryItem definition shown above.
If your class is large and complex, it may be inappropriate to use a dataclass
. I'm writing this on the day of release of Python 3.7.0, so usage patterns are not yet well established.
It's a natural way to do things in Python. Don't try to invent something more clever, it will lead to overly clever code that no one on your team will understand. If you want to be a team player and then keep writing it this way.