Class retains previous content where new instance is expected - python

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

Related

How to access a variable from constructor outside of method in python

class A():
B: str = "no"
class test(A):
a = None
  def __init__(self, val):
      self.a = val
  if self.a == "test":
B = "yes"
t = test("test")
print(t.B)
NameError: name 'self' is not defined
self.a shows an error so how can I access a which was assigned a value in the constractor out side of a method inside the class?
Because you are making class object u need to define the object name used
class test():
def __init__(self):
You want to access your attribute, you cant access outside of method so
class test():
def __init__(self):
self.a = "test"
if self.a == "test":
pass
or you can create another method that process that
class test():
def __init__(self):
self.a = "test"
self.access_a()
def access_a(self):
if self.a == "test":
print("do something")
pass
What you are asking for (given that your example defines an instance attribute) is quite frankly not possible, you can't access an instance attribute without referencing that instance and you can't reference an instance of a class in its body.
What could be done is changing the class attribute from the constructor but that would be pointless because all code in the body of the class gets executed first so such a check (as in your provided sample) would be pointless anyways.

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.

how to know from which class instance a function is called to access the instance attributes

I want to access an attribute of the class instance that called a function :
for example:
class A:
def a(self):
return B.q
class B:
q=0
def b(self):
M=A()
return M.a()
c=B()
c.q = 6
print(c.b())
the output will be 0 but I want it to print the q attribute of the instance c of the class B which has the value 6
Pass the instance as a parameter.
class A:
def a(self, b):
return b.q
class B:
q=0
def b(self):
M=A()
return M.a(self)
c=B()
c.q = 6
print(c.b())
This appears to be very bad program design. What are you trying to accomplish with this?
You have a class attribute and an instance attribute -- in that class -- of the same name, q. This makes your code difficult to follow and to maintain.
You have method B.b instantiate an instance of class A. You immediately call A.a, which has been assigned the questionable task of returning an instance attribute from and object of class B.
Clean up your design.
Use init appropriately for each class.
Design your class methods to work appropriately with the characteristics of instances of that class. Your question strongly suggests that your design is not yet clean in your mind, nor in code.
define an init method so that you can work with the instance attributes instead of the class variable
class A:
def a(self):
return B.q
class B:
def __init__(self):
self.q = 0
def b(self):
M=A()
return M.a()
c=B()
c.q = 6
print(c.b())

Store instance of class A in instance of class B

I have a question which is more regarding OOP in general rather than python specific.
Is ist possible to store instances of ClassA in instance of ClassB without a specific method, i.e. by some kind of inheritance.
Example: let's say I have one Model class and one Variable class
class Model():
def __init__(self):
self.vars = []
def _update_vars(self,Variable):
self.vars.append(Variable)
class Variable(Model):
def __init__(self,**kwargs):
self.__dict__.update(kwargs)
Is it now possible to call _update_vars whenever an instance of variable is being created.
So if I do something like this:
mdl = Model()
varA = Variable(...)
varB = Variable(...)
that mdl.vars would now include varA and varB.
I know that I could easily do this by passing the variables as an argument to a "public" method of Model. So I am not looking for
mdl.update_vars(varA)
So my two questions are:
is this possible?
if yes: would this very non-standard OOP programming?
Thanks for your help!
That's not how class inheritance is supposed to work. You only want to inherit something if the child class is going to make use of a good amount of the attributes/methods within the parent class. If the child class has a markedly different structure it should be a class of its own.
In either case, as mentioned by #jasonharper, at some point you would need to give direction as to which Variable instance belongs in which Model instance, so you're likely to end up with something like these:
varA = Variable(mdl, ...)
# or this
mdl.varA = Variable(...)
With the first way, you would maintain the method on your Variable class:
class Foo:
def __init__(self):
self.vars = []
class Bar:
def __init__(self, foo_instance, **kwargs):
foo_instance.vars.append(self)
f = Foo()
b = Bar(f, hello='hey')
f.vars
# [<__main__.Bar object at 0x03F6B4B0>]
With the second way, you can append the Variable instances into a list each time it's added:
class Foo:
def __init__(self):
self.vars = []
def __setattr__(self, name, val):
self.__dict__.update({name: val})
if not name == 'vars': # to prevent a recursive loop
self.vars.append(val)
f = Foo()
f.vars
# []
f.a = 'bar'
f.vars
# ['bar']
Of course, an easier way would be to just look directly into the __dict__ each time you want vars:
class Bar:
#property
def vars(self):
# Or you can return .items() if you want both the name and the value
return list(self.__dict__.values())
b = Bar()
b.a = 'hello'
b.vars
# ['hello']
Both of these will work the same even if you assigned the attributes with your own class instances.
You can use super() for this and pass the instance to the parent
class Model():
vars = []
def __init__(self, other=None):
if other:
self.vars.append(other)
class Variable(Model):
def __init__(self, a):
self.a = a
super().__init__(self)
mdl = Model()
varA = Variable(3)
varB = Variable(4)
print(mdl.vars)

Python object instance inheriting changes to parent class by another instance

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

Categories