I have a class that takes a single parameter a
on instantiation, which is stored in the _a
attribute. For a number of methods (operators), I need to set also a _b
attribute on the result. This is currently implemented in a straight-forward way:
class SomeClass(object):
def __init__(self, a=0):
self._a = a
self._b = 0
def __add__(self, other):
result = self.__class__()
result._b = self._a + other._a
return result
Now, I have an number of members like _b
, such as _c
and _d
, so __add__
will need an extra line for each of these attributes. Being able to pass these on object instantiation would result in cleaner code:
class SomeClass(object):
def __init__(self, a=0, _b=0):
self._a = a
self._b = 0
def __add__(self, other):
return self.__class__(_b=self._a + other._a)
However, I don't want the user to pass values for all of the parameters, except for a
as _b
, _c
and _d
are implementation specifics. I could simply state in the docstring not to pass more than one argument. Preceding the 'private' attributes with an underscore is intended to reflect this.
Alternatively, I can try to make it harder for the user to misbehave, by providing a second, private constructor:
class SomeClass(object):
def __init__(self, a=0):
self._a = a
self._init()
def _init(self, _b=0):
self._b = _b
@classmethod
def _constructor(cls, a, _b):
obj = cls(a)
obj._init(b)
return obj
def __add__(self, other):
return self.__class__._constructor(_b=self._a + other._a)
I'm thinking this is a rather clunky solution.
What would be the preferred way to solve this problem? Are there other, more elegant, solutions? Is this really a problem; should I just use the first option and end up with some more lines of code?
The _
underscore convention is clear and prevalent through the python world.
You document your 'public' attributes, and just use default arguments with underscores to your __init__
method. Keep it simple.
If someone wants to screw up a class by using those private parameters anyway, you are not going to stop them, not in Python.
To tidy it up a tiny bit, you could set _b
before __init__
:
class SomeClass(object):
_b = 0
def __init__(self, a=0):
self._a = a
def __add__(self, other):
result = self.__class__()
result._b = self._a + other._a
return result
Or if there are heaps of private variables, put them into a list and do some magic?
class SomeClass(object):
calculated_vars = ['_b'] # All your calculated variables
def __init__(self, a=0):
self._a = a
def __getattr__(self, k):
if k in self.calculated_vars:
return 0 # Default value for calculated variables
else:
raise AttributeError('{} not found'.format(k))
def __add__(self, other):
result = self.__class__()
result._b = self._a + other._a
return result
if __name__ == '__main__':
i = SomeClass(1)
print '_a attr: ', i._a # 1
print '_b attr: ', i._b # 0 (Default value)
print '_c attr: ', i._c # AttributeError: _c not found
i2 = SomeClass(3)
i3 = i + i2
print '_b attr: ', i3._b # 4 (Calculated value)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.