Increment class property attribute in setter - python

I understand the concept of getter/setter in python. The thing I am not able to understand is, I need to add new value to the variable itself and I am not sure how I can achieve this with #property decorator.
The old code instantiates some variables and self increment them. I am trying to refactor the code and move those variables to a class and add #property/setter so that I can access them as attributes.
Old Code:
class ExistingCode(object):
a = 0
b = 0
c = 0
d = 0
bunch of other code..
a += 12
b += 12
c += 12
d += 12
What I am trying to do is:
class Variables(object):
def __init__(self):
a = 0
b = 0
c = 0
d = 0
#property
def a(self):
return self.a
#a.setter
def a(self, x)
a = x
......
I am getting "RuntimeError: maximum recursion depth exceeded". Please help.

I found the issue. The main problem was that I was using the same name for the attribute and the property as mentioned by #martineau. Also, I missed self in many places. Below is the working example.
class Variables(object):
def __init__(self):
self.a = 0
#property
def a(self):
return self.__a
#a.setter
def a(self, x):
self.__a = x

Related

Why does my class variable _x don't increase?

I want to describe the class instances of which store quantity of instances of that class. Here is the code:
class WeAre:
_x = 0
def __init__(self):
self._x += 1
#property
def count(self):
return self._x
#count.setter
def count(self, val):
return None
#count.deleter
def count(self):
return None
def __del__(self):
self._x -= 1
a = WeAre()
print(a.count)
b, c = WeAre(), WeAre(),
a.count = 100500
print(a.count, b.count, c.count)
del b.count
del b
print(a.count)
Here is my output:
1
1 1 1
1
And I can't understand why class variable _x doesn't increase/decrease
In constructor you are creating instance's variable which overshadows class variable. Therefor you are always working with object instance's variable.
class WeAre:
_x = 0 # <-- class variable
# creates uses
# object var class var
#
# | |
def __init__(self): # V V
self._x += 1 # same as self._x = self._x + 1
That would work:
class WeAre:
_x = 0
def __init__(self):
WeAre._x += 1
But you may need to re-think it if you would need to override WeAre class.

Make variable common to all subclasses

I want a class temp with a variable a, and its two subclasses c1 and c2. If a is changed in c1, it should also be reflected in c2 and vice-versa. For this, I tried:
class temp(ABC):
a=1
def f(self):
pass
class c1(temp):
def f(self):
print(self.a)
class c2(temp):
def f(self):
print(self.a)
o1=c1()
o2=c2()
o1.f()
o2.f()
o1.a+=1
o1.f()
o2.f()
It gives me output:
1
1
2
1
whereas I want it to be
1
1
2
2
I also tried super.a instead of self.a, but it gives me an error. How can I achieve the desired target? Thanks...
Rather than incrementing o1.a, you need to increment the static variable itself.
Ie temp.a += 1
class temp():
a=1
def f(self):
pass
class c1(temp):
def f(self):
print(self.a)
class c2(temp):
def f(self):
print(self.a)
o1=c1()
o2=c2()
o1.f()
o2.f()
temp.a+=1
o1.f()
o2.f()
>>> 1
1
2
2

Pass a class "self" for other classes' instances?

From an existing code, I need to create instance from a class within another class while lots of information that are needed for initializing the called class, are contained in the caller one.
A way to pass some attributes of a caller class to the called class can be like in the following example passing self as argument and it does what exactly is expected, bu I wondered if it is the correct or whether is there a better way to do so?
class A:
def __init__(self):
self.x = 1
self.y = 10
self.myObj = B(self)
class B:
def __init__(self, Obj_from_A):
self.i = None
self.j = None
self.v= Obj_from_A.x
self.w = Obj_from_A.y
A_obj = A()
print(A_obj.myObj.v, A_obj.myObj.w)
Output:
1 10
Your class does what you think it is doing, except when it might not.
(btw your code does not run: you don't define B_Obj)
See the extra code I've added at the end:
class A:
def __init__(self):
self.x = 1
self.y = 10
self.myObj = B(self)
class B:
def __init__(self, Obj_from_A):
self.i = 0
self.j = 0
self.v= Obj_from_A.x
self.w = Obj_from_A.y
A_obj = A()
print(A_obj.myObj.v, A_obj.myObj.w)
A_obj.x = 2 # Now update the x member
print(A_obj.x, A_obj.myObj.v, A_obj.myObj.w)
Output:
1 10
2 1 10
Here A_obj.x has changed, but the instance of B has held onto the previous values.

Count of full objects and subobjects in Python

I would like to maintain count of A and B objects, B is subclassed from A. So the counts should be specific to A and B. For example, if I create 3 A objects and 2 B objects, by virtue of constructor call, count for A becomes 3+2=5, but I would like to keep as 3 (not when used as a subobject as part of B). Please comment on the following code snippet:
class A:
acount = 0 # class variable
def __init__(self, isFullA = True):
if (isFullA):
self.iamFullA = True
A.acount += 1
else:
self.iamFullA = False
def __del__(self):
if (self.iamFullA):
A.acount -= 1
class B(A):
bcount = 0 # class variable
def __init__(self, isFullB = True):
A.__init__(self,False)
if (isFullB):
self.iamFullB = True
B.bcount += 1
else:
self.iamFullB = False
def __del__(self):
if (self.iamFullB):
B.bcount -= 1
#MAIN
L=[]
for i in range(3):
L.append(A())
for i in range(2):
L.append(B())
print "A.acount = " + str(A.acount)
print "B.bcount = " + str(B.bcount)
The output is:
A.acount = 3
B.bcount = 2
You're making it way to complicated - all you need is to have a distinct count class attribute for each class:
class A(object):
_counter = 0
#classmethod
def _inc(cls):
cls._counter += 1
#classmethod
def _dec(cls):
cls._counter -= 1
#classmethod
def get_count(cls):
return cls._counter
def __init__(self):
self._inc()
def __del__(self):
self._dec()
class B(A):
_counter = 0
def __init__(self, wot):
super(B, self).__init__()
self.wot = wot
L=[]
for i in range(3):
L.append(A())
for i in range(2):
L.append(B(i))
print "A.count = {}".format(A.get_count())
print "B.count = {}".format(B.get_count())
Note that I used classmethods to ensure we're accessing the class attribute, as self._counter += 1 in the __init__ would create an instance attribute. You could also get the right behaviour using type(self)._counter += 1 (or self.__class__._counter += 1) but that's a bit ugly imho.
If this is for an API other devs will build upon, you may want to use a custom metaclass to ensure each subclass has it's own _counter, ie:
class CounterType(type):
def __new__(meta, name, bases, attribs):
if "_counter" not in attribs:
attribs["_counter"] = 0
return type.__new__(meta, name, bases, attribs)
class CounterBase(object):
__metaclass__ = CounterType
#classmethod
def _inc(cls):
cls._counter += 1
#classmethod
def _dec(cls):
cls._counter -= 1
#classmethod
def get_count(cls):
return cls._counter
def __init__(self):
self._inc()
def __del__(self):
self._dec()
class A(CounterBase):
pass
class B(A):
def __init__(self, wot):
super(B, self).__init__()
self.wot = wot
L=[]
for i in range(3):
L.append(A())
for i in range(2):
L.append(B(i))
print "A.count = {}".format(A.get_count())
print "B.count = {}".format(B.get_count())

Is it Possible to rewrite the getter of a property in a subclass?

For example:
class Example:
def __init__(self):
self.v = 0
#property
def value(self):
return self.v
#value.setter
def value(self, v):
self.v = v
class SubExample(Example):
pass
Would it be possible to rewrite just the getter to value in SubExample?
You can do so like this
class DoubleExample(Example):
#Example.value.getter
def value(self):
return self.v * 2
o = Example()
o.value = 1
print o.value # prints "1"
p = DoubleExample()
p.value = 1
print p.value # prints "2"
However, this only works if Example is a new-style class (class Example(object):) rather than an old style class (class Example:), as it is in your example code.
Warning: Thomas pointed out in the comments that this method may not behave as expected if you're using multiple inheritance (class Foo(Bar, Baz)).
It isn't possible to override a property's getter in a subclass, no. The property is an object that lives in the class and that holds references to the functions you give it -- if you later redefine the names of those functions, it won't affect the property at all.
What you can do is have the functions your property calls perform indirect calls, like so:
class Example(object):
def __init__(self):
self.v = 0
#property
def v(self):
return self._v_getter()
#v.setter
def v(self, value):
return self._v_setter(value)
def _v_setter(self, value):
self._v = value
class SubExample(Example):
def _v_getter(self):
return 5
>>> se = SubExample()
>>> se.v
5
>>> se._v
0
>>> se.v = 10
>>> se.v
5
>>> se._v
10
Alternatively, you can redefine the entire property in the subclass, by simply defining a new property. You won't have convenient access to the functions or property defined in the parentclass, however, and doing the right thing in the face of multiple inheritance is difficult.
Your question has been answered before:
http://code.activestate.com/recipes/408713-late-binding-properties-allowing-subclasses-to-ove/
http://stackoverflow.com/questions/3393534/python-property-and-method-override-issue-why-subclass-property-still-calls-the
Essentially, instead of using property directly, you have to defer calling the getter so that it will access the one defined in the subclass rather than the one defined in the superclass when you first defined the property. This can be achieved via a lambda:
class Test(object):
def __init__(self):
self.v = 0
def _value(self):
return self.v
def _value_setter(self, v):
self.v = v
value = property(lambda self: self._value(), lambda self, v: self._value_setter(v))
class Test2(Test):
def _value(self):
return self.v + 1
a = Test()
a.value = 2
print a.value # 2
b = Test2()
b.value = 2
print b.value # 4

Categories

Resources