Best way to access class member in a class in Python - python

I want to know which one is the best way to access the class variable in a class, either by self, or by class name
I have read somewhere that self is only used for accessing the instance variable. But when I tried with the below code, it is one of the same things. Is is it mean that we can use either of them?
class MyClass:
cls_var = 0 # class variable
def increment(self, incre):
self.cls_var += incre
MyClass.cls_var += incre
def print_var(self):
print(self.cls_var) #Choice 1
print(MyClass.cls_var) # Choice 2
obj1 = MyClass()
obj2 = MyClass()
obj1.increment(5)
obj2.increment(10)
obj1.print_var() #prints 5, 15
obj2.print_var() # prints 15, 15

You should access a class variable only by class name, since that variable is shared among all classes. Thus, to avoid confusion, one should only access class variables by the name of the class; otherwise it might lead to surprising errors (See the second snippet).

In my opinion you should use "Choice 2", as the class variable "cls_var" is shared by all instances. So if you do
ob1.increment(5)
also "ob2.cls_var" gets incremented, but Zen of Python sais that explicit is better than implicit! So do
MyClass.increment(5)
See: https://docs.python.org/2/tutorial/classes.html#class-and-instance-variables.

Related

What is variable shadowing?

This Stack Overflow answer states that for the program:
class Parent(object):
i = 5;
def __init__(self):
self.i = 5
def doStuff(self):
print(self.i)
class Child(Parent, object):
def __init__(self):
super(Child, self).__init__()
self.i = 7
class Main():
def main(self):
m = Child()
print(m.i) #print 7
m.doStuff() #print 7
m = Main()
m.main()
Output will be:
$ python Main.py
7
7
That answer then compares it to a similar program in Java:
The reason is because Java's int i declaration in Child class makes the i become class scope variable, while no such variable shadowing in Python subclassing. If you remove int i in Child class of Java, it will print 7 and 7 too.
What does variable shadowing mean in this case?
What does variable shadowing mean in this case?
Variable shadowing means the same thing in all cases, independent of context. It's defined as when a variable "hides" another variable with the same name. So, when variable shadowing occurs, there are two or more variables with the same name, and their definitions are dependent on their scope (meaning their values may be different depending upon scope). Quick example:
In [11]: def shadowing():
...: x = 1
...: def inner():
...: x = 2
...: print(x)
...: inner()
...: print(x)
...:
In [12]: shadowing()
2
1
Note that we call inner() first, which assigns x to be 2, and prints 2 as such. But this does not modify the x at the outer scope (i.e. the first x), since the x in inner is shadowing the first x. So, after we call inner(), and the call returns, now the first x is back in scope, and so the last print outputs 1.
In this particular example, the original author you've quoted is saying that shadowing is not occurring (and to be clear: not occurring at the instance level). You'll note that i in the parent takes on the same value as i in the child. If shadowing occurred, they would have different values, like in the example above (i.e. the parent would have a copy of a variable i and the child would have a different copy of a variable also named i). However, they do not. i is 7 in both the parent and child. The original author is noting that Python's inheritance mechanism is different than Java's in this respect.
Variable shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope. Then the variable in the scope that you are in shadows (hides/masks) the variable in the outer scope.
In the above code the variable i is being initialized in both the super class and the child class. So the initialization in the super class will be shadowed by the initialization in the child and class.
m = Child() #we initialized the child class with i=7
print(m.i) #eventhough we are calling a method in the super class the value of i in the super class is shadowed by the value we initialized the instance of the child class (m)
m.doStuff() #same thing here
In Java, methods and fields are fundamentally different things, operating by entirely different rules. Only methods are inherited by subclasses; fields are specific to the class that declared them. If a subclass declares a field with the same name as one in a parent class, they are entirely unrelated; methods of the parent class continue to access the parent's version, and methods of the child class access its version. This is what is referred to as shadowing. If the parent class actually wanted to make its field available to children, it would have to define getter/setter methods for it.
In Python, there is no such distinction - methods are basically fields whose value happens to be a function. Furthermore, all of the fields from the entire inheritance hierarchy are stored in a single namespace (typically implemented as a dict attribute named __dict__). If the child and parent use the same name for something, they are necessarily referring to the same object.

Access Class method and variable using self

In below example Test class has two instance method and one classmethod
In set_cls_var_1 method I set class variable using self.
In set_cls_var_2 method I call class method using self.
class Test():
#class variable
cls_var = 10
def __init__(self):
obj_var=20
def set_cls_var_1(self,val):
#second method to access class variable
print "first "
self.cls_var = val
def set_cls_var_2(self):
print "second"
self.task(200)
#classmethod
def task(cls,val):
cls.cls_var = val
t=Test()
#set class variable by first method
t.set_cls_var_1(100)
print Test.cls_var
#set class variable by second method
t.set_cls_var_2()
print Test.cls_var
Output
first
10
second
200
Expected Output
first
100
second
200
My question is:
why only classmethod can call by self, Why not class variable
When you attempt to access an object's attribute using self, Python first searches the object's attributes. If it cannot find it there, then is searches the object's class's attributes. That is what's happening in your case;
Python first searches t's attributes. It doesn't find cls_var, so it then searches the T class's attributes. It finds cls_var so it stops, and returns cls_var's value.
However, when assigning attributes to self, Python always assigns them directly to the object, and never the object's class unless explicitly told to do so. That's why assinging self.cls_var to 100 didn't affect Test's cls_var attrbiute.
I find something else that always use following way to access classmethod or variable in instance method
class Test():
#class variable
cls_var = 10
def __init__(self):
obj_var=20
def set_cls_var_1(self,val):
#first method to access class variable
print "first type"
cls = self.__class__
cls.cls_var = val
t=Test()
#set class variable by first method
t.set_cls_var_1(100)
print Test.cls_var
When defining the Test class like you did, python creates a class object called Test which has an attribute cls_var equal to 10. When you instantiate this class, the created object doesn't have cls_var attribute. When calling self.cls_var it is actually the class' attribute that is retrieved due to the way python resolves attributes.
However when set self.cls_var the value is set at the object level! So further call to self.cls_var will give you the value of the object's attribute, and not the class' anymore!
Maybe this bit of code will make this clearer:
class A(object):
a = 1
a = A()
print a.a # prints 1
A.a = 2
print a.a # prints 2
You see that even though when set the value at the class level, the changes are repercuted on the object, because, python will look up for the attribute in the class when it is not found at the object level.
When calling Test.cls_var it is the cls_var attribute of the class you are accessing! Not the one of the object you just modified.

Python inheritance: when and why __init__

I'm a Python newbie, trying to understand the philosophy/logic behind the inheritance methods. Questions ultimately regards why and when one has to use the __init__ method in a subclass. Example:
It seems a subclass inheriting from a superclass need not have its own constructor (__init__) method. Below, a dog inherits the attributes (name, age) and methods (makenoise) of a mammal. You can even add a method (do_a_trick) Everything works as it ``should", it seems.
However, if I wanted to add a new attribute in the subclass as I attempt to do in the Cats class, I get an error saying "self" is not defined. Yet I used "self" in the definition of the dog class. What's the nature of the difference?
It seems to define Cats as I wish I need to use __init__(self,name) and super()__init__(name). Why the difference?
class Mammals(object):
def __init__(self,name):
self.name = name
print("I am a new-born "+ self.name)
self.age = 0
def makenoise(self):
print(self.name + " says Hello")
class Dogs(Mammals):
def do_a_trick(self):
print(self.name + " can roll over")
class Cats(Mammals):
self.furry = "True" #results in error `self' is not defined
mymammal = Mammals("zebra") #output "I am a new-born zebra"
mymammal.makenoise() #output "zebra says hello"
print(mymmmal.age) #output 0
mydog = Dogs("family pet") #output "I am a new-born family pet"
mydog.makenoise() #output "family pet says hello"
print(mydog.age) # output 0
mydog.do_a_trick() #output "family pet can roll over"
Explicit is better than implicit.
However, you can do below:
class Dogs(Mammals):
def __init__(self):
#add new attribute
self.someattribute = 'value'
Mammals.__init__(self)
or
class Dogs(Mammals):
def __init__(self):
#add new attribute
self.someattribute = 'value'
super(Mammals, self).__init__()
if I wanted to add a new attribute in the subclass as I attempt to do
in the Cats class, I get an error saying "self" is not defined. Yet I
used "self" in the definition of the dog class.
In your superclass, Mammal, you have an __init__ function, which takes an argument that you've chosen* to call self. This argument is in scope when you're in the body of the __init__ function - it's a local variable like any local variable, and it's not possible to refer to it after its containing function terminates.
The function defined on the Dog class, do_a_trick, also takes an argument called self, and it is also local to that function.
What makes these variables special is not their name (you could call them anything you wanted) but the fact that, as the first arguments to instance methods in python, they get a reference to the object on which they're called as their value. (Read that last sentence again a few times, it's the key to understanding this, and you probably won't get it the first time.)
Now, in Cat, you have a line of code which is not in a function at all. Nothing is in scope at this point, including self, which is why this fails. If you were to define a function in Cat that took an argument called self, it would be possible to refer to that argument. If that argument happened to be the first argument to an instance method on Cat, then it would have the value of the instance of Cat on which it had been called. Otherwise, it would have whatever got passed to it.
*you have chosen wisely!
Declarations at the top level of a Python class become class attributes. If you come from a C++ or Java background, this is similar to declaring a static member variable. You cannot assign instance attributes at that level.
The variable self usually refers to a specific instance of a class, the one from which the method has been called. When a method call is made using the syntax inst.method(), the first argument to the function is the object inst on which the method was called. In your case, and usually by convention, that argument is named self within the function body of methods. You can think of self as only being a valid identifier within method bodies then. Your assignment self.furry = True does not take place in a method, so self isn't defined there.
You have basically two options for achieving what you want. The first is to properly define furry as an attribute of the cat class:
class Cat(Mammals):
furry = True
# Rest of Cat implementation ...
or you can set the value of an instance variable furry in the cat constructor:
class Cat(Mammals):
def __init__(self):
super(Mammals, self).__init__(self)
self.furry = True
# Rest of Cat implementation ...
If you're getting into Python I highly recommend to read these two parts of the Python documentation:
Python classes
Python data model special methods (more advanced)
As pointed out in the other answers, the self that you see in the other
functions is actually a parameter. By Python convention, the first parameter in
an instance method is always self.
The class Cats inherits the __init__ function from its base class,
Mammals. You can override __init__, and you can call or not call the base
class implementation.
In case the Cats __init__ wants to call the base implementation, but doesn't want to care about the parameters, you can use Python variable arguments. This is shown in the following code.
Class declaration:
class Cats(Mammals):
def __init__(self, *args):
super().__init__(*args)
self.furry = "True"
See, for example, this Stack Overflow question for something about the star
notation for variable numbers of arguments:
Can a variable number of arguments be passed to a function?
Additional test code:
cat = Cats("cat")
print(vars(cat))
Output:
I am a new-born cat
{'name': 'cat', 'age': 0, 'furry': 'True'}
You can do something like in Chankey's answer by initiating all the variables in the constructor method ie __init__
However you can also do something like this
class Cats(Mammals):
furry = "True"
And then
cat = Cats("Tom")
cat.furry # Returns "True"
The reason you can't use self outside the functions is because self is used explicitly only for instances of the class. If you used it outside, it would lead to ambiguity. If my answer isn't clear please let me know in comments.
The __init__ method runs once on the creation of an instance of a class. So if you want to set an attribute on an instance when it's created, that's where you do it. self is a special keyword that is passed as the first argument to every method, and it refers to the instance itself. __init__ is no different from other methods in this regard.
"What's the nature of the difference": you define the method Dog.do_a_trick, and you receive self as an argument to the method as usual. But in Cat you've unintentionally (perhaps subconsciously!) attempted to work on the class scope -- this is how you'd set a class attribute whose value is identical for all cats:
class Cat(object):
sound = "meow"
It's different so you can have both options available. Sometimes (not all the time, but once in a while) a class attribute is a useful thing to have. All cats have the same sound. But much of the time you'll work with instance attributes -- different cats have different names; when you need that, use __init__.
Suppose you have a class named Person which has a method named get_name defined as :
class Person():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def get_name(self):
return self.first_name + ' ' + self.last_name
And, you create an instance of Person as p1. Now when you call the function get_name() with this instance, it will converts internally
Person.get_name(p1)
So, self is the instance itself.
Without self you can write above code as :
class Person():
first_name = None
last_name = None
def get_name(personobject):
return personobject.first_name + ' ' + personobject.last_name
What I am trying to say is the name self is a convention only.
And for inheritance, if you would like to have extra attributes in your subclass, you need to initiate your super class first and add your parameter as you wanted.
For example, if you want to create a subclass from Person named Boy with new attribute height, the you can define it as:
class Boy(Person):
def __init__(self, first_name, last_name, height):
super(Person, self).__init__(first_name, last_name)
self.height = height

Can I access a class variable using object of that class

I have two very basic object oriented question
1) Can we modify a class variable with member function?
For example
class test:
'''test class'''
idd=0
def __init__(self,mark,subject):
self.markk=mark
self.subjectt=subject
def display(self):
print "the display is",self.markk,self.subjectt;
stud1=test(30,'maths')
stud2=test(40,'english')
when i tried to modify class variable idd using the object stud1.idd=9;, the variable didnt modified. test.idd=9 modified the variable.
Can someone explain me why it is not possible to modify a class vars from a object?
2) Also in the above snippet, when I added a keyword global with the class var idd like
class test:
'''test class'''
global idd;
idd=0;
print test.idd
it threw error like name class test don't have attribute idd.
But when I commented out the global idd, it displayed value.
So is global keyword not supported in class?
can someone help me to get some idea on these two question as this is my basic step to object oriented concept..
I think that you're not understanding that python looks up values by looking at a "chain" of objects1. When you do value = self.foo, python will first look for foo on the instance. Then it will look on the class. Then it will look on the super-classes (in their "Method Resolution Order").
When you write:
self.foo = 'bar'
Python simply puts a foo on the instance. So now subsequent lookups on that instance will give you 'bar' even if foo is also defined on the class. Also note that since foo gets put on the instance, no changes are visible on the class.
If you want to update the class in a particular method, you might be able to use a classmethod:
class Foo(object):
idd = 0
#classmethod
def increment_idd(cls):
cls.idd += 1
f = Foo()
f.increment_idd()
print(Foo.idd)
print(f.idd)
This doesn't work if you need access to self however. In that case, you'll need to get a reference to the class from the instance:
class Foo(object):
idd = 0
def increment_idd(self):
cls = type(self)
cls.idd += 1
f = Foo()
f.increment_idd()
print(Foo.idd)
print(f.idd)
1If you know javascript, it's actually not too much different than javascript's prototypical inheritance
As long as it is a public variable you should be able to.

Classes in python, how to set an attributes

When I write class in python, most of the time, I am eager to set variables I use, as properties of the object. Is there any rule or general guidelines about which variables should be used as class/instance attribute and which should not?
for example:
class simple(object):
def __init(self):
a=2
b=3
return a*b
class simple(object):
def __init(self):
self.a=2
self.b=3
return a*b
While I completely understand the attributes should be a property of the object. This is simple to understand when the class declaration is simple but as the program goes longer and longer and there are many places where the data exchange between various modules should be done, I get confused on where I should use a/b or self.a/self.b. Is there any guidelines for this?
Where you use self.a you are creating a property, so this can be accessed from outside the class and persists beyond that function. These should be used for storing data about the object.
Where you use a it is a local variable, and only lasts while in the scope of that function, so should be used where you are only using it within the function (as in this case).
Note that __init is misleading, as it looks like __init__ - but isn't the constructor. If you intended them to be the constructor, then it makes no sense to return a value (as the new object is what is returned).
class Person(object):
def __init__(self, name):
# Introduce all instance variables on __init__
self.name = name
self.another = None
def get_name(self):
# get_name has access to the `instance` variable 'name'
return self.name
So if you want a variable to be available on more than one method, make
it an instance variable.
Notice my comment on introducing all instance vars on __init__.
Although the example below is valid python don't do it.
class Person(object):
def __init__(self):
self.a = 0
def foo(self):
self.b = 1 # Whoa, introduced new instance variable
Instead initialize all your instance variables on __init__ and set
them to None if no other value is appropriate for them.
I try to imagine what I want the API of my class to look like prior to implementing it. I think to myself, If I didn't write this class, would I want to read the documentation about what this particular variable does? If reading that documentation would simply waste my time, then it should probably be a local variable.
Occasionally, you need to preserve some information, but you wouldn't necessarily want that to be part of the API, which is when you use the convention of appending an underscore. e.g. self._some_data_that_is_not_part_of_the_api.
The self parameter refers to the object itself. So if you need to use on of the class attributes outside of the class you would it call it as the name of class instance and the attribute name. I don't think there is any guideline on when to use self, it all depends on your need. When you are building a class you should try to think about what you will use the variables you creating for. If you know for sure that you will need that specific attribute in the program you are importing your class, then add self.

Categories