Could you clarify some ideas behind Python classes and class instances?
Consider this:
class A():
name = 'A'
a = A()
a.name = 'B' # point 1 (instance of class A is used here)
print a.name
print A.name
prints:
B
A
if instead in point 1 I use class name, output is different:
A.name = 'B' # point 1 (updated, class A itself is used here)
prints:
B
B
Even if classes in Python were some kind of prototype for class instances, I'd expect already created instances to remain intact, i.e. output like this:
A
B
Can you explain what is actually going on?
First of all, the right way in Python to create fields of an instance (rather than class fields) is using the __init__ method. I trust that you know that already.
Python does not limit you in assigning values to non-declared fields of an object. For example, consider the following code:
class Empty: pass
e = Empty()
e.f = 5
print e.f # shows 5
So what's going in your code is:
You create the class A with a static field name assigned with A.
You create an instance of A, a.
You create a new field for the object a (but not for other instances of A) and assign B to it
You print the value of a.name, which is unique to the object a.
You print the value of the static field A.name, which belongs to the class
Perhaps this example may make things more help clarify. Recall that Python names are not storage (as variables are in other languages) but references to storage. You can find what a name refers to with id(name). The identity operator x is y tells whether two names point at the same object.
>>> class A(object):
... name = 'A'
...
>>> x = A()
>>> A.name is x.name
True
>>> x.name = 'fred' # x.name was bound to a new object (A.name wasn't)
>>> A.name is x.name
False
>>> x = A() # start over
>>> A.name is x.name
True # so far so good
>>> A.name = 'fred'
>>> A.name is x.name
True # this is somewhat counter-intuitive
You also should look at these SO threads for further explanations:
Static class variables in Python
In Python how can I access "static" class variables within class methods
And an official tutorial:
http://docs.python.org/tutorial/classes.html#SECTION0011320000000000000000
Keep in mind that the assignment "=" operator in python behaves differently than C++ or Java:
http://docs.python.org/reference/simple_stmts.html#assignment-statements
Related
I have this code:
class Singleton(type):
def __call__(cls,*args,**kwargs):
if cls.created is None :
print('called')
cls.created = super().__call__(*args,**kwargs)
return cls.created
else:
return cls.created
def __new__(cls,name,base,attr,**kwargs):
return super().__new__(cls,name,base,attr,**kwargs)
class OnlyOne(metaclass=Singleton):
created = None
def __init__(self,val):
self.val = val
class OnlyOneTwo(OnlyOne):
pass
k = OnlyOne(1)
a = OnlyOneTwo(2)
print(a.val)
print(k.val)
print('a.created: {0} - b.created: {1}'.format(id(a.created),id(k.created)))
I'm new to Python 3 so I decided to do some little experiment and playing around Python's metaclasses.
Here, I attempted to make a metaclass that will strict a class to a single instance when set.
I'm not sure yet if this works but whenever I try to do:
k = OnlyOne(1)
a = OnlyOneTwo(2)
the output will be:
called
1
1
which means that OnlyOneTwo wasn't set but when I try to do:
a = OnlyOneTwo(2)
k = OnlyOne(1)
the output will be:
called
called
2
1
Can someone help me traceback? I'm somehow confused but here are my initial questions/thoughts:
Does OnlyOneTwo's created property the same as OnlyOne's ? because I get different results through id() depending on which one I defined first. It's different if it's OnlyOneTwo first but it's the same if it's OnlyOne first.
How come created is still None if I will run a = OnlyOneTwo(2)
print(OnlyOne.created) ?
I'll give this a shot. I think the symptom is due to the assignment, cls.created = ... in __call__.
When the class objects are first created OnlyOneTwo.created points to OnlyOne.created. They both have the same id, which is the same as None.
>>> id(None)
506773144
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(506773144, 506773144)
If you make an instance of OnlyOne first, the instance is assigned to OnlyOne.created (it no longer points to None) but OnlyOneTwo.created still points to OnlyOne.created - they are still the same thing so that when OnlyOneTwo is called, the else clause of the conditional is executed.
>>> a = OnlyOne('a')
called
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(54522152, 54522152)
>>> z = OnlyOneTwo('z')
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(54522152, 54522152)
>>> id(a)
54522152
When you make an instance of OnlyOneTwo first, that instance is assigned to OnlyOneTwo.created, it no longer points to OnlyOne.created. OnlyOne.created still points to None.
>>> id(None)
506773144
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(506773144, 506773144)
>>> z = OnlyOneTwo('z')
called
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(506773144, 54837544)
>>> id(z)
54837544
Now when you make an instance of OnlyOne the if condition is True and the instance is assigned to OnlyOne.created
>>> a = OnlyOne('a')
called
>>> id(OnlyOne.created), id(OnlyOneTwo.created)
(54352752, 54837544)
>>> id(a)
54352752
I often find myself re-reading Binding of Names and Resolution of Names - also A Word About Names and Objects and Python Scopes and Namespaces
I feel that I haven't actually explained the mechanism - I don't really understand how the child class attribute points to the base class attribute - it is something different than a = b = None.
Maybe:
Initially the child class doesn't actually have the attribute, the points to mechanism is how inheritance is implemented, since it doesn't have the attribute, the attribute is searched for in its parent(s).
Even though the parent class attribute changes with instantiation, the child class still doesn't have the attribute and has to search for it and it finds the new thing.
If the child class is instantiated first the assignment in the metaclass gives the attribute to the child class - now it has it and it doesn't have to search for it.
Re-reading the Custom Classes section of the Standard Type Hierarchy in the docs triggered that brain dump.
I feel like I've been here before, maybe even in SO. Hope I remember it this time and don't have to figure it out again.
If you want to fix your Singleton there are numerous options if you search for them. Using a metaclass it seems the instance is held in the metaclass, not the the class itself. Creating a singleton in Python, SO Q&A, is a good start.
This question already has answers here:
What is the purpose of the `self` parameter? Why is it needed?
(26 answers)
Closed 6 years ago.
In the following example employee is not used in the __init__ function, but we used it in the add_employee function calling self.employee.append().
Why is that? Why did we use self.employee.append() instead of employee.append() ? I thought we only use self for variables in the __init__ function.
class Workers():
employee = []
def __init__(self, name):
self.name = name
self.skills = []
self.add_employee()
def add_employee(self):
self.employee.append(self.name)
print('{} added to list'.format(self.name))
employee, __init__, and add_employee are just attributes of the class Workers.
employee is an attribute being a list, and __init__ is another attribute, being a method.
Also from the [def documentation](
https://docs.python.org/3/reference/compound_stmts.html#grammar-token-funcdef):
A function definition is an executable statement. Its execution binds the function name in the current local namespace to a function object (a wrapper around the executable code for the function).
so employees and __init__ and all other methods are really the same: names in a namespaces.
See also
https://docs.python.org/3/tutorial/classes.html#class-objects
The employee object is a class variable, not an instance variable. This means it is shared across all instances of that class. You can access it with classname.classvariablename or instancename.classvariablename. If you reassign an instance's version of it with something like instancename.classvariablename = newvalue, that instance will have a new instance variable of that name that masks its access to the class variable with the self reference (i.e., you won't be able to do instancename.classvariablename to get the class variable), but other instances - and the class - will still be able to (i.e., classname.classvariable will still work, and otherinstancename.classvariable will still point to that class variable). The following example demonstrates this.
>>> class A:
... l = []
...
>>> a = A()
>>> b = A()
>>> a.l
[]
>>> A.l
[]
>>> a.l = 3
>>> b.l
[]
>>> b.l.append(1)
>>> b.l
[1]
>>> A.l
[1]
>>> a.l
3
I found that some classes contain a __init__ function, and some don’t. I’m confused about something described below.
What is the difference between these two pieces of code:
class Test1(object):
i = 1
and
class Test2(object):
def __init__(self):
self.i = 1
I know that the result or any instance created by these two class and the way of getting their instance variable are pretty much the same. But is there any kind of “default” or “hidden” initialization mechanism of Python behind the scene when we don’t define the __init__ function for a class? And why I can’t write the first code in this way:
class Test1(object):
self.i = 1
That’s my questions. Thank you very much!
Thank you very much Antti Haapala! Your answer gives me further understanding of my questions. Now, I understand that they are different in a way that one is a "class variable", and the other is a "instance variable". But, as I tried it further, I got yet another confusing problem.
Here is what it is. I created 2 new classes for understanding what you said:
class Test3(object):
class_variable = [1]
def __init__(self):
self.instance_variable = [2]
class Test4(object):
class_variable = 1
def __init__(self):
self.instance_variable = 2
As you said in the answer to my first questions, I understand the class_variable is a "class variable" general to the class, and should be passed or changed by reference to the same location in the memory. And the instance_variable would be created distinctly for different instances.
But as I tried out, what you said is true for the Test3's instances, they all share the same memory. If I change it in one instance, its value changes wherever I call it.
But that's not true for instances of Test4. Shouldn't the int in the Test4 class also be changed by reference?
i1 = Test3()
i2 = Test3()
>>> i1.i.append(2)
>>> i2.i
[1, 2]
j1 = Test4()
j2 = Test4()
>>> j1.i = 3
>>> j2.i
1
Why is that? Does that "=" create an "instance variable" named "i" without changing the original "Test4.i" by default? Yet the "append" method just handles the "class variable"?
Again, thank you for your exhaustive explanation of the most boring basic concepts to a newbie of Python. I really appreciate that!
In python the instance attributes (such as self.i) are stored in the instance dictionary (i.__dict__). All the variable declarations in the class body are stored as attributes of the class.
Thus
class Test(object):
i = 1
is equivalent to
class Test(object):
pass
Test.i = 1
If no __init__ method is defined, the newly created instance usually starts with an empty instance dictionary, meaning that none of the properties are defined.
Now, when Python does the get attribute (as in print(instance.i) operation, it first looks for the attribute named i that is set on the instance). If that fails, the i attribute is looked up on type(i) instead (that is, the class attribute i).
So you can do things like:
class Test:
i = 1
t = Test()
print(t.i) # prints 1
t.i += 1
print(t.i) # prints 2
but what this actually does is:
>>> class Test(object):
... i = 1
...
>>> t = Test()
>>> t.__dict__
{}
>>> t.i += 1
>>> t.__dict__
{'i': 2}
There is no i attribute on the newly created t at all! Thus in t.i += 1 the .i was looked up in the Test class for reading, but the new value was set into the t.
If you use __init__:
>>> class Test2(object):
... def __init__(self):
... self.i = 1
...
>>> t2 = Test2()
>>> t2.__dict__
{'i': 1}
The newly created instance t2 will already have the attribute set.
Now in the case of immutable value such as int there is not that much difference. But suppose that you used a list:
class ClassHavingAList():
the_list = []
vs
class InstanceHavingAList()
def __init__(self):
self.the_list = []
Now, if you create 2 instances of both:
>>> c1 = ClassHavingAList()
>>> c2 = ClassHavingAList()
>>> i1 = InstanceHavingAList()
>>> i2 = InstanceHavingAList()
>>> c1.the_list is c2.the_list
True
>>> i1.the_list is i2.the_list
False
>>> c1.the_list.append(42)
>>> c2.the_list
[42]
c1.the_list and c2.the_list refer to the exactly same list object in memory, whereas i1.the_list and i2.the_list are distinct. Modifying the c1.the_list looks as if the c2.the_list also changes.
This is because the attribute itself is not set, it is just read. The c1.the_list.append(42) is identical in behaviour to
getattr(c1, 'the_list').append(42)
That is, it only tries read the value of attribute the_list on c1, and if not found there, then look it up in the superclass. The append does not change the attribute, it just changes the value that the attribute points to.
Now if you were to write an example that superficially looks the same:
c1.the_list += [ 42 ]
It would work identical to
original = getattr(c1, 'the_list')
new_value = original + [ 42 ]
setattr(c1, 'the_list', new_value)
And do a completely different thing: first of all the original + [ 42 ] would create a new list object. Then the attribute the_list would be created in c1, and set to point to this new list. That is, in case of instance.attribute, if the attribute is "read from", it can be looked up in the class (or superclass) if not set in the instance, but if it is written to, as in instance.attribute = something, it will always be set on the instance.
As for this:
class Test1(object):
self.i = 1
Such thing does not work in Python, because there is no self defined when the class body (that is all lines of code within the class) is executed - actually, the class is created only after all the code in the class body has been executed. The class body is just like any other piece of code, only the defs and variable assignments will create methods and attributes on the class instead of setting global variables.
I understood my newly added question. Thanks to Antti Haapala.
Now, when Python does the get attribute (as in print(instance.i) operation, it first looks for the attribute named i that is set on the instance). If that fails, the i attribute is looked up on type(i) instead (that is, the class attribute i).
I'm clear about why is:
j1 = Test4()
j2 = Test4()
>>> j1.i = 3
>>> j2.i
1
after few tests. The code
j1.3 = 3
actually creates a new instance variable for j1 without changing the class variable. That's the difference between "=" and methods like "append".
I'm a newbie of Python coming from c++. So, at the first glance, that's weird to me, since I never thought of creating a new instance variable which is not created in the class just using the "=". It's really a big difference between c++ and Python.
Now I got it, thank you all.
I'm trying to understand Python's classes and for that I created this simple program:
class TestClass(object):
b = 3
def __init__(self):
self.a = 1
print '*** INIT ***'
print self.a, TestClass.b
print
def set_all(self):
self.a *= 2
TestClass.b *= 2
def print_all(self):
print 'PrintAll'
print self.a, TestClass.b
print
def main():
c = TestClass()
c.a *= 10
TestClass.b *= 10
c.b *= 10
print c.a, TestClass.b, c.b
print
c.print_all()
c.set_all()
print c.a, TestClass.b, c.b
TestClass.b
c.b
if __name__ == '__main__':
main()
I already understood that var c.a is an instance var. Var TestClass.b is a class/static var.
My 1st question is what is var c.b?
The program shows that it is different than TestClass.b.
My 2nd question is when should I use class/static vars instead of instance vars?
Thanks,
JM
To answer your first question, c.b is initially another name for TestClass.b, because no b attribute exists on the instance c. However, as soon as you do an assignment to it by that name (as you do with c.b *= 10), you create a new instance variable b on the c instance which shadows the class variable b. From then on c.b is unrelated to TestClass.b and works just like any other instance variable.
As to your second question, there are a few times where class variables are useful. Perhaps the most common is for class constants, which are not expected to change throughout the running of the program. Python doesn't have any easy way to actually prevent other users from reassigning them, but if you name them in ALL_CAPITOLS and document that they're intended to be constant anyone who messes with them deserves any bugs they cause. Putting the constants in the class means that you don't need to recalculate them over and over for each instance (or worse, for each call to a method).
Another use of class variables is for bookkeeping, such as counting the number of objects of a class that have been created. This can be useful if each instance needs a unique ID number, just copy the current count into an instance variable! Other situations come up when you want to have only a limited number of instances (often just a single one, as a Singleton). You can store that instance in a class variable and return it from __new__, to prevent other instances from being created.
Some programmers like to use class variables as default values for instance variables that may be created later to shadow them (as in question 1). While this isn't forbidden by Python's language design, I tend not to like this style of code as it can be confusing to see a method refer to something that looks like an instance variable which doesn't exist yet. It can also get badly broken if you use mutable objects as the class variable defaults. I think it's better to stick with instance variables from the start, assigning them default values as necessary in __init__.
To answer your second question, static variables are used to contain some general information about the class. For a simple example, let us say that you have a Student class which holds the info about the students in some class. You use an instance variable "marks", to keep track of object specific data. i.e. Marks of each student.
Whereas, if you want to keep track of the number of students you have, a static variable comes in handy here. So, the static variable can be increased whenever an object is created, and Student.count will give you the number of objects created.
Hope this helps...
As for your first question, I don't think TestClass.b is different from c.b. This is what I tried:
>>> class A:
... b = 3
... def __init__(self):
... self.a = 1
... A.b += 1
... print self.a,A.b
...
>>> c = A()
1 4
>>> c.b
4
>>> d = A()
1 5
>>> d.b
5
>>> c.b
5
I have been studying Python for three months and now I have a question that I could not solve by using google, but luckily I am able to simplify it here:
I have a var_class module:
#var_class.py
class A(object):
def __init__(self, x):
self.x = x+2
zz = A(10)
class B():
b = 0
def __init__(self):
pass
def update(self):
B.b = zz.x
and in main program I have:
#main.py
from var_class import *
b_class = B()
b_class.b # I get 0 as expected
zz = A(100)
b_class.update()
b_class.b # Instead of 102, I get 12 unexpectedly
You see my goal is to change "zz" frequently for every data input and then update a class variable 'b', and the reason I wrote zz = A(10) in var_class.py is that otherwise when I import it, module 'var_class' is missing 'zz' in 'class B', it would give error "global name zz is not defined".
However, as I write it like this now, looks like the value '10' is stuck to the class, and I am not able to change it in the main program. Don't know how to overcome this.
Thanks in advance for any help.
Answer:
alKid wrote the whole answer first, have to thanks to alexvassel and Mr. C too, would like to know if there is way to thanks them, others helped me with the knowledge, also appreciate a lot.
Easy understanding:
You can't do that, you're inside var_class module, so zz is A(10).
How about passing zz as a parameter? Like this!
class A(object):
def __init__(self, x):
self.x = x+2
zz = A(10)
class B():
b = 0
def __init__(self):
pass
def update(self, zz):
B.b = zz.x
Hope this helps!
When you do B.b = zz.x (update method) you are inside the module var_class, so zz is A(10)
python runtime finds variables by namespace. Namespace is something like scope. When B.b = zz.x executes, the runtime first searches the local namespace(the function namespace -- update), it sees no zz. Then, it goes to the module space(var_class), well we get the variable and stop searching.
The python namespace search order:
1. local namespace, the function scope
2. global namespace, the module scope
3. built-in namespace
Better not use global variables around.
your code may like this:
class B():
b = 0
def __init__(self):
pass
def update(self, zz):
B.b = zz.x
That is a matter of scope! you are using zz = A(100) in your main.py. But when you call b_class.update(), b_class has to get "some2 variable called "zz" - and the one which is available is the one you defined in your class.py - and this one still has the value A(10)!!!
To work around this, you have different options.
The dirty hack (but closest to your solution) would be to define a global variable and use ist (google "python globals" for more info on this approach).
I would suggest passing A (or A.x) to your "update" method b_class.update(A.x). This avoids globals and is more readable. Of course, you'll have to adjust B.update for the new parameter.
when you import a variable from a module, you get a copy of the variable, not the original. you need to write to the original directly.
from a.b import c
from a.b.c import var
a.b.c.var = 1
var = 2
a.b.c.var
1
var
2
Edit: So, more correctly, in python, there are objects in memory, and then there are names for the objects. When you import a module, you create two separate names, but they both point to the same object - i.e. they have a reference to the same object. It's very similar to the below code, which doesn't require any imports at all:
>>> a = 4
>>> b = a
>>> b
4
>>> a
4
>>> b = 'something different'
>>> b
'something different'
>>> a
4
Why did changing b not also change a? The sequence is like this: First, we create an object (the 4) and point the name 'a' at it. Then, we create a name 'b', and we point it at the same object. So, now looking up those names returns the same object. Now, we then go back and point the name 'b' at a different object, a string. The object 'a' is pointing to still exists, and has not changed.
New users more often trip up on this the other way, with objects like lists:
>>> a = [1,2,3,4,5]
>>> b = a
>>> b
[1,2,3,4,5]
>>> a
[1,2,3,4,5]
>>> b.append(6)
>>> b
[1,2,3,4,5,6]
>>> a
[1,2,3,4,5,6]
>>> b = b[1:3]
>>> b
[2,3]
>>> a
[1,2,3,4,5,6]
What's going on here? Well, first we create a list object, and then point the name 'a' at it. Then we create the name 'b' and point it to the same object. So, 'a' and 'b' both point to the same list. Then, we use the reference b to get the object and modify it. Note that we haven't changed what 'b' points to in this case - we grabbed the reference, and then modified the object it points to directly. So, in this case, both 'a' and 'b' will see the change - they both point to the modified object. Then, we extract a slice, and assign it to 'b'. Now, this actually creates a new object, and points 'b' at it - 'b' is no longer pointing to the original object. So now 'a' and 'b' point to different objects, and now updates to one are no longer reflected in the other.
The import case is just a special case of this.
maybe you can do this
class B():
b = 0
def __init__(self):
pass
def update(self,value):
self.b =self.b+value