Why does my class variable _x don't increase? - python

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.

Related

assign different value to python object

I want to make a python class named "Foo" that has an attribute called "x" which is an int with a default value of 0.
If I assign a posetive value to x it would automatically change to 10 and if I assign a negative value it would change it to -10. for example:
>>p = Foo()
>>print(p.x)
0
>>p.x = -45
>>print(p.x)
-10
>>p.x = 85
>>print(p.x)
10
Utilize the property decorator:
You first define _x as a class member in the constructor:
def __init__(self):
self._x = 0
and initialize it with 0.
Then you define x as property:
#property
def x(self):
return self._x
This means that we can get the values of _x through the name x.
Then you define setter for x with #x.setter:
#x.setter
def x(self, value):
self._x = 10 if value > 0 else (-10 if value < 0 else 0)
This overrides the original logics for setting value to x, with the one that you defined.
ATTENTION: _x is still accessible, and if you change it the magic defined above won't hold (there is no private class members such as in other languages like C, C++, C#, Java, etc...). Things that start with _ conventionally means that they are of internal use.
Code:
class Foo(object):
def __init__(self):
self._x = 0
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = 10 if value > 0 else (-10 if value < 0 else 0)
p = Foo()
# 0
print(p.x)
p.x = -45
# -10
print(p.x)
p.x = 85
# 10
print(p.x)

Increment class property attribute in setter

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

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())

Composition - Reference to another class in Python

In my example below in Python, object x 'has-an' object y. I'd like to be able to invoke methods of x from y.
I'm able to achieve it using #staticmethod, however I'm discouraged to do that.
Is there any way(s) to reference the whole Object x from Object y?
class X(object):
def __init__(self):
self.count = 5
self.y = Y() #instance of Y created.
def add2(self):
self.count += 2
class Y(object):
def modify(self):
#from here, I wanna called add2 method of object(x)
x = X()
print x.count
>>> 5
x.y.modify()
print x.count
>>> # it will print 7 (x.count=7)
Thanks in advance.
You need to store a reference to the object which has the instance of a Y object:
class X(object):
def __init__(self):
self.count = 5
self.y = Y(self) #create a y passing in the current instance of x
def add2(self):
self.count += 2
class Y(object):
def __init__(self,parent):
self.parent = parent #set the parent attribute to a reference to the X which has it
def modify(self):
self.parent.add2()
Example usage:
>>> x = X()
>>> x.y.modify()
>>> x.count
7
Maybe it's possible for you to use class inheritance? For example:
class X(object):
def __init__(self):
self.count = 5
def add2(self):
self.count += 2
class Y(X):
def __init__(self):
super(Y, self).__init__()
def modify(self):
self.add2()
y = Y() # We now create an instance of Y which is a child class of 'super' class X
y.modify()
print(y.count) # 7

Categories

Resources