class members also creates instance members in python - python

It seems that python class members also are "secretly" copied to instance members, I have never heard of this. Is this described somewhere?
Here is a small example I did to investigate this (python 3.6.7 ubuntu 18:04).
class A:
a = 'hello' # class member
def __init__(self):
print(self.a) # a has also become a instance member
self.a = 'Hi' # change the instance member of a
print(A.a) # class member a unchanged
a = A()

This is not at all a "secret" copy. It is the intended behaviour and for example discussed here in the official reference (3.2. The standard type hierarchy: "Class instances"):
A class instance is created by calling a class object (see above). A class instance has a namespace implemented as a dictionary which is the first place in which attribute references are searched. When an attribute is not found there, and the instance’s class has an attribute by that name, the search continues with the class attributes. [...]
By creating an entry for the attribute in the class instance's dictionary, you shadow the class's attribute entry.
Let's walk through your example step-by-step:
def __init__(self):
print(self.a) # (1.)
self.a = 'Hi' # (2.)
print(A.a) # (3.)
Attribute lookup starts at the instance's attribute dict. No matching attribute is found, hence, lookup continues at the class's attribute dict. A matching attribute, a = 'hello', is found.
An explicit assignment using the class instance creates a new attribute entry of name a in the class instance's attribute dict. Consequently, this attribute is unique to the class instance.
The class attribute remains unchanged because it resides in an entirely different dict, the attribute dict of the class rather than the instance.

Related

We can create instance attrbitues for objects in Python. Can we create instance methods (not class Methods) as well in Python?

How To create a methods which are common to a particular object just like creating instance attrbitue obj.instance_attribute
A method which belongs specifically for a single object ?
The link contains the code. I need to create method only for this object and not all instance of class.
Creating class methods and attribute. The instance attrbitue. How to create instance methods
class A():
def init(self):
self.class_variable = 999999
def class_methods(self):
#available to all object
print("Hey")
obj = A()
obj.class_variable
999999
obj.class_methods()
Hey
obj.instance_attribute = 40404040 #common to particular object
obj.instance_attribute
40404040
#a method which is common to only this object
obj.new_method():
SyntaxError: invalid syntax
obj.new_mehtod(self):
SyntaxError: invalid syntax
I think you are mixing up terminology. Every "normal" method is a instance method - that means it applies the function without affecting any other instances of this class. To reference the instance, use the passed self keyword.
Defining a method for a single instance inside the generator/ class definition does not make sense in an OOP-context. If you create a car class, every instance of this class should be able to access its methods, like drive().
The only way to add a unique function is to add it after instantiating the object. This can be done with the types.MethodType method, which binds the function to the class instance:
from types import MethodType
def fly(self):
print(f"i, {self.name}, can fly")
class Car:
def __init__(self, name):
self.name = name
car_1 = Car("car one")
car_2 = Car("car two")
car_1.fly = MethodType(fly, car_1)
car_1.fly() # i, car one, can fly
car_2.fly() # AttributeError: 'Car' object has no attribute 'fly'
As you can see, car_1 has the class fly, which references car_1's name, while car_2 does not have this function.
But you should seriously reconsider what you are trying to achieve here.

Python official name for an attribute that is not a method

According to my understanding the data members of objects in Python are referred to as 'attributes'.
Attributes that are callable are referred to as an object's 'methods', but I couldn't find a name for non-callable attributes, such as val in the following example:
class C:
def __init__(self):
self.val = 42. # How would this be called?
def self.action():
"""A method."""
print(self.val)
I am sure different people may call val different things like 'field' or 'variable' but I am interested in an official name.
Surprisingly hard to find official information on this topic. After reading this article I do believe it should simply be called Class Variable and Instance Variable.
Attributes, Properties, Methods and Variables
Attribute is the collection name for the three names Property, Method and Variable. The latter two are prefixed by either Class or Instance. A property can only belong to the Class.
class Foo:
a = 1
def __init__(self):
self.b = 2
#property
def c(self):
return 3
#classmethod
def d(cls):
return 4
def e(self):
return 5
Foo.a # Class Attribute: Class Variable
Foo().a # Class Attribute: Class Variable
Foo().b # Instance Attribute: Instance Variable
Foo.c # Class Attribute: Property
Foo.d # Class Attribute: Class Method
Foo().d # Class Attribute: Class Method
Foo.e # Class Attribute: Class Method
Foo().e # Instance Attribute: Instance Method
Sources
Difference between Class and Instance methods
How do I assign a property to an instance in Python?
What's the difference between a Python "property" and "attribute"?
https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces
Diagram made in Creately
I'm not sure if one exists, but I'd suggest just "instance attribute".
Features about this naming:
It excludes methods. Methods are all callable class attributes, so this wording excludes all methods.
It includes callable instance attributes. Consider the following code:
class Container:
def __init__(self, item):
self.item = item
c = Container(x)
c.item # is an "instance attribute"
c.item == x # True
Note that c.item is an "instance attribute" regardless of whether or not it's callable. I think this is behaviour you're after, but I'm not sure.
It excludes non-callable class attributes, e.g.
class SomeClass:
x = 5 # Is not an "instance attribute"
It includes per-instance attributes, e.g.
obj.x = 5
obj.x # Is an "instance attribute"
In the end, all of these features may be positives or negatives depending on specifically what you want. But I don't know specifically what you want, and this is as close as I can get. If you can provide more information, I can give a better suggestion.

Difference between instance attributes and class attributes

I'm trying to learn about the instance and class attributes in python. Then am a little confused: is this_obj.var an instance attribute or it belongs to the class attribute. The code is below
class Myclass (object):
var = 10
this_obj = Myclass()
this_obj.somevar = 12
that_obj = Myclass()
that_obj.somevar = 12
Instance and class attributes can be kind of confusing to understand at first.
The best way of thinking about it is to pay attention to the name.
Instance attributes are owned by the specific instance of the class, meaning that these attributes can vary from instance to instance of a specific class.
On the other hand, Class attributes are owned by the class itself, so the attribute has the same value for each instance of a particular class.
In your example, var would be a class attribute to every instance of MyClass. However, once var is set to a different value for any given instance, say this_obj.var = 69, then this_obj.var is now an instance attribute to the this_obj instance. Meaning, instance attribute are created upon changing the class attribute of any instance.
Hope that helps!
EDIT: You can also change the class attribute value itself, meaning it'll change for all instances without an instance attribute for that specific variable. For example MyClass.var = 34 would change the value for all instances of MyClass that hasn't created an instance attribute yet.

Python Class Inheritance, __init__ and cls

The desired output of the code is that I have a class variable Team.stuff which has one entry holding the b instance, and the Player.stuff variable should be empty. Instead I get an error...
class Player:
stuff=[]
def __init__(self):
cls.stuff.append(self)
class Team(Player):
def __init__(self):
super(Team, self).__init__()
b=Team()
ERROR
cls.stuff.append(self)
NameError: global name 'cls' is not defined
I could pass the cls variable in the Team.__init__(), but I'm not sure if that is the "correct" way, and more importantly the Player.__init__() would need a class variable, and I'm not sure on the syntax on how to do that.
class Player(object):
stuff=[]
def __init__(self):
self.stuff.append(self)
class Team(Player):
def __init__(self):
super(Team, self).__init__()
b = Team()
print(Team.stuff)
prints (something like)
[<__main__.Team object at 0xb7519dec>]
Remember that cls is not a keyword in Python. Rather it is a convention for the first argument of a method when that method is supposed to be a class function and not one that is called on a particular instance of something.
If you want stuff to be an attribute of a function, you have to define it like so: self.stuff=[].
And then, when you refer to it in methods, do it with the self keyword as well: self.stuff.append(..).
The reason for this is that cls in your __init__ function is not defined. The argument names self and cls are just naming conventions. In reality, you could name them foo and bar for an instance and a class method respectively, and foo would point at the class instance whilst bar would point a the class itself.
Moreover, self.stuff would be valid as when searching for an attribute, if an object does not have an attribute of such name in it's __dict__ dictionary, the __dict__ of it's class is looked instead. If both are missing, further lookups are done according to mro order.
Notice that, once you set an attribute stuff on an object instance, it will shadow the class definition.
Explained by example:
class MyClassA(object):
stuff = []
class MyClassB(MyClassA):
def __init__(foobar):
# `foobar` points at the instance of `MyClassB` class.
# MyClassA.stuff gets `1` object appended to it.
foobar.stuff.append(1)
# This should print '[1]'
print foobar.stuff
# `MyClassB` object gets a _new_ attribute named `stuff` pointing at a list.
foobar.stuff = []
# This should print '[]'.
print foobar.stuff

difference between <class name>. <var name> and self.<var name> in a python class

I was wondering what was the difference between the Foo.var= user input and self.var= userinput in the 2 classes.
class foo():
var=None
def __init__(self,userinput):
foo.var=userinput
class bar():
var=None
def __init__(self,userinput):
self.var=userinput
foo refers to the class, self refers to the object.
Class members are a property of the class (and thus are shared between all objects of that class), while instance members are a property of the specific object, so a change to an instance member affects only the given object.
When you operate on an object, the members it has are a merge of the class members and the instance members. When two members with the same name are defined, the instance members have the priority.
Thus:
bar sets an instance variable; that change has effect only on the current instance, so if you do:
b=bar(10)
c=bar(20)
you'll see that c.var is 20 and b.var is 10; nothing strange here;
foo sets a class variable, which is common to all the instances; so, if you do:
f=foo(10)
g=foo(20)
you'll see that both f.var and g.var will be 20, because they both actually refer to foo.var, that was last set to 20 in g's constructor;
on the other hand, instance variables shadow class variables; so, if you do
f=foo(10)
g=foo(20)
f.var=30
you'll have g.var==foo.var==20, but f.var==30, since now f.var refers to the instance variable f.var; but, if you do
del f.var
now the instance (f's) attribute var no longer exists, and thus f.var refers again to the class attribute var (thus f.var==g.var==foo.var==20).
Long story short: normally you'll want to use self.var (i.e. instance members); classname.var is only for sharing stuff between all instances of a given class.
I'd like to point to an existing post which explains the difference perfectly in my opinion.
Python: Difference between class and instance attributes
Yes,
In the first instance you are setting the variable for all instances of foo this is because it is a class variable.
In the second case you are only setting the variable for that instance of foo.
For Example:
class pie():
def __init__(self, j):
pie.var = "pies" + str(j)
print (self.var)
def __str__(self):
return self.var
a = pie(1)
b = pie(2)
print (a)
print (b)

Categories

Resources