"Private" arguments to __init__()? - python

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)

Related

Is there a method/interface specific for an attribute in Python?

Is there any way to have a method which processes the attributes and returns the desired value in python?
Below is the example of what i want to achieve.
class Foo():
self.a = '123'
self.b = '234'
def hex_value(self,attribute): # method for attribute.
return hex(attribute)
if __name__=="__main__":
obj = Foo()
print(obj.a.hex) # should give hex value of 'a' by simply using dot operator.
I feel a little dirty by hacking someting like this together, but you could use some kind of proxy class to do this:
class Proxy():
def __init__(self, value, parent):
self.value = value
self.parent = parent
def __getattr__(self, attr):
return self.parent.__getattribute__(attr + '_value')(self.value)
class Foo():
def __init__(self):
self.a = '123'
self.b = '234'
self.c = 'foo_Bar'
def hex_value(self,attribute):
return hex(int(attribute))
def repeated_value(self,attribute):
return attribute + " " + attribute + " " + attribute
def __getattribute__(self, attr):
if not attr.endswith('_value') and not attr.startswith('__'):
return Proxy(super(Foo, self).__getattribute__(attr), self)
return super(Foo, self).__getattribute__(attr)
if __name__=="__main__":
obj = Foo()
print(obj.a.hex) # should give hex value of 'a' by simply using dot operator.
print(obj.c.repeated) # prints 'foo_Bar foo_Bar foo_Bar'
The idea is that everything that you access in Foo is wrapped in a proxy. And everything you access in the proxy that's not avaiable is called on the proxy's creator (with an '_value' added) instead.
But just because you can doesn't mean you should.

Change dependent objects based on a class attribute

For example, if I have two classes :
class A:
def __init__(self):
self.a = 1;
def update(self, val):
self.a = val;
class B:
def __init__(self, default = A()):
self.b = default.a;
Using them :
object_a = A(); object_b = B(object_a);
Then, I would like to update the object_a.a attribute using object_a.update(update_val) but also concurrently update at all other dependent objects (object_b.b will also be updated to update_val).
How to do this in Python, is there a 'built-in' way?
I already have some manual solutions in mind, such as:
class A:
def __init__(self):
self.a = 1;
self.dependent = None;
def update(self, val):
self.a = val;
if self.dependent != None:
self.dependent.b = self.a;
class B:
def __init__(self, default = A()):
default.dependent = self;
self.b = default.a;
One way to accomplish what you are asking is use a mutable object, such as a list, to store the attribute's data. Since the objects will reference the list, changing the values of the list will be shared to both objects.
Here is a version that uses a list to store the underlying value, but maintains the attribute behavior .a and .b
class A:
def __init__(self):
self._a = [1]
def update(self, val):
self._a[0] = val
#property
def a(self):
return self._a[0]
class B:
def __init__(self, default):
self._b = default._a
#property
def b(self):
return self._b[0]
a = A()
b = B(a)
a.update(4)
b.b
# returns:
4

Dependent properties that are CPU intensive

I am very often confronted to this case and did not manage to discover a stable way to deal with it.
Suppose I have a class defined like that:
class MyClass(object):
def __init__(self, a, b):
self.a = a
self.b = b
#property
def c(self):
"""This method performs some heavy computations based on a and b properties"""
# Some heavy computations only with a and b attributes
return c
Property c may be now be retrieved by:
>>> obj = MyClass(a, b)
>>> print obj.c
However, every time I ask for obj.c, the heavy computations will be performed, resulting in a poor performance code as c results from heavy computations and it would preferably be calculated only while a or b is set or modified.
What would the better way to deal with this case ? I am thinking of creating a c_update method to use as a decorator for some #a.setter and #b.setter decorated methods but is that the better way ?
Regards,
But what if I have a lot of XX dependent properties that rely on a and b values. Do I have to write an update_XX method for each of them and add this method to init and to each a.setter and b.setter ? That seems to me quite verbose...
You can have the c value (and any other number of dependent properties) updated everytime either a or b is mutated, I implemented an update_properties() method below:
class MyClass(object):
def __init__(self, a, b):
self._a = a
self._b = b
self.update_properties()
#property
def a(self):
return self.a
#a.setter
def a(self, value):
self._a = value
self.update_properties()
#property
def b(self):
return self._b
#b.setter
def b(self, value):
self._b = value
self.update_properties()
def update_properties(self):
self.c = self._a + self._b
self.d = self._a * self._b
self.e = self._a - self._b
# self.f = ...
# ...
# self.z = ...
# Can go on as long as you want
Do you think it would be possible to implement this machinery as some decorators in order to lighten the code
The verbosity seems to be only on the side that tracks the free variables (e.g. here a and b), so if I had to support an arbitrary number of those, I would implement a MyClass.set_value(name, value)
def set_value(self, name, value):
setattr(self, name, value)
self.update_properties()
So the idea here is that our set_value() can work with an arbitrary number of attributes. And it's possible to call it from __init__ if you use **kwargs to unpack the key-values passed to the constructor.
One requirement here, since we haven't set the free variables as #property we're required to use obj.set_value('a', 42) instead of obj.a = 42
There is a small pypi package that fits well: cached-property
from cached_property import cached_property
class MyClass(object):
def __init__(self):
pass
#cached_property
def c(self):
# Heavy computation based on self.a / self.b
return ...
#property
def a(self):
return self._a
#a.setter
def a(self, value):
self._a = value
del self.c
#property
def b(self):
return self._b
#b.setter
def b(self, value):
self._b = value
del self.c
Of course you could also build an abstraction for the a/b properties on top of that, that utilizes del self.c.
One benefit of using cached_property is that you can easily make the cache thread-safe by changing it to threaded_cached_property.
I'd simply store the actual value of c in a private attribute and check if this is not None. Set this to None when either a or b changes.
So the "proper" way of doing this using properties would be:
class MyClass(object):
def __init__(self, a, b):
self._a = a
self._b = b
self._c = None
#property
def a(self):
return self._a
#a.setter
def a(self, value):
self._a = value
self._c = None
#property
def b(self):
return self._b
#b.setter
def a(self, value):
self._b = value
self._c = None
#property
def c(self):
if self._c is None:
self._c = # compute c here
return self._c
If you want to avoid creating all these properties and setters you probably want to hijack the __getattr__ and __setattr__ methods instead:
class MyClass(object):
def __init__(self, a, b):
self.a = a
self.b = b
self._c = None
def __getattr__(self, name):
if name == 'c':
if self._c is None:
self._c = # compute c here
return self._c
raise AttributeError(name)
def __setattr__(self, name, value):
if name == 'c':
raise TypeError('You cannot modify property c directly')
super(MyClass, self).__setattr__(name, value)
if name in ('a', 'b'):
super(MyClass, self).__setattr__('_c', None)
Note that this last solution could be extended to like 10 attributes a1, ..., a10 without having to define 10 properties and setters.
It's probably a bit less robust.
So based on your answers, I managed to build a new answer using a dict for dependent properties.
class MyClass(object):
def __init__(self, a, b):
self._properties = dict()
self._a = a
self._b = b
def _update_dependent_properties(self):
# Do computations for c1, c2...
self._properties['c1'] = # c1 value
self._properties['c2'] = # c2 value
# ...
#property
def a(self):
return self._a
#property
def b(self):
return self._b
#a.setter
def a(self, value):
self._properties.clean()
self._a = value
#b.setter
def b(self, value):
self._properties.clean()
self._b = value
#property
def c1(self):
try:
return self._properties['c1']
except KeyError:
_update_dependent_properties()
return self._properties['c1']
#property
def c2(self):
try:
return self._properties['c2']
except KeyError:
_update_dependent_properties()
return self._properties['c2']
This seem to do the trick but it is still quite verbose... and I have still to write a property for each of the dependent property I am expecting. However, it does force the calculation of update_dependent_properties() when either attribute a or b is modidied.
I wonder if it does not exist a module to do it. It seem that my problem sounds like memoize technique... and may a decorator lighten the code by systematizing the procedure ?

pythonic class instance attribute calculated from other attributes

I have a class instance with attributes that are calculated from other attributes. The attributes will change throughout the life of the instance. All attributes are not necessarily defined when the object is initialized.
what is the pythonic way to calculate attributes from other attributes?
This is a simple example, the calculations have numerous input variables ("a" below) and calculations ("b" & "c").
a = something
b = function of a (a+5)
c = function of a and b (a*b)
I've tried numerous implementations. Here is a decent one to communicate my intention.
class CalcAttr(object):
def __init__(self):
self._a = None
self._b = None
self._c = None
#property
def a(self):
return self._a
#a.setter
def a(self,value):
self._a = value
#property
def b(self):
self.calc_b()
return self._b
#property
def c(self):
self.calc_c()
return self._c
def calc_b(self):
self._b = self._a + 5
def calc_c(self):
self._c = self._a * self._b
def test():
abc = CalcAttr()
a = 5
return abc.c
Note: t.c works if I first call t.b first.
> >>> t=abc.test()
> >>> t.c Traceback (most recent call last): File "<stdin>", line 1, in <module> File "abc.py", line 22, in c
> self.calc_c() File "abc.py", line 29, in calc_c
> self._c = int(self._a) * int(self._b) TypeError: int() argument must be a string or a number, not 'NoneType'
> >>> t.b 10
> >>> t.c 50
> >>>
Keep in mind most of the real calculations are dependent on multiple attribures (5-10 input variables & as many calculated ones).
My next iteration will include a "calculate_model" function that will populate all calculated attributes after checking that all inputs are defined. Maybe that will be the pyhonic answer?
Thanks!
Update - working solution
I created a method that calculates each attribute in order:
def calc_model(self):
self.calc_b()
self.calc_c()
Each calculated attribute calls that method
#property
def c(self):
self.calc_model()
return self._c
I'm not sure if this is proper, but it works as desired...
If I understand your question correctly, you should compute b and c in their getters. You should also probably require that the user passes a value for a in the initializer, since b and c can't be computed without a. Also, it doesn't seem like there is much of a reason to keep _a, _b, and _c around -- unless b and c are expensive to compute and you'd like to cache them.
For example:
class CalcAttr(object):
def __init__(self, a):
self.a = a
#property
def b(self):
return self.a + 5
#property
def c(self):
return self.a * self.b
Such that
>>> x = CalcAttr(42)
>>> x.c
1974
I understand what #jme suggested in the accepted answer is more elegant, but I still try to fix the original example and get it to work. Here is the code.
class CalcAttr(object):
def __init__(self):
self._a = None
self._b = None
self._c = None
#property
def a(self):
return self._a
#a.setter
def a(self,value):
self._a = value
#property
def b(self):
self.calc_b()
return self._b
#property
def c(self):
self.calc_c()
return self._c
def calc_b(self):
self._b = self._a + 5
def calc_c(self):
self._c = self.a * self.b
def test():
abc = CalcAttr()
abc.a = 5
return abc.c
test()
The code will work and 50 is the resulted value.

Decorating arithmetic operators | should I be using a metaclass?

I'd like to implement an object, that bounds values within a given range after arithmetic operations have been applied to it. The code below works fine, but I'm pointlessly rewriting the methods. Surely there's a more elegant way of doing this. Is a metaclass the way to go?
def check_range(_operator):
def decorator1(instance,_val):
value = _operator(instance,_val)
if value > instance._upperbound:
value = instance._upperbound
if value < instance._lowerbound:
value = instance._lowerbound
instance.value = value
return Range(value, instance._lowerbound, instance._upperbound)
return decorator1
class Range(object):
'''
however you add, multiply or divide, it will always stay within boundaries
'''
def __init__(self, value, lowerbound, upperbound):
'''
#param lowerbound:
#param upperbound:
'''
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def init(self):
'''
set a random value within bounds
'''
self.value = random.uniform(self._lowerbound, self._upperbound)
def __str__(self):
return self.__repr__()
def __repr__(self):
return "<Range: %s>" % (self.value)
#check_range
def __mul__(self, other):
return self.value * other
#check_range
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self.div(other)
#check_range
def __add__(self, other):
return self.value + other
#check_range
def __sub__(self, other):
return self.value - other
It is possible to use a metaclass to apply a decorator to a set of function names, but I don't think that this is the way to go in your case. Applying the decorator in the class body on a function-by-function basis as you've done, with the #decorator syntax, I think is a very good option. (I think you've got a bug in your decorator, BTW: you probably do not want to set instance.value to anything; arithmetic operators usually don't mutate their operands).
Another approach I might use in your situation, kind of avoiding decorators all together, is to do something like this:
import operator
class Range(object):
def __init__(self, value, lowerbound, upperbound):
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def __repr__(self):
return "<Range: %s>" % (self.value)
def _from_value(self, val):
val = max(min(val, self._upperbound), self._lowerbound)
# NOTE: it's nice to use type(self) instead of writing the class
# name explicitly; it then continues to work if you change the
# class name, or use a subclass
return type(self)(val, rng._lowerbound, rng._upperbound)
def _make_binary_method(fn):
# this is NOT a method, just a helper function that is used
# while the class body is being evaluated
def bin_op(self, other):
return self._from_value(fn(self.value, other))
return bin_op
__mul__ = _make_binary_method(operator.mul)
__div__ = _make_binary_method(operator.truediv)
__truediv__ = __div__
__add__ = _make_binary_method(operator.add)
__sub__ = _make_binary_method(operator.sub)
rng = Range(7, 0, 10)
print rng + 5
print rng * 50
print rng - 10
print rng / 100
printing
<Range: 10>
<Range: 10>
<Range: 0>
<Range: 0.07>
I suggest that you do NOT use a metaclass in this circumstance, but here is one way you could. Metaclasses are a useful tool, and if you're interested, it's nice to understand how to use them for when you really need them.
def check_range(fn):
def wrapper(self, other):
value = fn(self, other)
value = max(min(value, self._upperbound), self._lowerbound)
return type(self)(value, self._lowerbound, self._upperbound)
return wrapper
class ApplyDecoratorsType(type):
def __init__(cls, name, bases, attrs):
for decorator, names in attrs.get('_auto_decorate', ()):
for name in names:
fn = attrs.get(name, None)
if fn is not None:
setattr(cls, name, decorator(fn))
class Range(object):
__metaclass__ = ApplyDecoratorsType
_auto_decorate = (
(check_range,
'__mul__ __div__ __truediv__ __add__ __sub__'.split()),
)
def __init__(self, value, lowerbound, upperbound):
self._lowerbound = lowerbound
self._upperbound = upperbound
self.value = value
def __repr__(self):
return "<Range: %s>" % (self.value)
def __mul__(self, other):
return self.value * other
def __div__(self, other):
return self.value / float(other)
def __truediv__(self, other):
return self / other
def __add__(self, other):
return self.value + other
def __sub__(self, other):
return self.value - other
As it is wisely said about metaclasses: if you wonder wether you need them, then you don't.
I don't fully understand your problem, but I would create a BoundedValue class, and us only instances of said class into the class you are proposing.
class BoundedValue(object):
default_lower = 0
default_upper = 1
def __init__(self, upper=None, lower=None):
self.upper = upper or BoundedValue.default_upper
self.lower = lower or BoundedValue.default_lower
#property
def val(self):
return self._val
#val.setter
def val(self, value):
assert self.lower <= value <= self.upper
self._val = value
v = BoundedValue()
v.val = 0.5 # Correctly assigns the value 0.5
print v.val # prints 0.5
v.val = 10 # Throws assertion error
Of course you could (and should) change the assertion for the actual behavior you are looking for; also you can change the constructor to include the initialization value. I chose to make it an assignment post-construction via the property val.
Once you have this object, you can create your classes and use BoundedValue instances, instead of floats or ints.

Categories