Python Class Script Running Errors? - python

I am trying to make a class using Python 2.7.9 and it keeps running into errors.
Here is my script:
class Hero():
def __init__(self, name):
self.health=50
def eat(self, food):
if(food=='apple'):
self.health+=10
self.name=Jeff
Jeff=Hero('Jeff')
def introduce(self, name):
print Jeff.name
def checkAtt():
print Jeff.health
introduce()
It keeps saying name 'Jeff' is not defined.

Your code has numerous problems. The first, that is causing the specific error, is that you attempt to assign:
self.name = Jeff
before you have defined either self or Jeff. self is conventionally only used inside instance methods (like your Hero.eat), where it is the name of the first parameter.
Secondly, your Hero.__init__ doesn't actually assign the name parameter to the name attribute; it should look like:
class Hero(object): # Note inheritance from 'object' for new-style class
def __init__(self, name):
self.name = name # Note assignment of instance attribute
self.health = 50
...
jeff = Hero("Jeff") will call Hero.__init__, creating new Hero instance, setting its name attribute to "Jeff" (and health attribute to 50) and assigning that instance to the name jeff.
Thirdly, you have two standalone functions (introduce and checkAtt) that should probably also be instance methods:
def Hero(object):
...
def introduce(self):
print self.name
...
jeff = Hero("Jeff")
jeff.introduce() # equivalent to 'Hero.introduce(jeff)'
or, if remaining as standalone functions, take a single parameter, the Hero instance to operate on (which should not be called self, again by convention) - there is not much point writing a function that only works if it's run in a scope where the name Jeff is available!
class Hero(object):
...
def introduce(hero):
print hero.name
jeff = Hero("Jeff")
introduce(jeff)
Note the indentation in these two different cases - it is very important in Python. Also, note the different ways of calling introduce depending on whether it's an instance method or a function.
I suggest you read the tutorial on classes and the style guide.

Related

When to use self and when not to use self

Which class option is preferable and why?
Option 1
class Person():
def __init__(self):
pass
def sayHello(self, name):
print "{} says hello!".format(name)
def driver(self):
for name in names: # names is generated in the driver function by some means of input
self.sayHello(name)
Option 2
class Person():
def __init__(self):
self.name = None
def sayHello(self):
print "{} says hello!".format(self.name)
def driver(self):
for name in names: # names is generated in the driver function by some means of input
self.name = name
self.sayHello()
You can assume that there are more variables than just name and that multiple functions are using these variables. The main point I am trying to make is that the variable value's are changing inside the for loop
Even though your exemple is syntaxically correct, it doesn't help at all understand your question regarding how to use a instance attribute.
From want I'm guessing, there's two questions :
When to use a class method (def foo(self, bar)) ?
When to use a instance attribute (self.name) ?
Instance attribute should be used when you need to "share" a variable between functions or retrieve it from outside a function. That variable will be "attached" to the object (for exemple, the color of a car, the nickname of a user, ...)
If your function / method need to call this kind of variable, it must use self to get it, so you have to set it as the first argument when defining this function.
If you just need a temporary variable to loop over it and do some stuff, you don't need to use a class method, a simple function will do the trick.

How is the usage of #classmethod causing difference in outputs?

I was learning about classes and objects in Python when I came across this dilemma. Below are two cases of the same code, one without #classmethod and the other with #classmethod:
#without #classmethod
>>> class Human:
... name = "Rounak"
... def change_name(self, new_name):
... self.name=new_name
...
>>> Human().change_name("Agarwal")
>>> print(Human().name)
Rounak
#with #classmethod
>>> class Human:
... name = "Rounak"
... #classmethod
... def change_name(self, new_name):
... self.name=new_name
...
>>> Human().change_name("Agarwal")
>>> print(Human().name)
Agarwal
As you can see that when not using #classmethod, the name doesn't change from Rounak to Agarwal. I don't seem to understand how.
I went through the definition of #classmethod in the Python documentation and also went through various questions on Stack Overflow that have detailed explanation about the usage of #classmethod but I still don't understand how it is causing this difference in output. I am new to Python, so if I am missing some fundamental knowledge, please let me know.
Using the classmethod changes the name in the class namespace Human.__dict__, which is different from the instance's namespace Human().__dict__. Class methods are usually implemented using a different variable name than self as the first argument, for this reason:
class Human:
name = "Rounak"
#classmethod
def change_name(cls, new_name):
cls.name = new_name
Note that you are calling Human() again within the print call. Every time you call Human() you are creating a new instance, which has its own namespace!
Every time you call Human(), you create a new object. If you were to re-use the first object in the print() statement, you'd see the instance attribute was indeed set to Agarwal.
The call to the classmethod persists across all subsequently created instances, because it's modifying the class attribute.
Well, since you are using:
class Human:
... name = "Rounak"
...
name is a class attribute, without the #classmethod you modify the self, so the instance of the class. Your problem here is that in your function:
#classmethod
def change_name(self, new_name):
self.name=new_name
You are using self as the variable name, but under the hood python is not passing the instance of a class but the class itself, that is why usually it is written as:
#classmethod
def change_name(cls, new_name):
cls.name=new_name
Resume:
Normal version modifies class instance
classmethod version modifies class itself

Difference between methods and attributes in python

I am learning python and doing an exercise about classes. It tells me to add an attribute to my class and a method to my class. I always thought these were the same thing until I read the exercise. What is the difference between the two?
Terminology
Mental model:
A variable stored in an instance or class is called an attribute.
A function stored in an instance or class is called a method.
According to Python's glossary:
attribute: A value associated with an object which is referenced by
name using dotted expressions. For example, if an object o has an
attribute a it would be referenced as o.a
method: A function which is defined inside a class body. If called as an attribute of an instance of that class, the method will get the instance object as its first argument (which is usually called self). See function and nested scope.
Examples
Terminology applied to actual code:
a = 10 # variable
def f(b): # function
return b ** 2
class C:
c = 20 # class attribute
def __init__(self, d): # "dunder" method
self.d = d # instance attribute
def show(self): # method
print(self.c, self.d)
e = C(30)
e.g = 40 # another instance attribute
A method is an attribute, but not all attributes are methods. For example, if we have the class
class MyClass(object):
class_name = 'My Class'
def my_method(self):
print('Hello World!')
This class has two attributes, class_name and my_method. But only my_method is a method. Methods are functions that belong to your object. There are additional hidden attributes present on all classes, but this is what your exercise is likely talking about.
A quick,simplified explanation.
Attribute == characteristics.
Method == operations/ actions.
For example, Let's describe a cat (meow!).
What are the attributes(characteristics) of a cat?
It has different breed, name, color, whether they have spots...etc.
What are methods (actions) of a cat?
It can meow, climb, scratch you, destroy your laptop, etc.
Notice the difference, attributes define characteristics of the cat.
Methods, on the other hand, defines action/operation (verb).
Now, putting the above definition in mind, let's create an object of class 'cat'...meowww
class Cat():
To create attributes, use def init(self, arg1, arg2) - (as shown below).
The 'self' keyword is a reference to a particular instance of a class.
def __init__(self, mybreed, name):
# Attributes
self.breed = mybreed
self.name = name
# Operations/actions --> methods
def kill_mouse(self):
print('Insert some method to kill mouse here')
Notice (above) 'mybreed' is an input argument that the user need to specify, whereas self.breed is an attribute of the instance assigned to 'mybreed' argument. Usually, they're the same (e.g. breed for both, self.breed = breed). Here, it's coded differently to avoid confusion.
And attributes are usually written as 'self.attribute_name' (as shown above).
Now, methods are more like actions, or operations, where you define a function inside the body of a class to perform some operation, for example, killing a mouse. A method could also utilize the attributes that you defined within the object itself.
Another key difference between a method and attribute is how you call it.
For example, let's say we create an instance using the above class we defined.
my_cat = Cat()
To call an attribute, you use
my_cat.name
or
my_cat.breed
For methods, you call it to execute some action. In Python, you call method with an open and close parenthesis, as shown below:
my_cat.kill_mouse()
A method is a function defined in the class. An attribute is an instance variable defined in the class.
Example:
class Example(object):
def __init__(self, name):
self.name = name
def hello(self):
print 'Hi, I am ' + self.name
Here hello is a method, and name is an attribute.
class example:
global a
# a=0
def __init__(self,x,y):
self.fname=x
self.lname=y
def show(self):
return "first name: {} & Last name: {}".format(self.fname,self.lname)
obj1=example('reyan','ishtiaq')
obj2=example('ishtiaq','reyan')
print('method associated with obj1: '+ obj1.show())
print('method associated with obj2: '+ obj2.show())
obj1.a=20
obj2.a=30
print(obj1.a)
print(obj2.a)
output:
method associated with obj1: first name: reyan & Last name: ishtiaq................
method associated with obj2: first name: ishtiaq & Last name: reyan................
20
30
#Below u can see that I made a class called "example" with two class attributes:
variable1 and variable2.
class example():
def init(self, variable1, variable2):
self.variable1 = variable1
self.variable2 = variable1
i did not construct a method inside this class. Notice that variable1 comes first and after comes variable2 inside the init():
#below i created an object "object1" with the example class. I created the example class with two arguments "variable1" and "variable2". "self" does not count), so i have to pass two arguments when calling the example class. I gave two variables "10" and "20".
object1 = example(10,20)
with the code below i just get the value of the first argument, which is 10.
print(object1.variable1)

How to access "__" (double underscore) variables in methods added to a class

Background
I wish to use a meta class in order to add helper methods based on the original class. If the method I wish to add uses self.__attributeName I get an AttributeError (because of name mangling) but for an existing identical method this isn't a problem.
Code example
Here is a simplified example
# Function to be added as a method of Test
def newfunction2(self):
"""Function identical to newfunction"""
print self.mouse
print self._dog
print self.__cat
class MetaTest(type):
"""Metaclass to process the original class and
add new methods based on the original class
"""
def __new__(meta, name, base, dct):
newclass = super(MetaTest, meta).__new__(
meta, name, base, dct
)
# Condition for adding newfunction2
if "newfunction" in dct:
print "Found newfunction!"
print "Add newfunction2!"
setattr(newclass, "newfunction2", newfunction2)
return newclass
# Class to be modified by MetaTest
class Test(object):
__metaclass__ = MetaTest
def __init__(self):
self.__cat = "cat"
self._dog = "dog"
self.mouse = "mouse"
def newfunction(self):
"""Function identical to newfunction2"""
print self.mouse
print self._dog
print self.__cat
T = Test()
T.newfunction()
T.newfunction2() # AttributeError: 'Test' object has no attribute '__cat'
Question
Is there a way of adding newfunction2 that could use self.__cat?
(Without renaming self.__cat to self._cat.)
And maybe something more fundamental, why isn't self.__cat being treated in the same way for both cases since newfunction2 is now part of Test?
Name mangling happens when the methods in a class are compiled. Attribute names like __foo are turned in to _ClassName__foo, where ClassName is the name of the class the method is defined in. Note that you can use name mangling for attributes of other objects!
In your code, the name mangling in newfunction2 doesn't work because when the function is compiled, it's not part of the class. Thus the lookups of __cat don't get turned into __Test_cat the way they did in Test.__init__. You could explicitly look up the mangled version of the attribute name if you want, but it sounds like you want newfunction2 to be generic, and able to be added to multiple classes. Unfortunately, that doesn't work with name mangling.
Indeed, preventing code not defined in your class from accessing your attributes is the whole reason to use name mangling. Usually it's only worth bothering with if you're writing a proxy or mixin type and you don't want your internal-use attributes to collide with the attributes of the class you're proxying or mixing in with (which you won't know in advance).
To answer both of your questions:
You will need to change self.__cat when you need to call it from newfunction2 to self._Test__cat thanks to the name mangling rule.
Python documentation:
This mangling is done without regard to the syntactic position of the
identifier, as long as it occurs within the definition of a class.
Let me brake it down for you, it's saying that it doesn't matter where your interpreter is reading when it encounters a name mangled name. The name will only be mangled if it occurs in the definition of a class, which in your case, it's not. Since it's not directly "under" a class definition. So when it reads self.__cat, it's keeping it at self.__cat, not going to textually replace it with self._Test__cat since it isn't defined inside theTest class.
You can use <Test instance>._Test__cat to access the __cat attribute from the Test class. (where <Test instance> is replaced by self or any other instance of the Test class)
learn more in the Python doc
class B:
def __init__(self):
self.__private = 0
def __private_method(self):
'''A private method via inheritance'''
return ('{!r}'.format(self))
def internal_method(self):
return ('{!s}'.format(self))
class C(B):
def __init__(self):
super().__init__()
self.__private = 1
def __private_method(self):
return 'Am from class C'
c = C()
print(c.__dict__)
b = B()
print(b.__dict__)
print(b._B__private)
print(c._C__private_method())

use of self argument

I am a newcomer to Python. I don't understand how/why the self argument is used:
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print 'Hello, my name is', self.name
p = Person('Swaroop')
p.sayHi()
This code is from a Byte of Python. This code could have just as easily been written as:
def sayHi(self, name):
print 'Hello, my name is', name
p = Person('Swaroop')
p.sayHi()
...right? What is the purpose of making name a field of self?
It seems you are oversimplifying a not so simple thing.
In object-oriented programming, a Class is a Declarative Construct which gives a blueprint as to what an object (a manifestation of this blueprint) would contain (properties) and how it would behave (members).
Every manifestation of such a Class is called an Object which has a defined and specific instance. From an object via any of this behavioral attributes called member functions/methods we need somehow to refer to that instance of the object and remember individual elements within it and make a clear distinction with the other non member entities.
Consider Your example
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print 'Hello, my name is', self.name
Every Instance of this Person (Tom, Dick, Harry) is unique and within each instance, to refer back to itself we need some idiom like (self in Python, this ptr is C++ or this in Java).
So in the __init__ method when you need to demarcate between the name attribute of Person with the name parameter we can easily do so with self. Not only that, at any instance we can keep on referring back to this name via the self.
Making an instance of Person p=Person('Swaroop') and then invoking sayHi contrasting to calling just a function sayHi which is not a part of an object has two implications
The Function is transient, has no state, no instance and its like Saying this Guy "Hey Mr. who ever you are say 'Hello, my name is Swaroop'". It's like on every run you have to make an imbecile make aware of his name who will forget the next moment you will meet him. It's like this Guy is suffering from Anterograde_amnesia. Calling sayHi of the instance of Person named Swaroop on the other hand would mean something like a physically existing Swaroop greeting back his Name who has a persistent memory and would never forget unless he adopts a new name.
The Function never remembers but forgets every time the call ends. The Person object will remember the name until you explicitly or implicitly Kill That Person.
If you have a background of C++ and might be wondering why on earth do we need to add that extra parameter to the function call where as in C++ this pointer is never passed.
Well Candidly speaking it does. If you read the C++ calling convention, whether X86 or X64, the this pointer is passed through the register ecx to the method to give an handle to itself. This is more explicit here where we deliberately pass the handle to the current instance to the method.
Have a look at the new method sayHiTo:
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print 'Hello, my name is', self.name
def sayHiTo(self, other):
print 'Hello', other.name, ' my name is', self.name
p1 = Person('Swaroop')
p2 = Person('codeninja')
p1.sayHiTo(p2)
p2.sayHiTo(p1)
Actually no. Your second example is not correct.
The 'self' keyword is a special reference that is passed to instance methods of a class. It represents the actual instance of the class at that scope. When you make a class it is just a general definition. Then you create instances of that class. Each instance is unique and thus the methods have to be able to work on that instance. You have no way of knowing them until they are made so 'self' passes them in for you.
For instance, if you created two instances of your person class:
p1 = Person("john")
p2 = Person("sam")
self.name value is different for each of those. And when you call sayHi() on each instance:
p1.sayHi()
> Hello, my name is john
p2. sayHi()
> Hello, my name is sam
You would not use the self keyword for unbound functions. That is, just general functions like what you have written as your second example. You would instead have to write it like this;
def sayHi(name):
print 'Hello, my name is', name
p = Person('Swaroop')
p.sayHi()
> sayHi("john")
But that would basically just pass a name string to a Person class and call its method. The idea here is that you create unique instances of Person with their own properties.
The purpose is to store the reference to the name so you can reference it in another method of the class e.g. def sayHi (self)
You can't compare a function in a class to just a function. Sure you can pass in name, but the idea of using a class is that you are encapsulating data. Having vars linked to self means you can pass around an object, and that object can always have access to its 'member variables'. Some other class can use an instance of Person and not need to know that persons name in order to say hi.

Categories

Resources