This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 9 years ago.
i just have a puzzling question abou class attributes in python.
consider the following class below:
class A:
__lst = []
def add(self, str):
self.__lst.append(str)
print len(self.__lst)
i tried to make two instances x and y and i got this:
>>> x = A()
>>> x.add('aaa')
1
>>> x.add('bbb')
2
>>> y = A()
>>> y.add('aaa')
3
>>> y.add('bbb')
4
i was expecting that the instance of y will have a separate copy of the list attribute but it seems that the list just gets bigger even if you use another object to add elements to the list. it's simply weird.
can anybody please enlighten me on this matter?
thanks a lot in advance for your help. :-)
If you define an attribute inside of the class body then it will be a class attribute, and it will be shared by all instances. In your code self.__lst is going to be a reference to A.__lst.
To have a separate list for each attribute, define it as self.__lst inside of the __init__() function:
class A(object):
def __init__(self):
self.__lst = []
def add(self, s):
self.__lst.append(s)
print len(self.__lst)
In addition to the change referenced above, I also made some minor modifications so that your code follows some Python best practices: inheriting from object (new-style class) and not using str (or any other built-in name) as a variable name.
Variables declared inside a class but not by means of self are class-level properties (like your __lst). They are equivalent to Java's static. If you want your property to be unique for all instances, you need to declare them via self (i.e., self.__lst).
Related
This question already has answers here:
Define a method outside of class definition?
(5 answers)
Closed 4 years ago.
Is it possible (preserving all the class functionality) to write the class functions in separate files?
Below is an example:
TestClass.py:
class MyClass():
def __init__(self, param1=1, param2=2, param3=3):
self.param1, self.param2, self.param3 =param1, param2, param3,
def ClassFun1(self, param1=2):
return param1**2/self.param2
TestClass2.py:
def ClassFun2(self, param1=3):
return param1*3/self.param2
Next, following this answer, I compile both files (I am too lazy to use import), create a class variable and try to use ClassFun2:
x=MyClass()
x.myMethod=ClassFun2
x.myMethod(2)
As a result, I get an error, since self in ClassFun2 is treated as a parameter, rather than class itself:
AttributeError: 'int' object has no attribute 'param2'
Is it possible to split class definition into several source files? It is possible in C++ and this is actually very convenient when working as a team.
The variable x is an object of the class, not the class itself. You need to do:
x = MyClass
x.myMethod = ClassFun2
Notice that I didn't put () after MyClass. That returns the class itself, it doesn't return an instance of the class.
Then you need to create an instance to execute the method:
y = MyClass()
y.myMethod(2)
This question already has answers here:
What is the difference between class and instance attributes?
(5 answers)
Closed 5 years ago.
Came across one Python Class and I am finding it hard to understand how and why its working . A simplified example of the class is :
class Test:
def __init__(self):
self.var = 1
otherVar = 2
def myPrinter(self):
print self.__dict__ # Prints {'var': 1}
print self.var
print self.otherVar # Doubt !!
print self.__dict__ # Prints {'var': 1}
ob = Test()
ob.myPrinter()
My doubt is with the self.otherVar call not throwing an error while self.__dict__ does not show reference to otherVar
It's because otherVar is an attribute of the class, while the var you setup in the __init__ is an attribute of the instance.
The otherVar is visible to the instance, because python first tries to get the instance attribute values, if the instance doesn't have it, then it checks its class attributes. If you define a var in both with different values, things may get confusing at first.
Well, do you know that comparison that a class is like a blueprint and the instance is the object built following it, right? So, var is an extra you added while creating the instance.
If you want to see otherVar, do Test.__dict__. It won't show you var, but all the class attributes.
Play a little with it and with time you are going to get used to it. Class attributes may be tricky, but extremely useful.
otherVar is a class member, not instance member, that's why it doesn't show in __dict__.
It appears in self.__class__.__dict__. (this way doesn't work in Python 2.x)
By the way, otherVar member value is shared across all instances and also accessible from type object: Test.otherVar
Example here: https://trinket.io/python3/d245351e58
For a more in depth explanation check here
This question already has answers here:
How to copy a class?
(9 answers)
Closed 8 years ago.
In the example below, I am deepcopying a base class and messing with the attributes of the copy. Why is this messing with the attributes of the original class? Is there any way to avoid this? The current code structure I am working with can't support multiple inheritance, so I really want to be able to somehow copy the class.
>>> class Base(object):
... foo = "bar"
...
>>> base_copy = copy.deepcopy(Base)
>>> del base_copy.foo
>>>
>>> base_again = copy.deepcopy(Base)
>>> hasattr(base_again, 'foo')
False
>>>
copy() and deepcopy() are designed to copy objects not classes. When you pass a class the original class is returned.
Python documentation says :
This module does not copy types like module, method, stack trace, stack frame, file, socket, window, array, or any similar types. It does “copy” functions and classes (shallow and deeply), by returning the original object unchanged; this is compatible with the way these are treated by the pickle module.
Indeed when testing with your code we have:
In [8]: base_copy is Base
Out[8]: True
You could try messing with type() as suggested in the other answer but it's pretty hackish.
You could do
class B(A):
pass
It's the closest I can think of that would make a copy.
As stated in copy documentation:
This module does not copy types like module, method, stack trace,
stack frame, file, socket, window, array, or any similar types. It
does “copy” functions and classes (shallow and deeply), by returning
the original object unchanged
You can try to do it using metaclasses:
class Base(object):
foo = "bar"
# Create a new class called `base_copy` with attributes and base classes
# from Base without inheriting from Base
base_copy = type('base_copy', Base.__bases__, dict(Base.__dict__))
# Will delete attribute on `base_copy` class
del base_copy.foo
base_again = type('base_again', Base.__bases__, dict(Base.__dict__))
print(hasattr(base_again, 'foo')) # True
You can try using deepcopy on dict(Base.__dict__) object to copy objects like list, dict and others.
Define all variables inside the constructor.
You can create a new constructor which, on the basis of the argument provided, decides which all fields should exist in the object of the class.
Class Foo:
def __init__(self):
self.param0 = 0
self.param1 = 0
def __init__(self,i):
if i == 0:
self.param0 = 0
if i == 1:
self.param1 = 1
This question already has answers here:
Why can't you add attributes to object in python? [duplicate]
(2 answers)
Can't set attributes on instance of "object" class
(7 answers)
Closed 9 years ago.
I just realized that:
class A(object): pass
a = A()
a.x = 'whatever'
Works (does not raise an error and creates a new x member).
But this:
a = object()
a.x = 'whatever'
Raises:
AttributeError: 'object' object has no attribute 'x'
While I probably would never use this in real production code, I'm a bit curious about what the reason is for the different behaviors.
Any hints ?
Probably because of __slots__. By default your class have dict of all atributes which can be added to like in your first example. But that behaviour can bi overriden by using slots.
Also, some classes like datetime which are implemented in C also can not be extended with new attributes at runtime.
Workaround for such classes is to do something like :
class MyObject(): # extend that class, here we extend object
pass # add nothing to the class
o = MyObject()
o.x = 'whatever' # works
This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 9 years ago.
I just got owned. I couldn't believe that this was true, but upon testing it, I found it to be:
class A(object):
v = []
a = A()
b = A()
What do you think that the following code will return?
a.v is b.v
What about this code?
a.v.append(1)
a.v[0] == b.v[0]
Sure enough, a.v is b.v, they both share the same reference to the same list. Coming from a, well, every other programming language background, how does this make sense?
In Java, if I were to write a class like this:
class A {
public Object[] v = new Object[]{};
}
...I would never, in my wildest dreams, think that two instances of the class would share the same reference to the array.
My main question is this, is there something equivalent for initial values in Python classes as in Java, C#, etc.? Why do all instances of the class share the same reference to the same list?
You have defined a class attribute instead of an instance attribute. Python is doing the right thing.
Instead of
class A(object):
v = [] # Class attribute, shared across all instances!
you need
class A(object):
def __init__(self): # Instance attribute, created anew for each new object
self.v = []
Java syntax is different to Python's. It's not a good idea to just try to guess the right thing to use based on your Java knowledge
class A(object):
v = [] # class attribute
class A(object):
def __init__(self):
self.v = [] # instance attribute
Ok, the rules are kinda funny.
If you try to access self.v, first Python looks for an instance attribute, if there isn't one it looks at the class, and then the parent classes until it finds one or raises an attribute error.
When you assign to self.v it always binds it to an instance attribute even if it wasn't before.
Then there are descriptors...
That's because v is a class attribute (think static member variable in C++).
If you want a non-shared member attribute, you have to declare it in the constructor:
class A(object):
def __init__(self):
selv.v = []
class A(object):
v = []
here v is a class attribute not instance attribute, They are only defined once, during the class definition. So, that's why the're are pointing to the same object.
Use instance attribute instead:
class A(object):
def __init__(self):
self.v = [] #different for each instance
a= A()
b = A()
print a is b #prints False