Is there a generally accepted best practice for creating a class whose instances will have many (non-defaultable) variables?
For example, by explicit arguments:
self.x = x
self.y = y
self.radius = radius
def __init__(self, **kwargs):
if 'x' in kwargs:
self.x = kwargs['x']
if 'y' in kwargs:
self.y = kwargs['y']
if 'radius' in kwargs:
self.radius = kwargs['radius']
or using properties:
def x(self, value):
self._x = value
def y(self, value):
self._y = value
def radius(self, value):
self._radius = value
For classes which implement a small number of instance variables (like the example above), it seems like the natural solution is to use explicit arguments, but this approach quickly becomes unruly as the number of variables grows. Is there a preferred approach when the number of instance variables grows lengthy?
Best How To :
Without really knowing the particulars of your situation, the classic answer is this: if your class initializer requires a whole bunch of arguments, then it is probably doing too much, and it should be factored into several classes.
Car class defined as such:
def __init__(self, tire_size, tire_tread, tire_age, paint_color,
paint_condition, engine_size, engine_horsepower):
self.tire_size = tire_size
self.tire_tread = tire_tread
self.engine_horsepower = engine_horsepower
Clearly a better approach would be to define
Paint classes (or
namedtuples) and pass instances of these into
def __init__(self, tire, paint, engine):
self.tire = tire
self.paint = paint
self.engine = engine
If something is required to make an instance of a class, for example,
radius in your
Circle class, it should be a required argument to
__init__ (or factored into a smaller class which is passed into
__init__, or set by an alternative constructor). The reason is this: IDEs, automatic documentation generators, code autocompleters, linters, and the like can read a method's argument list. If it's just
**kwargs, there's no information there. But if it has the names of the arguments you expect, then these tools can do their work.
Now, properties are pretty cool, but I'd hesitate to use them until necessary (and you'll know when they are necessary). Leave your attributes as they are and allow people to access them directly. If they shouldn't be set or changed, document it.
Lastly, if you really must have a whole bunch of arguments, but don't want to write a bunch of assignments in your
__init__, you might be interested in Alex Martelli's answer to a related question.