I saw the following Python documentation which says that "define variables in a Class" will be class variables:
"Programmer's note: Variables defined in the class definition are
class variables; they are shared by all instances. "
but as I wrote sample code like this:
class CustomizedMethods(object):
class_var1 = 'foo'
class_var2 = 'bar'
cm1 = CustomizedMethods()
cm2 = CustomizedMethods()
print cm1.class_var1, cm1.class_var2 #'foo bar'
print cm2.class_var1, cm2.class_var2 #'foo bar'
cm2.class_var1, cm2.class_var2 = 'bar','for'
print cm1.class_var1, cm1.class_var2 #'foo bar' #here not changed as my expectation
print cm2.class_var1, cm2.class_var2 #'bar foo' #here has changed but they seemed to become instance variables.
I'm confused since what I tried is different from Python's official documentation.
When you assign an attribute on the instance, it is assigned on the instance, even if it previously existed on the class. At first, class_var1 and class_var2 are indeed class attributes. But when you do cm1.class_var1 = "bar", you are not changing this class attribute. Rather, you are creating a new attribute, also called class_var1, but this one is an instance attribute on the instance cm1.
Here is another example showing the difference, although it still may be a bit tough to grasp:
>>> class A(object):
... var = []
>>> a = A()
>>> a.var is A.var
True
>>> a.var = []
>>> a.var is A.var
False
At first, a.var is A.var is true (i.e., they are the same object): since a doesn't have it's own attribute called var, trying to access that goes through to the class. After you give a its own instance attribute, it is no longer the same as the one on the class.
You're assigning attributes on the instances, so yes, they become instance variables at that point. Python looks for attributes on whatever object you specify, then if it can't find them there, looks up the inheritance chain (to the class, the class's parents, etc.). So the attribute you assign on the instance "shadows" or "hides" the class's attribute of the same name.
Strings are immutable, so the difference between a class and instance variable isn't as noticable. For immutable variables in a class definition, the main thing to notice is less use of memory (i.e., if you have 1,000 instances of CustomizedMethods, there's still only one instance of the string "foo" stored in memory.)
However, using mutable variables in a class can introduce subtle bugs if you don't know what you're doing.
Consider:
class CustomizedMethods(object):
class_var = {}
cm1 = CustomizedMethods()
cm2 = CustomizedMethods()
cm1.class_var['test'] = 'foo'
print cm2.class_var
'foo'
cm2.class_var['test'] = 'bar'
print cm1.class_var
'bar'
When you reassigned the cm2 variables, you created new instance variables that "hid" the class variables.
>>> CustomizedMethods.class_var1 = 'one'
>>> CustomizedMethods.class_var2 = 'two'
>>> print cm1.class_var1, cm1.class_var2
one two
>>> print cm2.class_var1, cm2.class_var2
bar for
Try to
print cm1.__dict__
print cm2.__dict__
it will be enlightning...
When you ask cm2 for an attribute it first looks among the attributes of the instance (if one matches the name) and then if there is no matching attribute among the class attributes.
So class_var1 and class_var2 are the names of the class attributes.
Try also the following:
cm2.__class__.class_var1 = "bar_foo"
print cm1.class_var1
what do you expect?
Related
This question already has answers here:
How to access (get or set) object attribute given string corresponding to name of that attribute
(3 answers)
Closed 3 years ago.
I have a Python class that have attributes named: date1, date2, date3, etc.
During runtime, I have a variable i, which is an integer.
What I want to do is to access the appropriate date attribute in run time based on the value of i.
For example,
if i == 1, I want to access myobject.date1
if i == 2, I want to access myobject.date2
And I want to do something similar for class instead of attribute.
For example, I have a bunch of classes: MyClass1, MyClass2, MyClass3, etc. And I have a variable k.
if k == 1, I want to instantiate a new instance of MyClass1
if k == 2, I want to instantiate a new instance of MyClass2
How can i do that?
EDIT
I'm hoping to avoid using a giant if-then-else statement to select the appropriate attribute/class.
Is there a way in Python to compose the class name on the fly using the value of a variable?
You can use getattr() to access a property when you don't know its name until runtime:
obj = myobject()
i = 7
date7 = getattr(obj, 'date%d' % i) # same as obj.date7
If you keep your numbered classes in a module called foo, you can use getattr() again to access them by number.
foo.py:
class Class1: pass
class Class2: pass
[ etc ]
bar.py:
import foo
i = 3
someClass = getattr(foo, "Class%d" % i) # Same as someClass = foo.Class3
obj = someClass() # someClass is a pointer to foo.Class3
# short version:
obj = getattr(foo, "Class%d" % i)()
Having said all that, you really should avoid this sort of thing because you will never be able to find out where these numbered properties and classes are being used except by reading through your entire codebase. You are better off putting everything in a dictionary.
For the first case, you should be able to do:
getattr(myobject, 'date%s' % i)
For the second case, you can do:
myobject = locals()['MyClass%s' % k]()
However, the fact that you need to do this in the first place can be a sign that you're approaching the problem in a very non-Pythonic way.
OK, well... It seems like this needs a bit of work. Firstly, for your date* things, they should be perhaps stored as a dict of attributes. eg, myobj.dates[1], so on.
For the classes, it sounds like you want polymorphism. All of your MyClass* classes should have a common ancestor. The ancestor's __new__ method should figure out which of its children to instantiate.
One way for the parent to know what to make is to keep a dict of the children. There are ways that the parent class doesn't need to enumerate its children by searching for all of its subclasses but it's a bit more complex to implement. See here for more info on how you might take that approach. Read the comments especially, they expand on it.
class Parent(object):
_children = {
1: MyClass1,
2: MyClass2,
}
def __new__(k):
return object.__new__(Parent._children[k])
class MyClass1(Parent):
def __init__(self):
self.foo = 1
class MyClass2(Parent):
def __init__(self):
self.foo = 2
bar = Parent(1)
print bar.foo # 1
baz = Parent(2)
print bar.foo # 2
Thirdly, you really should rethink your variable naming. Don't use numbers to enumerate your variables, instead give them meaningful names. i and k are bad to use as they are by convention reserved for loop indexes.
A sample of your existing code would be very helpful in improving it.
to get a list of all the attributes, try:
dir(<class instance>)
I agree with Daenyth, but if you're feeling sassy you can use the dict method that comes with all classes:
>>> class nullclass(object):
def nullmethod():
pass
>>> nullclass.__dict__.keys()
['__dict__', '__module__', '__weakref__', 'nullmethod', '__doc__']
>>> nullclass.__dict__["nullmethod"]
<function nullmethod at 0x013366A8>
I think I have some misconception about class and instance variables. Here is an example code:
class Animal(object):
energy = 10
skills = []
def work(self):
print 'I do something'
self.energy -= 1
def new_skill(self, skill):
self.skills.append(skill)
if __name__ == '__main__':
a1 = Animal()
a2 = Animal()
a1.work()
print a1.energy # result:9
print a2.energy # result:10
a1.new_skill('bark')
a2.new_skill('sleep')
print a1.skills # result:['bark', 'sleep']
print a2.skills # result:['bark', 'sleep']
I thought that energy and skill were class variables, because I declared them out of any method. I modify its values inside the methods in the same way (with self in his declaration, maybe incorrect?). But the results show me that energy takes different values for each object (like a instance variable), while skills seems to be shared (like a class variable). I think I've missed something important...
The trick here is in understanding what self.energy -= 1 does. It's really two expressions; one getting the value of self.energy - 1, and one assigning that back to self.energy.
But the thing that's confusing you is that the references are not interpreted the same way on both sides of that assignment. When Python is told to get self.energy, it tries to find that attribute on the instance, fails, and falls back to the class attribute. However, when it assigns to self.energy, it will always assign to an instance attribute, even though that hadn't previously existed.
You are running into initialization issues based around mutability.
First, the fix. skills and energy are class attributes.
It is a good practice to consider them as read only, as initial values for instance attributes. The classic way to build your class is:
class Animal(object):
energy = 10
skills = []
def __init__(self,en=energy,sk=None):
self.energy = en
self.skills = [] if sk is None else sk
....
Then each instance will have its own attributes, all your problems will disappear.
Second, what's happening with this code?
Why is skills shared, when energy is per-instance?
The -= operator is subtle. it is for in-place assignation if possible. The difference here is that list types are mutable so in-place modification often occurs:
In [6]:
b=[]
print(b,id(b))
b+=['strong']
print(b,id(b))
[] 201781512
['strong'] 201781512
So a1.skills and a2.skills are the same list, which is also accessible as Animal.skills. But energy is a non-mutable int, so modification is impossible. In this case a new int object is created, so each instance manages its own copy of the energy variable:
In [7]:
a=10
print(a,id(a))
a-=1
print(a,id(a))
10 1360251232
9 1360251200
Upon initial creation both attributes are the same object:
>>> a1 = Animal()
>>> a2 = Animal()
>>> a1.energy is a2.energy
True
>>> a1.skills is a2.skills
True
>>> a1 is a2
False
When you assign to a class attribute, it is made local to the instance:
>>> id(a1.energy)
31346816
>>> id(a2.energy)
31346816
>>> a1.work()
I do something
>>> id(a1.energy)
31346840 # id changes as attribute is made local to instance
>>> id(a2.energy)
31346816
The new_skill() method does not assign a new value to the skills array, but rather it appends which modifies the list in place.
If you were to manually add a skill, then the skills list would be come local to the instance:
>>> id(a1.skills)
140668681481032
>>> a1.skills = ['sit', 'jump']
>>> id(a1.skills)
140668681617704
>>> id(a2.skills)
140668681481032
>>> a1.skills
['sit', 'jump']
>>> a2.skills
['bark', 'sleep']
Finally, if you were to delete the instance attribute a1.skills, the reference would revert back to the class attribute:
>>> a1.skills
['sit', 'jump']
>>> del a1.skills
>>> a1.skills
['bark', 'sleep']
>>> id(a1.skills)
140668681481032
Access the class variables through the class, not through self:
class Animal(object):
energy = 10
skills = []
def work(self):
print 'I do something'
self.__class__.energy -= 1
def new_skill(self, skill):
self.__class__.skills.append(skill)
Actually in you code
a1.work();
print a1.energy;
print a2.energy
when you are calling a1.work() an instance variable for a1 object is getting created with the same name that is 'energy'.
And When interpreter comes to 'print a1.energy' it execute the instance variable of object a1.
And when interpreter comes to 'print a2.energy' it execute the class variable, and since you have not changed the value of class variable it shows 10 as output.
The code below:
Since Iter Class is inheriting the Parser class, class Iter(Parser):
is it unnessary to define duplicate but Iter class specific variables with Parser class variables?
Meaning
self.totalEntriesI is just receiver of the variable value in the Parser class known as totalEntires shown in the code as Parser.totalEntires so that work may be done with the value.
however is this necessary?
could I achieve the same thing with out doing it
class Iter(Parser):
def __init__(self, Parser):
self.totalEntriesI = Parser.totalEntries
self.perPageI = Parser.perPage
self.currentPageI = Parser.currentPage
Hugs and kisses
Correct, it's unneccesary. The class attributes ("variables") of Parser are also available on its subclass Iter.
If you assign them to instance attributes as shown, then each Iter instance will get its own copy of the values -- useful if you need to modify them later on a per-instance basis, but otherwise a waste of space and attention :)
A subtlety to be aware of: if you subsequently assign a value to one of these attributes via the subclass Iter, then Iter will get its own copy of the attribute. For example:
>>> class A(): my_attr = 'foo'
>>> class B(A): pass
As you'd expect,
>>> A.my_attr == B.my_attr == 'foo'
True
However, observe:
>>> B.my_attr = 'bar'
>>> B.my_attr
'bar'
>>> A.my_attr
'foo'
What I do not understand is b = Bar(a). What does it do? How is Bar taking a as an argument?
Won't that mean Bar inherits from a? What is Bar.Foo1 = Foo? Does it mean Foo1 is an instance of class Foo()? How do we access Foo1 when it itself is an object? What is the meaning of b.arg.variable? Doesn't it mean that b has a method arg which has a variable called variable? The following code is from this answer
I just could not find parsing objects as an argument to another class.
class Foo (object):
#^class name #^ inherits from object
bar = "Bar" #Class attribute.
def __init__(self):
# #^ The first variable is the class instance in methods.
# # This is called "self" by convention, but could be any name you want.
self.variable="Foo" #instance attribute.
print self.variable, self.bar #<---self.bar references class attribute
self.bar = " Bar is now Baz" #<---self.bar is now an instance attribute
print self.variable, self.bar
def method(self,arg1,arg2):
#This method has arguments. You would call it like this : instance.method(1,2)
print "in method (args):",arg1,arg2
print "in method (attributes):", self.variable, self.bar
a=Foo() # this calls __init__ (indirectly), output:
# Foo bar
# Foo Bar is now Baz
print a.variable # Foo
a.variable="bar"
a.method(1,2) # output:
# in method (args): 1 2
# in method (attributes): bar Bar is now Baz
Foo.method(a,1,2) #<--- Same as a.method(1,2). This makes it a little more explicit what the argument "self" actually is.
class Bar(object):
def __init__(self,arg):
self.arg=arg
self.Foo1=Foo()
b=Bar(a)
b.arg.variable="something"
print a.variable # something
print b.Foo1.variable # Foo
"What I do not understand is b = Bar(a). What does it do?"
b = Bar(a) does two things. First, it creates an object of class Bar (with any class variables and methods attached). Then, it runs __init__ with the first argument (self) pointing to the object that was just created, and with a as the second argument (arg). While running __init__, as one of the commands in that method, it sets self.arg to point to the object pointed to by arg (i.e. to the object pointed to by the variable a). Finally, the variable b is set to refer to the object that was created.
It may help to think this way: a variable in Python is really just a pointer that points to an object. You can have more than one variable pointing to the same object. In this case, a and b.arg both point to the same object.
I found this sort of thing confusing too, at first. I had seen the advice to think of variables as separate concepts from the object they point to and ignored it as unnecessarily complicating things, but I had to go back to accepting that way of thinking in order to make sense of things. People do often use the variable as a name to refer to the object it points to; you just have to know when to take this literally or not.
"Wont that mean Bar inherit from a?"
No. If a is a class, then class Bar(a) would mean that Bar inherits from a. But in
b = Bar(a), a is an object being passed as an argument to __init__.
"What is Bar.Foo1 = Foo?"
Sorry -- I don't see that in the example code you gave.
"What is the meaning of b.arg.variable?"
b is an object (i mean, b refers to an object) and b.arg is one of the attributes of that object. Methods and variables are different types of attributes. In this case, b.arg is a variable pointing to an object. The object referred to by b.arg has attribute variable, which is a variable.
b.arg refers to the same object that a refers to, therefore b.arg.variable is the same variable as a.variable. It not only points to the same object, but actually is the same variable. The object it points to is the string "something".
#Brenbarn: I think that's what quirius meant by "Wont that mean Bar inherit from a?".
Here is a simpler example. Suppose you have these classes:
class Foo(object):
pass
class Bar(object):
def __init__(self, arg):
self.arg = arg
Here are two things you could do:
# Option 1: pass in an integer
>>> b = Bar(1)
>>> b.arg
1
# Option 2: pass in a Foo object
>>> a = Foo()
>>> b = Bar(a)
>>> b.arg
<__main__.Foo object at 0x0000000002A440F0>
There is no difference in how the two cases are handled. Passing in a (a Foo object) is no different from passing in an integer. All that Bar does is store the value that is passed in, and it can store it just the same whether it is a Foo or an int. When you call Bar(something), it is entirely up to the Bar class how to handle the object that is passed in. The type of the passed-in object is not involved except insofar as Bar chooses to explicitly involve it (e.g., by calling methods on the passed in object).
The way I usually declare a class variable to be used in instances in Python is the following:
class MyClass(object):
def __init__(self):
self.a_member = 0
my_object = MyClass()
my_object.a_member # evaluates to 0
But the following also works. Is it bad practice? If so, why?
class MyClass(object):
a_member = 0
my_object = MyClass()
my_object.a_member # also evaluates to 0
The second method is used all over Zope, but I haven't seen it anywhere else. Why is that?
Edit: as a response to sr2222's answer. I understand that the two are essentially different. However, if the class is only ever used to instantiate objects, the two will work he same way. So is it bad to use a class variable as an instance variable? It feels like it would be but I can't explain why.
The question is whether this is an attribute of the class itself or of a particular object. If the whole class of things has a certain attribute (possibly with minor exceptions), then by all means, assign an attribute onto the class. If some strange objects, or subclasses differ in this attribute, they can override it as necessary. Also, this is more memory-efficient than assigning an essentially constant attribute onto every object; only the class's __dict__ has a single entry for that attribute, and the __dict__ of each object may remain empty (at least for that particular attribute).
In short, both of your examples are quite idiomatic code, but they mean somewhat different things, both at the machine level, and at the human semantic level.
Let me explain this:
>>> class MyClass(object):
... a_member = 'a'
...
>>> o = MyClass()
>>> p = MyClass()
>>> o.a_member
'a'
>>> p.a_member
'a'
>>> o.a_member = 'b'
>>> p.a_member
'a'
On line two, you're setting a "class attribute". This is litterally an attribute of the object named "MyClass". It is stored as MyClass.__dict__['a_member'] = 'a'. On later lines, you're setting the object attribute o.a_member to be. This is completely equivalent to o.__dict__['a_member'] = 'b'. You can see that this has nothing to do with the separate dictionary of p.__dict__. When accessing a_member of p, it is not found in the object dictionary, and deferred up to its class dictionary: MyClass.a_member. This is why modifying the attributes of o do not affect the attributes of p, because it doesn't affect the attributes of MyClass.
The first is an instance attribute, the second a class attribute. They are not the same at all. An instance attribute is attached to an actual created object of the type whereas the class variable is attached to the class (the type) itself.
>>> class A(object):
... cls_attr = 'a'
... def __init__(self, x):
... self.ins_attr = x
...
>>> a1 = A(1)
>>> a2 = A(2)
>>> a1.cls_attr
'a'
>>> a2.cls_attr
'a'
>>> a1.ins_attr
1
>>> a2.ins_attr
2
>>> a1.__class__.cls_attr = 'b'
>>> a2.cls_attr
'b'
>>> a1.ins_attr = 3
>>> a2.ins_attr
2
Even if you are never modifying the objects' contents, the two are not interchangeable. The way I understand it, accessing class attributes is slightly slower than accessing instance attributes, because the interpreter essentially has to take an extra step to look up the class attribute.
Instance attribute
"What's a.thing?"
Class attribute
"What's a.thing? Oh, a has no instance attribute thing, I'll check its class..."
I have my answer! I owe to #mjgpy3's reference in the comment to the original post. The difference comes if the value assigned to the class variable is MUTABLE! THEN, the two will be changed together. The members split when a new value replaces the old one
>>> class MyClass(object):
... my_str = 'a'
... my_list = []
...
>>> a1, a2 = MyClass(), MyClass()
>>> a1.my_str # This is the CLASS variable.
'a'
>>> a2.my_str # This is the exact same class variable.
'a'
>>> a1.my_str = 'b' # This is a completely new instance variable. Strings are not mutable.
>>> a2.my_str # This is still the old, unchanged class variable.
'a'
>>> a1.my_list.append('w') # We're changing the mutable class variable, but not reassigning it.
>>> a2.my_list # This is the same old class variable, but with a new value.
['w']
Edit: this is pretty much what bukzor wrote. They get the best answer mark.