Difference between methods and member variables? - python

class Animal(object):
"""Makes cute animals."""
is_alive = True
health = 'good'
def __init__(self, name, age):
self.name = name
self.age = age
# Add your method here!
def description(self):
print self.name
print self.age
hippo = Animal('Tom', '20')
sloth = Animal('Randy', '18')
ocelot = Animal('Birdman','57')
hippo.description()
print ocelot.health
print hippo.health
print sloth.health
The code above is from codecademy's python course. I am getting confused about some of the definitions surrounding OOP. If my understanding is correct, a function defined within a class is known as a method, which is why when it's called, for example like this: 'hippo.description()', the '()' are necessary because of the syntax involving functions.
However, I start to get confused with 'self.name' and 'self.age'. Are these also methods? I was wondering if they were perhaps member variables, but then wouldn't they be defined in the same way the variable 'health' was above? And if they aren't member variables, how come they can be accessed using dot notation in the same way as the member variables?
Cheers

I assume you're coming from a more traditional OOP programming language like C++ or Java.
health in the Animal class is what you would refer to as a static member variable, but in Python this is called a class attribute because it is unique to the class.
name in the Animal class is what you would refer to as a member or instance variable, and in Python this is called an instance attribute because it is unique to each instance of a class.
You use self to refer to attributes within its own class.

First of all the difference between class and instance attributes are answered elsewhere.
The difference between a method and member variables are that while they are both attributes, a method is a function while a member variable is not (or need not be). Also a method is normally a class attribute (at least if you use new style classes).
However in python functions are first class objects so this may confuse a little more: it's perfectly valid to assign a member variable with a function (or vice versa), but then that will become somewhat different because normally a method is shared among all objects, but when assigned to an instance it becomes private to that instance.
self.foo may be used to access both instance attributes or class attributes (if instance attribute does not exist).

Related

How to change an instance variable in python using a method?

I'm very new to python and currently practicing OOP. One of the problems I'm facing is how to change an instance variable in python using a method.
My code:
class Monster:
def __init__ (self, name, health):
self.name = name
self.health = health
#classmethod
def change_name (self, given_name):
self.name = given_name
mon = Monster("Drake", 100)
print(mon.name)
mon.change_name("Derrick")
print(mon.name)
Output:
#Expected:
Drake
Derrick
#Actual:
Drake
Drake
Can someone tell me what the problem is and how I can solve it?
It happens because the change_name method is declared as a
classmethod
Which means its self parameter is not the object (instance of the class) but the class, in fact you should rename it to cls to make it clear.
Assigning tbe variable via the class creates it in the class' namespace, not in the object's.
But when looked up via the object, python looks for it in the object's namespace and if it cannot be found, it looks for it in the class' (and above in the superclasses' if not found yet)
Since you do not seem to need it , as the name attribute belongs to each monster instance, the solution is to make the method a plain instance one by removing the #classmethod decorator.

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

chaining of attributes in python

I am new to Python so it would be great if someone can find time to answer my query :
Fido = Dog()
I am able to understand
Fido.size = "tall"
Fido.sleeps()
But I am not sure what this means as given in the below link :
http://reeborg.ca/docs/oop_py_en/oop.html
Objects can also have other objects that belong to them, each with their own methods or attributes:
Fido.tail.wags()
Fido.tail.type = "bushy";
Fido.left_front_paw.moves()
Fido.head.mouth.teeth.canine.hurts()
Please help
Fido.tail.type is setting the type variable (attribute) inside the class' .tail() method to "bushy".
In classes, there are functions, which are called methods.
class Person:
def __init__(self, name):
self.name = name # Setting the name of the 'person'
def wave(self): # The methods which is called with George.wave()
print(self.name + ' waves at you.')
George = Person('George')
George.wave()
Will print "George waves at you."
To start with, everything is an object in Python. This SO question is a good place to start understanding what it means for something to be an object. What this means is that almost everything in Python has attributes and methods. E.g
the string
'foo'
is an object of the string class, and so, has methods and attributes that are shared across other strings such as its length.
In the Fido example, 'tail' is an object that belongs to Fido. This object has a 'type' and a method called 'wags'. Hence, we can say that 'wags' is a method of tail, which is an object found in Fido (which is an instance of the Dog class).

How to specify a variable as a member variables of a class or of an instance of the class?

in latest Python 2.7.x:
Given any member variable inside the definition of a class, is the member variable always at the class level in the sense that it is a single variable shared by all the instances of the class?
In the definition of a class, how can I specify
which member variables in the definition of a class belong to the class and thus shared by all the instances of the class, and
which belong to a particular instance of the class and not to another instance of the class?
How can I refer to a member variable of a class?
How can I refer to a member variable of an instance of a class?
Do the answers to the above questions appear somewhere in the official python language reference https://docs.python.org/2/reference/?
I can't find them there.
Thanks.
You might want to use the terminology "class variable" and "instance variable" here, as that's the usual language in python.
class Foo(object):
var1 = "I'm a class variable"
def __init__(self, var2):
self.var2 = var2 # var2 is an instance variable
The only scoping rule you really need to know in python is the lookup order for names - "LEGB", for Local, Enclosing, Global and Builtin.
The class scoped variable var1 still has to be looked up by "get attribute", you can only access that by Foo.var1 or self.var1. Of course, you can also access it elsewhere inside the class definition block, but that is just an example usage from the "Local" scope.
When you see self.var1, you can't immediately know whether it is an instance or a class variable (nor, in fact, if the name is bound to an object at all!). You only know that get attribute is tried on the object itself before it's tried on the class.
Indeed, an instance variable can shadow a class variable of the same name:
>>> f1 = Foo(var2='f1_2')
>>> f2 = Foo(var2='f2_2')
>>> f2.var1
"I'm a class variable"
>>> f2.var1 = "Boom!" # this shadows the class variable
>>> f1.var1, Foo.var1, f2.var1 # but: the class variable still exists
("I'm a class variable", "I'm a class variable", 'Boom!')
>>> del f2.var1 # restores the name resolution on the Foo object
>>> f2.var1
"I'm a class variable"
To complicate matters, we can write fancy code which makes class variables behave more like instance variables; a notable example are "fields" of an ORM. For example in Django, you may define an integer field on the model class - however when you lookup that name on an instance of the model, you get an actual integer returned (not an IntegerField object).
If you're interested in this advanced usage of attribute access, read up on the descriptor protocol. For mundane classes you can safely ignore those details, but it's worth knowing that the usual resolution of instance variables and then class variables has lower precedence than any descriptors that may have been defined on the class.

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