In Python, do objects have their own copies of class variables? - python

This is a question which confuses every Python Intermediate learner, so please give a brief (and idiot-friendly) answer.
I wanted to create a variable which increments the variable population by 1 when a new object is created.
class Human:
population = 0
# initialization.
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def increment_pop(self):
self.population += 1
# class Human ends.
person = Human('Tom', 22, 'M')
person.increment_pop()
person.increment_pop()
print('Population : ', person.population)
person2 = Human('Anna', 24, 'F')
person2.increment_pop()
print('Population : ', person2.population)
print(Human.population)
Output :
Population : 2
Population : 1
0
So both the object and the class has the variable population? What is the difference between the variable population and the variables inside the init() method?
I know that only instance variables are inside the init() method.

It's a bit more complex than that. There are both class variables and instance variables, but what's happening in your example is that the class variable is being overridden by the instance variable.
Consider the following:
>>> class Foobar:
... my_list = []
...
>>> foo = Foobar()
>>> Foobar.my_list.append('hello')
>>> foo.my_list.append('world')
>>> foo.my_list
['hello', 'world']
As you can see the Foobar class and foo instance share a variable here. So no, instantiating a class does not "copy" all the class variables. Consider this, however:
>>> foo.my_list = ['spam', 'eggs']
>>> foo.my_list
['spam', 'eggs']
>>> Foobar.my_list
['hello', 'world']
Now we have two variables, one that's a class variable, the other that's an instance variable. They are no longer the same.
If you wanted to always use class variables, the most elegant thing would be to use class methods. Eg,
class Human:
population = 0
# initialization.
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
#classmethod
def increment_pop(cls):
cls.population += 1
Now because increment_pop is a class method, it will always operate on the class, not the instance. However, the population attribute will be available to instances and as long as they don't overwrite it, it will be the same as the class variable.
A few important things to keep in mind:
Primitives, like integers and strings, are immutable. When you do foo += 1, you're creating a new instance of an integer and replacing the old one. You're not modifying it in place.
Instances can access class variables and class methods with self.whatnot. But if you want to be unambiguous, you can also reference them as ClassName.whatnot.
Class methods can be called from instances, similarly, like self.class_method().
Other notes on Python variables
Let's back up here and consider how Python resolves a request for something like my_human.population on the instance:
First, Python looks for an instance attribute named population. If it exists, that's the value you get.
Second, Python looks for a class attribute named population. If that exists, that's the value you get.
So, when you have no assigned population on your instance, and you access self.population, since no instance attribute exists with that name, you get the class attribute.
However, once you assign an instance attribute to your object, that second step above never happens.
You can inspect this at runtime, too:
>>> class Human:
... population = 0
...
>>> my_human = Human()
>>> 'population' in Human.__dict__
True
>>> 'population' in my_human.__dict__
False
So population only exists on the Human class, not on the instance. When we access Human.population, it finds the class attribute:
>>> my_human.population
0
But what happens if I create an instance attribute?
>>> Human.population = 100
>>> my_human.population = 50
>>> Human.population
100
>>> my_human.population
50
Now, because the instance has an attribute matching the name population, when you access my_human.population, it never looks up what's on the class.

self references a specific instance of a class. When you call increment_pop, you are using self.population, which is causing the increment only of that instance. Because in python you do not need to call initializers, increment_pop is created a new variable called self.population, where the class variable population should be global.
Change increment_pop to have cls.population rather than self.population and it should work as intended. Note that in the function definition you'll need the decorator #classmethod and the parameter cls.

Related

Python Inner Class value assignment

I created a inner class within a class and created two instances of the class, but when assigning different values to the inner class properties, it is assigned to both instances. Can anyone help?
Here's the code
class cl1:
def __init__(self,tagName):
self.name = tagName
name1 = 'tagName'
class cl2:
name2 = 'name2'
test1 = cl1('test1')
test2 = cl1('test2')
test1.cl2.name2 = "cl1"
test2.cl2.name2 = 'cl2'
print (test1.cl2.name2)
When running it, the result is
cl2
Why it is not "cl1" as assigned?
The value:
test1.cl2.name2
Is a class attribute for the class cl2. It is associated with that class, not with instances of that class. So even though you're going through references to an instance of the cl1 class to set the value of that attribute, since there is only one of them, the last thing you set it to wins. Your print statements are printing that same single value.
Google "python class vs instance variables" for a number of good looking write-ups of what the differences are between class and instance variables/attributes.
Here's an example that 1) Provides instance vs class atributes just where it seems you wanted them, and 2) renames the classes involved to have uppercase names so it's obvious when you're referencing an instance attribute vs a class attribute.
class Cl1:
class Cl2:
def __init__(self, tagName):
self.name2 = tagName
def __init__(self, tagName1, tagName2):
self.name1 = tagName1
self.cl2 = Cl1.Cl2(tagName2)
test1 = Cl1('test1', 'test2')
test2 = Cl1('test2', 'test2')
test1.cl2.name2 = 'cl1'
test2.cl2.name2 = 'cl2'
print(test1.cl2.name2)
Result:
cl1
Note that because you want to have an instance of the inner class associated with each instance of the outer class, the inner class's constructor has to instantiate an instance of the inner class as part of creating the outer class instance.
Also note the references to self. Instance variables are created inside a classes's constructor (its __init__ function) by referencing them on self, a reference to the instance being created.

When assigning class name as a identifier to a variable there is a confusing behavior

I was playing around in Python as I am relatively new to it. Below is a snippet
class Person:
version = "1.0"
def __init__(self, name="john doe",age=25):
self.name = name
self.first_name = name.split()[0]
self.second_name = name.split()[1]
self.age = age
def printi(self):
print(self.name)
new_person = Person()
new_person.printi()
refPerson = Person
print(refPerson.version)
another_one = refPerson()
#another_one.version = "2.0"
print(another_one.version)
another_one.printi()
print(Person.version)
Person.version = "2.0"
print(another_one.version)
print(refPerson.version)
And If you notice, the class name Person is directly assigned to a variable refPerson. I was under the impression that post this assignment new class of name refPerson will be created. But when I modify the Person class attribute, I could see that the value change is reflected in the new class. What am I missing here? I just need a clear picture.
Thanks in advance.
Classes are first-class objects in Python; you can pass references to them around.
Person is a reference to the class defined by the class statement. Person() (calling the class object like a function) returns an instance of that class.
Attribute lookup rules can get complicated, but for this example the following simplification will suffice. Since neither new_person.version nor another_one.version is defined, an attempt to look either one up will result in a class attribute lookup. That is, new_person.version == type(new_person).version.
If you create an instance attribute with the same name, it will shadow the class attribute:
>>> new_person.version = 3
>>> new_person.version
3
>>> type(new_person).version
"1.0"
>>> another_one.version
"1.0"
Going into more detail than you are probably ready for at this stage, Person() breaks down into the following calls:
Person() is equivalent to Person.__call__(Person), where __call__ is an instance method of the class type, of which Person is an instance. (That is, type(Person) returns type.)
Person.__call__ calls Person.__new__, which returns a new instance of Person; call it p.
Person.__call__ then calls Person.__init__ with p as its argument.
Finally, Person.__call__ returns p.

Where to set the class members in Python? [duplicate]

Is there any difference at all between these classes besides the name?
class WithClass ():
def __init__(self):
self.value = "Bob"
def my_func(self):
print(self.value)
class WithoutClass ():
value = "Bob"
def my_func(self):
print(self.value)
Does it make any difference if I use or don't use the __init__ method for declaring the variable value?
My main worry is that I'll be using it one way, when that'll cause me further problems down the road.
Variable set outside __init__ belong to the class. They're shared by all instances.
Variables created inside __init__ (and all other method functions) and prefaced with self. belong to the object instance.
Without Self
Create some objects:
class foo(object):
x = 'original class'
c1, c2 = foo(), foo()
I can change the c1 instance, and it will not affect the c2 instance:
c1.x = 'changed instance'
c2.x
>>> 'original class'
But if I change the foo class, all instances of that class will be changed as well:
foo.x = 'changed class'
c2.x
>>> 'changed class'
Please note how Python scoping works here:
c1.x
>>> 'changed instance'
With Self
Changing the class does not affect the instances:
class foo(object):
def __init__(self):
self.x = 'original self'
c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'
I would like to add something to the responses that I read in this thread and this thread (which references this one).
Disclaimer: this remarks come from the experiments I ran
Variables outside __init__:
These are, in fact, static class variables and are, therefore, accesible to all instances of the class.
Variables inside __init__:
The value of these instance variables are only accesible to the instance at hand (through the self reference)
My contribution:
One thing that programmers must consider when using static class variables is that they can be shadowed by instance variables (if you are accessing the static class variables through the self reference).
Explanation:
Previously, I thought that both ways of declaring the variables were exactly the same (silly me), and that was partly because I could access both kind of variables through the self reference. It was now, when I ran into trouble, that I researched the topic and cleared it up.
The problem with accessing static class variables through the
self reference is that it only references the static class variable if there is no instance variable with the same name, and to make things worse, trying to redefine a static class variable through the self reference does not work because an instance variable is created which then shadows the previously-accesible static class variable.
To get around this problem, you should always reference static class variables through the name of the class.
Example:
#!/usr/bin/env python
class Foo:
static_var = 'every instance has access'
def __init__(self,name):
self.instance_var = 'I am %s' % name
def printAll(self):
print 'self.instance_var = %s' % self.instance_var
print 'self.static_var = %s' % self.static_var
print 'Foo.static_var = %s' % Foo.static_var
f1 = Foo('f1')
f1.printAll()
f1.static_var = 'Shadowing static_var'
f1.printAll()
f2 = Foo('f2')
f2.printAll()
Foo.static_var = 'modified class'
f1.printAll()
f2.printAll()
Output:
self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class
I hope this is helpful to someone
further to S.Lott's reply, class variables get passed to metaclass new method and can be accessed through the dictionary when a metaclass is defined. So, class variables can be accessed even before classes are created and instantiated.
for example:
class meta(type):
def __new__(cls,name,bases,dicto):
# two chars missing in original of next line ...
if dicto['class_var'] == 'A':
print 'There'
class proxyclass(object):
class_var = 'A'
__metaclass__ = meta
...
...
class User(object):
email = 'none'
firstname = 'none'
lastname = 'none'
def __init__(self, email=None, firstname=None, lastname=None):
self.email = email
self.firstname = firstname
self.lastname = lastname
#classmethod
def print_var(cls, obj):
print ("obj.email obj.firstname obj.lastname")
print(obj.email, obj.firstname, obj.lastname)
print("cls.email cls.firstname cls.lastname")
print(cls.email, cls.firstname, cls.lastname)
u1 = User(email='abc#xyz', firstname='first', lastname='last')
User.print_var(u1)
In the above code, the User class has 3 global variables, each with value 'none'. u1 is the object created by instantiating this class. The method print_var prints the value of class variables of class User and object variables of object u1. In the output shown below, each of the class variables User.email, User.firstname and User.lastname has value 'none', while the object variables u1.email, u1.firstname and u1.lastname have values 'abc#xyz', 'first' and 'last'.
obj.email obj.firstname obj.lastname
('abc#xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')
In Python, a class comes with member functions (methods), class variables, attributes/instance variables (and probably class methods too):
class Employee:
# Class Variable
company = "mycompany.com"
def __init__(self, first_name, last_name, position):
# Instance Variables
self._first_name = first_name
self._last_name = last_name
self._position = position
# Member function
def get_full_name(self):
return f"{self._first_name} {self._last_name}"
By creating an instance of the object
my_employee = Employee("John", "Wood", "Software Engineer")
we essentially trigger __init__ that is going to initialise the instance variables of the newly created Employee. This means that _first_name, _last_name and _position are explicit parameters of the specific my_employee instance.
Likewise, member functions return information or change the state of a specific instance.
Now any variable defined outside the constructor __init__ are considered to be class variables. Those variables are shared amongst all the instances of the class.
john = Employee("John", "Wood", "Software Engineer")
bob = Employee("Bob", "Smith", "DevOps Engineer0")
print(john.get_full_name())
print(bob.get_full_name())
print(john.company)
print(bob.company)
>>> John Wood
>>> Bob Smith
>>> mycompany.com
>>> mycompany.com
You can also use class methods in order to change the class variable for all the instances of the class. For example:
#classmethod
def change_my_companys_name(cls, name):
cls.company = name
and now change_my_companys_name()
bob.change_my_companys_name("mynewcompany.com")
will have effect on all the instances of class Employee:
print(bob.company)
print(john.company)
>>> mynewcompany.com
>>> mynewcompany.com
Example code:
class inside:
def __init__(self):
self.l = []
def insert(self, element):
self.l.append(element)
class outside:
l = [] # static variable - the same for all instances
def insert(self, element):
self.l.append(element)
def main():
x = inside()
x.insert(8)
print(x.l) # [8]
y = inside()
print(y.l) # []
# ----------------------------
x = outside()
x.insert(8)
print(x.l) # [8]
y = outside()
print(y.l) # [8] # here is the difference
if __name__ == '__main__':
main()
This is very easy to understand if you track class and instance dictionaries.
class C:
one = 42
def __init__(self,val):
self.two=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)
The result will be like this:
{'two': 50}
{'__module__': '__main__', 'one': 42, '__init__': <function C.__init__ at 0x00000213069BF6A8>, '__dict__': <attribute '__dict__' of 'C' objects>, '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None}
Note I set the full results in here but what is important that the instance ci dict will be just {'two': 50}, and class dictionary will have the 'one': 42 key value pair inside.
This is all you should know about that specific variables.
classes are like blueprints to create objects. Let's make a metaphor with building a house. You have the blueprint of the house so you can build a house. You can build as many houses as your resources allow.
In this metaphor, the blueprint is the class and the house is the instantiation of the class, creating an object.
The houses have common attributes like having a roof, living room, etc. This is where you init method goes. It constructs the object (house) with the attributes you want.
Lets suppose you have:
`class house:`
`roof = True`
`def __init__(self, color):`
`self.wallcolor = color`
>> create little goldlock's house:
>> goldlock = house() #() invoke's class house, not function
>> goldlock.roof
>> True
all house's have roofs, now let's define goldlock's wall color to white:
>> goldlock.wallcolor = 'white'
>>goldlock.wallcolor
>> 'white'
class foo(object):
mStatic = 12
def __init__(self):
self.x = "OBj"
Considering that foo has no access to x at all (FACT)
the conflict now is in accessing mStatic by an instance or directly by the class .
think of it in the terms of Python's memory management :
12 value is on the memory and the name mStatic (which accessible from the class)
points to it .
c1, c2 = foo(), foo()
this line makes two instances , which includes the name mStatic that points to the value 12 (till now) .
foo.mStatic = 99
this makes mStatic name pointing to a new place in the memory which has the value 99 inside it .
and because the (babies) c1 , c2 are still following (daddy) foo , they has the same name (c1.mStatic & c2.mStatic ) pointing to the same new value .
but once each baby decides to walk alone , things differs :
c1.mStatic ="c1 Control"
c2.mStatic ="c2 Control"
from now and later , each one in that family (c1,c2,foo) has its mStatica pointing to different value .
[Please, try use id() function for all of(c1,c2,foo) in different sates that we talked about , i think it will make things better ]
and this is how our real life goes . sons inherit some beliefs from their father and these beliefs still identical to father's ones until sons decide to change it .
HOPE IT WILL HELP
As noted by S.Lott,
Variable set outside init belong to the class. They're shared by
all instances.
Variables created inside init (and all other method functions) and
prefaced with self. belong to the object instance.
However,
Note that class variables can be accessed via self.<var> until they are masked by an object variable with a similar name This means that reading self.<var> before assigning it a value will return the value of Class.<var> but afterwards it will return obj.<var> . Here is an example
In [20]: class MyClass:
...: elem = 123
...:
...: def update(self,i):
...: self.elem=i
...: def print(self):
...: print (MyClass.elem, self.elem)
...:
...: c1 = MyClass()
...: c2 = MyClass()
...: c1.print()
...: c2.print()
123 123
123 123
In [21]: c1.update(1)
...: c2.update(42)
...: c1.print()
...: c2.print()
123 1
123 42
In [22]: MyClass.elem=22
...: c1.print()
...: c2.print()
22 1
22 42
Second note: Consider slots. They may offer a better way to implement object variables.
Try this and check the difference
class test:
f = 3
def __init__(s, f):
s.__class__.f = f
s.f = s.__class__.f
print(f'def __init__(s, {f})')
print(f's.__class__.f = {f}')
print(f's.f={s.__class__.f}')
print(f'f={f}')
print('===============init over===========')
def setinstancetoOne(s, f):
print(f'def setinstancetoOne(s, {f})')
s.f = f
print(f'class var f = {f}')
def useClassname(test):
print(f'>>>>def useClassname({test})')
print(f'test.f {test.f}')
def p_method(s):
print(f'>>>>def p_method({s})')
print(f's.f {s.f}')
print(f'test.f {test.f}')
print(f's.__class__.f {s.__class__.f}')
print(f'class var f={f}')
# test.__init__.f = 19
t = test(2)
t.useClassname()
t.p_method()
print(f'Outside class t.f {t.f}')
print(f'Outside class test.f {test.f}')
print('______difference__________')
t = test(2)
t.setinstancetoOne(1)
t.useClass()
t.p_method()
print(f'Outside class instance variable(2) {t.f}')
print(f'Outside class class variable(3) {test.f}')

Please help my understanding of python class vs instance variables

I'm new to Python, and I'm having a little trouble comprehending how Python interprets class and instance variables. My background is C#, so I have a fairly good understanding of OOP (from a C# mindset), however I'm just a little confused with python. I'm guessing this is because I'm thinking in the wrong mind set.
Take the following class as example:
class User():
"""The default user implementation"""
# define the variables
id = None
first_name = None
last_name = None
email = None
password = None
created = None
deleted = False
def __init__(self):
"""Creates a new instance of the User object."""
self.is_admin = False
From the documentation that I have read, all of the id, first_name, last_name etc. are class attribute which are shared between instances. These would be static within a C# mindset. Then the is_admin is an instance attribute, which is limited to a specific instance of the object. These would be fields or properties within C#.
However, my confusion comes when I do something like this:
new_user = User()
new_user.id = "blah"
new_user.last_name = "lasty"
new_user1 = User()
new_user1.id = "some_id"
new_user1.last_name = "firsty"
This sets the values as:
new_user.id = "blah"
new_user.last_name = "lasty"
new_user1.id = "some_id"
new_user1.last_name = "firsty"
Given that the id and last_name are defined as class attributes, I would have assumed that the calls to the new_user1 objects would have overwritten the "blah" and "lasty" values, however each instance has retained the values that were defined to it. Hence, my confusion.
If this is normal, could someone please shed some light on to why this is? Also, in that case, how does one define a static variable?
Cheers,
Justin
Python looks up attributes on the instance, then the instance's class, then any base classes and their parents. So id and last_name are instance attributes that hide the attributes of the same name on the class. If you access an attribute you did not set on the instance (such as first_name) then you get the class's attribute since it was not found on the instance.
Simplest idea that works and shows the difference between a class variable and an instance variable:
>>> import datetime
>>> class Example:
... my_name = 'example'
... def __init__(self):
... self.now = datetime.datetime.now()
...
>>> e = Example()
>>> e.my_name
'example'
>>> e.now
datetime.datetime(2015, 6, 1, 2, 2, 58, 211399)
>>> d = Example()
>>> d.my_name
'example'
>>> d.now
datetime.datetime(2015, 6, 1, 2, 4, 21, 165731)
>>>
my_name is a class variable -- it is a property of the class and any instance of the class has access to that property. now is an instance variable -- only object of type Example have access to datetime and datetime is different for each object.
To drive the point home, let's try to access each variable from the class itself:
>>> Example.now
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Example' has no attribute 'now'
>>> Example.my_name
'example'
>>>
An object CAN modify a class variable for that instance:
>>> d.my_name = "George"
>>> d.may_name
'George'
>>> Example.my_name
'example'
But not for the class.
Static is a keyword that references static linkage in C and C++ and is used in many modern OO languages to denote a piece of code that is shared by all objects of a class but is not a class method or variable per se. Python as a staticmethod decorator for methods. but there are no static variables, only class variables.
I hope that clarifies things.
Class variables are not really 'static' in the sense that C and Java uses the term. They are easily overwritten. They are better thought of as single copy default values associated with the class object.
Consider (in Python 3):
class Foo(object):
cv='cv'
def __setattr__(self, name, value):
if name in self.__class__.__dict__:
print('Overloading class var "{}" with instance attribute "{}"'.format(self.__class__.__dict__[name], value))
super(self.__class__, self).__setattr__(name, value)
def __getattribute__(*args):
self, name, *the_rest=args
if name in Foo.__dict__:
print('there is a class variable called "{}" with value of: "{}"'.format(name, Foo.__dict__[name]))
return object.__getattribute__(*args)
Now instantiate a copy of the class Foo and test the class variable and instance variables:
>>> foo=Foo()
>>> foo.cv
there is a class variable called "cv" with value of: "cv"
'cv'
>>> foo.cv='IV'
Overloading class var "cv" with instance attribute "IV"
>>> foo.cv
there is a class variable called "cv" with value of: "cv"
'IV'
>>> Foo.cv='NEW CV'
>>> bar=Foo()
>>> bar.cv
there is a class variable called "cv" with value of: "NEW CV"
'NEW CV'
Python does not have constants or static variables. For class attributes it is the same. The class is loaded with the value on import. If the user changes that value for import.
class MyClass(object):
id = 1
def main():
myclass = MyClass()
print("class1", myclass.id)
print()
myclass2 = MyClass()
myclass2.id = 2
print("class1", myclass.id)
print("class2", myclass2.id)
print()
MyClass.id = 3
myclass3 = MyClass()
print("class1", myclass.id)
print("class2", myclass2.id)
print("class3", myclass3.id)
print()
myclass4 = MyClass()
print("class1", myclass.id)
print("class2", myclass2.id)
print("class3", myclass3.id)
print("class4", myclass4.id)
print()
myclass5 = MyClass()
myclass5.id = 5
print("class1", myclass.id)
print("class2", myclass2.id)
print("class3", myclass3.id)
print("class4", myclass4.id)
print("class5", myclass5.id)
# end main
if __name__ == '__main__':
main()
The results are interesting.
class1 1
class1 1
class2 2
class1 3
class2 2
class3 3
class1 3
class2 2
class3 3
class4 3
class1 3
class2 2
class3 3
class4 3
class5 5
If you have not set the instance id it will default to the class id.
MyClass.id = 1
This will change the value of an instance if the instance did not set a value.

What is the difference between declaring data attributes inside or outside __init__ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python: Difference between class and instance attributes
I'm trying to get my head around OOP in Python and I'm a bit confused when it comes to declare variables within a class. Should I declare them inside of the __init__ procedure or outside it? What's the difference?
The following code works just fine:
# Declaring variables within __init__
class MyClass:
def __init__(self):
country = ""
city = ""
def information(self):
print "Hi! I'm from %s, (%s)"%(self.city,self.country)
me = MyClass()
me.country = "Spain"
me.city = "Barcelona"
me.information()
But declaring the variables outside of the __init__ procedure also works:
# Declaring variables outside of __init__
class MyClass:
country = ""
city = ""
def information(self):
print "Hi! I'm from %s, (%s)"%(self.city,self.country)
me = MyClass()
me.country = "Spain"
me.city = "Barcelona"
me.information()
In your first example you are defining instance attributes. In the second, class attributes.
Class attributes are shared between all instances of that class, where as instance attributes are "owned" by that particular instance.
Difference by example
To understand the differences let's use an example.
We'll define a class with instance attributes:
class MyClassOne:
def __init__(self):
self.country = "Spain"
self.city = "Barcelona"
self.things = []
And one with class attributes:
class MyClassTwo:
country = "Spain"
city = "Barcelona"
things = []
And a function that prints out information about one of these objects:
def information(obj):
print "I'm from {0}, ({1}). I own: {2}".format(
obj.city, obj.country, ','.join(obj.things))
Let's create 2 MyClassOne objects and change one to be Milan, and give Milan "something":
foo1 = MyClassOne()
bar1 = MyClassOne()
foo1.city = "Milan"
foo1.country = "Italy"
foo1.things.append("Something")
When we call information() on the foo1 and bar1 we get the values you'd expect:
>>> information(foo1)
I'm from Milan, (Italy). I own: Something
>>> information(bar1)
I'm from Barcelona, (Spain). I own:
However, if we were to do exactly the same thing, but using instances of MyClassTwo you'll see that the class attributes are shared between instances.
foo2 = MyClassTwo()
bar2 = MyClassTwo()
foo2.city = "Milan"
foo2.country = "Italy"
foo2.things.append("Something")
And then call information()...
>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own: Something
So as you can see - things is being shared between the instances. things is a reference to a list that each instance has access to. So if you append to things from any instance that same list will be seen by all other instances.
The reason you don't see this behaviour in the string variables is because you are actually assigning a new variable to an instance. In this case that reference is "owned" by the instance and not shared at the class level. To illustrate let's assign a new list to things for bar2:
bar2.things = []
This results in:
>>> information(foo2)
I'm from Milan, (Italy). I own: Something
>>> information(bar2)
I'm from Barcelona, (Spain). I own:
You're two versions of the code are very different. In python, you have 2 distinct entities: classes and class instances. An instance is what is created when you do:
new_instance = my_class()
You can bind attributes to an instance within __init__ via self (self is the new instance).
class MyClass(object):
def __init__(self):
self.country = "" #every instance will have a `country` attribute initialized to ""
There's nothing terribly special about self and __init__. self is the customary name that is used to represent the instance that gets passed to every method (by default).
a.method() #-> Inside the class where `method` is defined, `a` gets passed in as `self`
The only thing special here is that __init__ gets called when the class is constructed:
a = MyClass() #implicitly calls `__init__`
You can also bind attributes to the class (putting it outside __init__):
class MyClass(object):
country = "" #This attribute is a class attribute.
At any point, you can bind a new attribute to an instance simply by:
my_instance = MyClass()
my_instance.attribute = something
Or a new attribute to a class via:
MyClass.attribute = something
Now it gets interesting. If an instance doesn't have a requested attribute, then python looks at the class for the attribute and returns it (if it is there). So, class attributes are a way for all instances of a class to share a piece of data.
Consider:
def MyClass(object):
cls_attr = []
def __init__(self):
self.inst_attr = []
a = MyClass()
a.inst_attr.append('a added this')
a.cls_attr.append('a added this to class')
b = MyClass()
print (b.inst_attr) # [] <- empty list, changes to `a` don't affect this.
print (b.cls_attr) # ['a added this to class'] <- Stuff added by `a`!
print (a.inst_attr) #['a added this']
When you define a variable in class scope (outside any method), it becomes a class attribute. When you define a value in method scope, it becomes a method local variable. If you assign a value to an attribute of self (or any other label referencing an object), it becomes (or modifies) an instance attribute.

Categories