Python object instance inheriting changes to parent class by another instance - python

I am confused by this behaviour of Python(2.6.5), can someone shed light on why this happens?
class A():
mylist=[]
class B(A):
j=0
def addToList(self):
self.mylist.append(1)
b1 = B()
print len(b1.mylist) # prints 0 , as A.mylist is empty
b1.addToList()
print len(b1.mylist) # prints 1 , as we have added to A.mylist via addToList()
b2 = B()
print len(b2.mylist) # prints 1 !!! Why ?????

You need to do:
class A:
def __init__(self):
self.mylist=[]
That way self.mylist is an instance variable. If you define it outside of a method it is a class variable and so shared between all instances.
In B if you define a constructor you'll have to explicitly call A's constructor:
class B(A):
def __init__(self):
A.__init__(self)
This is explained (not very clearly) in the Python tutorial.

This code creates a shared mylist among all instances of A (or subclasses)
class A():
mylist=[]
What you want to do is:
class A():
def __init__(self):
self.mylist=[]
What you've probably seen is people who do:
class A():
somevariable = a
def doit(self):
self.somevariable = 5
This works because it creates a new "somevariable" attribute because you are doing an assignment. Before that all A instances share the same copy of somevariable. As long as you don't change the copy that is fine. When the variable is assigned to, then it gets replaced rather then modified. So that technique is only really safe when the values in question are immutable (i.e. you can't change them, you can only replace them) However, I think that's a really bad idea and you should always assign all variables in init

Related

OOP: Init method questions

I have two questions regarding the code below.
What is the difference between self.a=self.test1() and a=self.test1()? One is class field and other one is object field?
Why cannot I define result = self.a+self.b? How to correct it?
class Test():
def __init__(self):
self.a=self.test1()
a=self.test1()
self.b=Test.test2()
result = self.a+self.b
def test1(self):
a=100
return a
#classmethod
def test2(cls):
b=200
return b
#staticmethod
def test3():
print("Testing3 is calling ")
c=500
return c
self.a = self.test1() creates an instance attribute named a. The attribute will be accessible from the object anywhere you have a reference to the object.
a = self.test1() defines a local variable named a. It will go out of scope once __init__ returns.
result = self.a + self.b doesn't work because it is in a context where self is not defined. self is just the (conventional) name of the first parameter of an instance method. It's not defined in the namespace of the class statement itself.
self.a is a property in this class. It will remain accessible throughout functions in the Test() class. a = self.test1(), however, goes away once __init__(self) finishes, because a is local to __init__(self).
For result = self.a + self.b, I assume you want a variable called result calculated after self.a and self.b is defined? At that indentation level a statement like this is usually not allowed (I could be wrong), usually a declaration of a property of a class happens here.

Is it possible to refer to the owner class that an object belongs to as an attribute?

I am not quite sure this is possible (or something similar) in python. I want to access a method (or another object) of a class from an object that is an attribute of such class.
Consider the following code:
class A():
def __init__(self):
self.b = B()
self.c = C()
def print_owner(self):
print('owner')
class B():
def __init__(self):
pass
def call_owner(self):
self.owner().print_owner()
so that b as an object attribute of class A, can refer to a method or attribute of A?
Or similarly, is it possible that b can access c?
It's possible. You can pass a reference to A to B constructor:
...
self.b = B(self)
...
class B:
def __init__(self, a):
self.a = a
So, B.a stores the reference to its owner A.
There can be many references to object B(), not only the one in instance of class A. So it's not possible as it is in your code. (Well you could try a hack, like finding all instances of class A in memory and find the one whose attribute b points to your B instance, but that's a really bad idea).
You should explicitly store in instance of B a reference to the owner.
You have a couple of options here. The better one is probably #Sianur suggests. It's simple, effective, and explicit. Give that answer an upvote.
Another option is to have the owner force itself on its minions. B can do something like
def call_owner(self):
if hasattr(self, 'owner'):
self.owner().print_owner()
else:
print('I am free!')
Meanwhile, A would set the owner attribute to itself:
def __init__(self):
self.b = B()
self.c = C()
self.b.owner = self.c.owner = self
In any case, if you want an object to have access to another object, store the reference into an accessible place. There's no magic here.

Class retains previous content where new instance is expected

I define a class, and a function which creates an instance of that class. I thought this function should create a new instance every time. However, it looks like it "inherits" its content from last call. Anyone can explain this? Thanks!
class test:
a = []
def b(self,x):
self.a.append(x)
def add():
t = test()
t.b(2)
return t
if __name__ == '__main__':
print add().a
print add().a
print add().a
Output:
[2]
[2, 2]
[2, 2, 2]
Here's how the definition of the a instance variable should look:
class test(object):
def __init__(self):
self.a = []
The way it was before a was not declared as an instance variable, but a class variable that was being shared across all instances of the class.
You defined a as a class variable. It's not bound to an instance of your class, but to the class itself, so there's only one list that's "shared" across the instances of the class.
You need to make it an instance variable:
class test:
def b(self, x):
self.a = []
self.a.append(x)
Also, you should inherit from object in order to utilize new-style classes:
class test(object):

In a Python class, what is the difference between creating a variable with the self syntax, and creating one without ?

What is the difference between creating a variable using the self.variable syntax and creating one without?
I was testing it out and I can still access both from an instance:
class TestClass(object):
j = 10
def __init__(self):
self.i = 20
if __name__ == '__main__':
testInstance = TestClass()
print testInstance.i
print testInstance.j
However, if I swap the location of the self, it results in an error.
class TestClass(object):
self.j = 10
def __init__(self):
i = 20
if __name__ == '__main__':
testInstance = TestClass()
print testInstance.i
print testInstance.j
>>NameError: name 'self' is not defined
So I gather that self has a special role in initialization.. but, I just don't quite get what it is.
self refers to the current instance of the class. If you declare a variable outside of a function body, you're referring to the class itself, not an instance, and thus all instances of the class will share the same value for that attribute.
In addition, variables declared as part of the class (rather than part of an instance) can be accessed as part of the class itself:
class Foo(object):
a = 1
one = Foo()
two = Foo()
Foo.a = 3
Since this value is class-wide, not only can you read it directly from the class:
print Foo.a # prints 3
But it will also change the value for every instance of the class:
print one.a # prints 3
print two.a # prints 3
Note, however, that this is only the case if you don't override a class variable with an instance variable. For instance, if you created the following:
class Bar(object)
a = 1
def __init__(self):
self.a = 2
and then did the following:
one = Bar()
two = Bar()
two.a = 3
Then you'd get the following results:
print Bar.a # prints "1"
print one.a # prints "2"
print two.a # prints "3"
As noted in the comments, assigning to two.a creates an instance-local entry on that instance, which overrides the a from Bar, hence why Bar.a is still 1 but two.a is 3.
j is a class variable as pointed by Amber. Now, if you come from C++ background, self is akin to the this pointer. While python doesn't deal with pointers, self plays the similar role of referring to current instance of the class.
In the python way, explicit is better than implicit. In C++, the availability of this is conventionally assumed for each class. Python, on the other hand, explicitly passes self as first argument to each of your instance methods.
Hence self is available only inside the scope of your instance methods, making it undefined for the place from which you tried using it.
Since you're made to explicitly pass self to instance methods, you could also call it something else if you want to -
>>> class Foo:
... b = 20
... def __init__(them):
... them.beep = "weee"
...
>>> f = Foo()
>>> f.beep
'weee'

using variables in class functions in another class (python)

I want to use the variables i have declared inside a function in one class, in another class.
For example i want to use the variable "j" in another class. Is it possible? (I read somewhere that it might have something to do with instance variables but fully couldn't understand the concept).
class check1:
def helloworld(self):
j = 5
class check1:
def helloworld(self):
self.j = 5
check_instance=check1()
print (hasattr(check_instance,'j')) #False -- j hasn't been set on check_instance yet
check_instance.helloworld() #add j attribute to check_instance
print(check_instance.j) #prints 5
but you don't need a method to assign a new attribute to a class instance...
check_instance.k=6 #this works just fine.
Now you can use check_instance.j (or check_instance.k) just like you would use any other variable.
This may seems a little bit like magic until you learn that:
check_instance.helloworld()
is completely equivalent to:
check1.helloworld(check_instance)
(If you think about it a little bit, that explains what the self parameter is).
I'm not completely sure what you're trying to achieve here -- There are also class variables which are shared by all instances of the class...
class Foo(object):
#define foolist at the class level
#(not at the instance level as self.foolist would be defined in a method)
foolist=[]
A=Foo()
B=Foo()
A.foolist.append("bar")
print (B.foolist) # ["bar"]
print (A.foolist is B.foolist) #True -- A and B are sharing the same foolist variable.
j cannot be seen by another class; however, I think you meant self.j, which can.
class A(object):
def __init__(self, x):
self.x = x
class B(object):
def __init__(self):
self.sum = 0
def addA(self, a):
self.sum += a.x
a = A(4)
b = B()
b.addA(a) # b.sum = 4
Using class inheritane it is very easy to "share" instance variables
example:
class A:
def __init__(self):
self.a = 10
def retb(self):
return self.b
class B(A):
def __init__(self):
A.__init__(self)
self.b = self.a
o = B()
print o.a
print o.b
print o.retb()

Categories