Are class fields inherited in python? - python

class A:
a = 3
def f(self):
print self.a
class C(A):
def __init__(self):
self.a = 4
>>> a=A()
>>> a.f()
3
>>> c = C()
>>> a.f()
3
>>> c.f()
4
//Update:
>>> C.a = 5
>>> A.a
3
>>> c.a
4
How to explain the result.
Seems like C and A has a different copy of a. In C++ a static member is expected to be shared with its derived class.

Martin Konecny's answer is mostly correct. There are class-level attributes (which are like static members) and instance-level attributes. All instances share their class attributes (but not their instance attributes), and they can be changed dynamically. Somewhat confusingly, you can get class attributes from an instance with the dot-notation, unless an instance attribute is defined with the same name. Perhaps these examples are illustrative:
>>> class A:
... a = 3
... def f(self):
... print self.a
...
>>> class C(A):
... def __init__(self):
... self.a = 4
...
>>> a = A()
>>>
>>> A.a # class-level attribute
3
>>> a.a # not redefined, still class-level attribute
3
>>> A.a = 5 # redefine the class-level attr
>>> A.a # verify value is changed
5
>>> a.a # verify instance reflects change
5
>>> a.a = 6 # create instance-level attr
>>> A.a # verify class-level attr is unchanged
5
>>> a.a # verify instance-level attr is as defined
6
>>> a.__class__.a # you can still get the class-level attr
5
>>>
>>> c1 = C()
>>> c2 = C()
>>> C.a # this changed when we did A.a = 5, since it's inherited
5
>>> c1.a # but the instance-level attr is still there
4
>>> c2.a # for both instances
4
>>> c1.a = 7 # but if we change one instance
>>> c1.a # (verify it is set)
7
>>> c2.a # the other instance is not changed
4

In python there is a class attribute and an instance attribute
class A:
a = 3 # here you are creating a class attribute
def f(self):
print self.a
class C(A):
def __init__(self):
self.a = 4 #here you are creating an instance attribute
Seems like C and A has a different copy of a.
Correct. If you're coming from Java, it's helpful to think of class A as a "static" field, and class C as an "instance" field.

Related

Why `is` return False for same instance method and class method but return True for staticmethod

Let the code speaks for the question:
>>> class A(object):
... a = None
... def b(self):
... pass
...
>>> a = A()
>>> a.a is a.a
True
>>> a.b is a.b
False
>>> class B(object):
... a = None
... #staticmethod
... def b():
... pass
...
>>> b = B()
>>> b.a is b.a
True
>>> b.b is b.b
True
>>> class C(object):
... a = None
... #classmethod
... def b(cls):
... pass
...
>>> c = C()
>>> c.a is c.a
True
>>> c.b is c.b
False
This will bound the method to the object of class.
a.b is a.b
<bound method A.b of <__main__.A object at 0x00000294E2DA1780>>
This will address the method directly because we can call static method directly with a class name it is not necessary to create an object to call static method.
b.b is b.b
<function B.b at 0x00000294E2C49D08>
This will bound the method directly to a class. You can call that method directly with a class name without creating an object or with object.
c.b is c.b
<bound method C.b of <class '__main__.C'>>

Python - Exclusive attribute value for object?

Let say I have this class:
class A(object):
def __init__(self, one=None):
self.one = one
So every time you create A object, you can assign one attribute. But only the last object assigned not false value gets to keep it.
For example:
a = A('a')
b = A('b')
c = A()
print a
print b
print c
----
None
b
None
Now these objects are also actual records (rows) in database, so those could be accessed later.
What could be a good pattern (if there is) to set such attribute dynamically (unsetting attribute for older objects)?
You could store an instance in a class variable and unset the previous one in the __init__.
class A(object):
obj = None
def __init__(self, one=None):
self.one = one
if self.one:
if A.obj:
A.obj.one = None
A.obj = self
def __str__(self):
return str(self.one)
Result:
>>> a = A('a')
>>> b = A('b')
>>> c = A()
>>> print a
None
>>> print b
b
>>> print c
None

python: class variables and instance variables

How python recognize class and instance level variables ? are they different ?
For example,
class abc:
i = 10
def __init__(self, i):
self.i = i
a = abc(30)
b = abc(40)
print a.i
print b.i
print abc.i
output
--------
30
40
10
Means, in above example when I access a.i (or b.i) and abc.i are they referring to completely different variables?
First, your sample is wrong for you can not init the instance if there is only a self in the __init__.
>>> class abc:
... i = 10
... j = 11
... def __init__(self, x):
... self.i = x
Then, when you access the attribute on the instance, it will check the instance variables first. Refer the paragraph here. As you guess:
>>> a = abc(30)
>>> a.i
30
>>> a.j
11
Besides, the class variables is an object shared by all the instances, and instance variables are owned by the instance:
>>> class abc:
... i = []
... def __init__(self, x):
... self.i = [x]
... abc.i.append(x)
...
>>> a = abc(30)
>>> b = abc(40)
>>> a.i
[30]
>>> b.i
[40]
>>> abc.i
[30, 40]
in above example when I access a.i (or b.i) and abc.i are they
referring to completely different variables?
Yes.
abc.i is a Class Object reference.
a.i and b.i are each Instance Object references.
They are all separate references.
This is all assuming your init is meant to be:
def __init__(self,i):
Other wise it doesn't work. In the third case, abc.i the class hasn't been initialized so i acts as a static variable for which you set the value at 10 in the class definition. In the first two instances, when you called init you created an instance of abc with a specific i value. When you ask for the i value of each of those instances you get the correct number.

Changing variables in multiple Python instances

Is there anyway to set the variables of all instances of a class at the same time? I've got a simplified example below:
class Object():
def __init__(self):
self.speed=0
instance0=Object()
instance1=Object()
instance2=Object()
#Object.speed=5 doesn't work of course
I can see it would be possible by adding all new instances to a list and iterating with isinstance(), but that's not desirable.
One, simpler way, as the other answers put it, is to keep your attribute always as a class attribute. If it is set on the class body, and all write access to the attribute is via the class name, not an instance, that would work:
>>> class Object(object):
... speed = 0
...
>>> a = Object()
>>> b = Object()
>>> c = Object()
>>>
>>> Object.speed = 5
>>> print a.speed
5
>>>
However, if you ever set the attribute in a single instance doing it this way, the instance will have its own attribute and it will no longer change along with the other instance's:
>>> a.speed = 10
>>> Object.speed = 20
>>> print b.speed
20
>>> print a.speed
10
>>>
To overcome that, so that whenever the attribute is set in any instance, the class attribute itself is changed, the easier way is to have the object as a property - whose setter sets the class attribute instead:
class Object(object):
_speed = 0
#property
def speed(self):
return self.__class__._speed
#speed.setter
def speed(self, value):
self.__class__._speed = value
Which works:
>>>
>>> a = Object()
>>> b = Object()
>>> a.speed, b.speed
(0, 0)
>>> a.speed = 10
>>> a.speed, b.speed
(10, 10)
If you want to have independent attribute on the instances, but a special "set_all" method that would set the attribute in all instances, the way to go is to use the gc (Garbage Collector) module in standard librayr, to find and loop through all instances of the class, and set their instance attributes:
import gc
class Object(object):
def __init__(self):
self.speed = 0
def set_all_speed(self, value):
for instance in (obj for obj in gc.get_referrers(self.__class__):
if isinstance(obj, self.__class__)):
instance.speed = value
Which results in:
>>> a =Object()
>>> b = Object()
>>> a.speed = 5
>>> b.speed = 10
>>> a.speed, b.speed
(5, 10)
>>> a.set_all_speed(20)
>>> a.speed, b.speed
(20, 20)
What about using a class attribute?
class Object():
speed=0
instance0=Object()
instance1=Object()
instance2=Object()
Object.speed=5
You could use a class attribute:
class Object():
speed = 0
instance0=Object()
instance1=Object()
instance2=Object()
Object.speed=5
# instance0.speed == instance1.speed == instance2.speed == Object.speed == 5
However this would mean that all instances would always have the same speed.
"Is there any way to set the variables of all instances of a class at the same time?"
That's a class attribute!
Some examples on how to access a class attribute:
>>> class Object:
... speed = 5
... #classmethod
... def first(cls):
... return cls.speed
... def second(self):
... return self.speed
...
>>> Object.speed
5
>>> instance = Object()
>>> instance.speed
5
>>> instance.first()
5
>>> instance.second()
5

Python - why use "self" in a class?

How do these 2 classes differ?
class A():
x=3
class B():
def __init__(self):
self.x=3
Is there any significant difference?
A.x is a class variable.
B's self.x is an instance variable.
i.e. A's x is shared between instances.
It would be easier to demonstrate the difference with something that can be modified like a list:
#!/usr/bin/env python
class A:
x = []
def add(self):
self.x.append(1)
class B:
def __init__(self):
self.x = []
def add(self):
self.x.append(1)
x = A()
y = A()
x.add()
y.add()
print("A's x:", x.x)
x = B()
y = B()
x.add()
y.add()
print("B's x:", x.x)
Output
A's x: [1, 1]
B's x: [1]
Just as a side note: self is actually just a randomly chosen word, that everyone uses, but you could also use this, foo, or myself or anything else you want, it's just the first parameter of every non static method for a class. This means that the word self is not a language construct but just a name:
>>> class A:
... def __init__(s):
... s.bla = 2
...
>>>
>>> a = A()
>>> a.bla
2
A.x is a class variable, and will be shared across all instances of A, unless specifically overridden within an instance.
B.x is an instance variable, and each instance of B has its own version of it.
I hope the following Python example can clarify:
>>> class Foo():
... i = 3
... def bar(self):
... print 'Foo.i is', Foo.i
... print 'self.i is', self.i
...
>>> f = Foo() # Create an instance of the Foo class
>>> f.bar()
Foo.i is 3
self.i is 3
>>> Foo.i = 5 # Change the global value of Foo.i over all instances
>>> f.bar()
Foo.i is 5
self.i is 5
>>> f.i = 3 # Override this instance's definition of i
>>> f.bar()
Foo.i is 5
self.i is 3
I used to explain it with this example
# By TMOTTM
class Machine:
# Class Variable counts how many machines have been created.
# The value is the same for all objects of this class.
counter = 0
def __init__(self):
# Notice: no 'self'.
Machine.counter += 1
# Instance variable.
# Different for every object of the class.
self.id = Machine.counter
if __name__ == '__main__':
machine1 = Machine()
machine2 = Machine()
machine3 = Machine()
#The value is different for all objects.
print 'machine1.id', machine1.id
print 'machine2.id', machine2.id
print 'machine3.id', machine3.id
#The value is the same for all objects.
print 'machine1.counter', machine1.counter
print 'machine2.counter', machine2.counter
print 'machine3.counter', machine3.counter
The output then will by
machine1.id 1
machine2.id 2
machine3.id 3
machine1.counter 3
machine2.counter 3
machine3.counter 3
I've just started learning Python and this confused me as well for some time. Trying to figure out how it all works in general I came up with this very simple piece of code:
# Create a class with a variable inside and an instance of that class
class One:
color = 'green'
obj2 = One()
# Here we create a global variable(outside a class suite).
color = 'blue'
# Create a second class and a local variable inside this class.
class Two:
color = "red"
# Define 3 methods. The only difference between them is the "color" part.
def out(self):
print(self.color + '!')
def out2(self):
print(color + '!')
def out3(self):
print(obj2.color + '!')
# Create an object of the class One
obj = Two()
When we call out() we get:
>>> obj.out()
red!
When we call out2():
>>> obj.out2()
blue!
When we call out3():
>>> obj.out3()
green!
So, in the first method self specifies that Python should use the variable(attribute), that "belongs" to the class object we created, not a global one(outside the class). So it uses color = "red". In the method Python implicitly substitutes self for the name of an object we created(obj). self.color means "I am getting color="red" from the obj"
In the second method there is no self to specify the object where the color should be taken from, so it gets the global one color = 'blue'.
In the third method instead of self we used obj2 - a name of another object to get color from. It gets color = 'green'.

Categories

Resources