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.
Related
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
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())
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
Let's take a simple class as an example:
class Vector:
def __init__(self):
self.x = 1
self.y = 1
self.z = 1
What I would like is to give this class a variable called sum such that when I do
v = Vector()
v.sum
I am given the sum x+y+z (in this case 3). Of course I can easily just make a class method that does this, but then I would have to write v.sum() instead of v.sum. Is there any way to hide the fact that the class actually calls a function when asking for a variable?
Thanks in advance.
class Vector(object): # subclass object for new style class
def __init__(self):
self.x = 1
self.y = 1
self.z = 1
#property
def sum(self):
return self.x + self.y + self.z
>>> v = Vector()
>>> v.sum
3
http://docs.python.org/2/library/functions.html#property
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