I'm trying to learn about the basic construction of the python class. I have the following code which is completely running fine:
class Test1:
name = 'Choton'
age = 28
class Test2: # __init__ function executes whenever the class is called
def __init__(self):
self.name = 'Choton'
self.age = 28
print('Class Test2 is called and initialized...')
def main():
# Test1
print(f'Test1:')
print(f'Test1().name = {Test1().name}, Test1().age = {Test1().age}')
print(f'Test1.name = {Test1.name}, Test1.age = {Test1.age}\n')
# Test2
print(f'Test2:')
print(f'Test2().name = {Test2().name}, Test2().age = {Test2().age}')
# DOES NOT WORK
# print(f' name = {Test2.name}, age = {Test2.age}')
if __name__ == '__main__':
main()
I know that the __init__ function always runs whenever a class is initialized. Here the Test1 class do not have any __init__ function and both Test1.name and Test1().name works fine. But whenever I am calling the name using the __init__ function in Test2, the Test2.name does not work anymore. It says the following error if I uncomment that line: AttributeError: type object 'Test2' has no attribute 'name'.
What is the difference in here? Why both syntax work for one class and not for the other? I am a bit confused about it. Is there any syntactic sugar in here or any generalization that I am missing?
In Test1 you are defining class variables, which are shared between all objects, and can be accessed by using the class only (Test1.name) as well as from the instance (Test1().name).
Defining self.name in Test2.__init__ makes it an instance variable, which is only available on a specific instance of the class, e.g. new object created by Test2()
Took me a long time to get my head around classes, I'm still not there. The init function isn't needed in every class, one thing it's used for is to allocate different values to the class attributes.
For info,
Test1 is the class.
Test1() is an instance of the class.
Both can be assigned. So you could say:
MyClassInstanceA = Test1()
MyClassInstanceB = Test1()
... These two are different items because they are both instances of the Test1 class, each instance is unique.
Or you could say
MyClassA = Test1
MyClassB = Test1
... These two are the same thing as they are both allocated Test1, not Test1()....
name and age are attributes. In the case of Test1 they are "class attributes". That is, the exist at the class level. They can be accessed via the class or an instance of the class. Remember Test1 is the class Test1() is an instance of the class.
The subtle difference between Test1() and Test1 is what is causing the error.
To further explain. In the Test1 class, the two attributes name and age exist in the class, before we create an instance of the class. If we do create any instances name and age attributes will be the same across all instances. But the important thing here is we don't have to create an instance of the class to access them. That's why Test1.name works....
On the other hand, in Test2 class. The attributes are only created when the class is initiated (this is what the init function is doing). They don't exist until then. So, when we want to access them you need to access them via an instance of the class Test2().name....
MyClassC = Test2
... Still no instance of the class so name or age doesn't exist
MyClassInstanceD = Test2()
... Now we have an instance of the class so name and age exists and it is accessed via that class which is called MyClassInstanceD...
MyClassInstanceD.name = 'Choton'
But as name and age only exist in the instance we can still not call
Test2.name
as this still doesn't exist and never will unless you modify the Test2 class...
Related
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.
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)
I have two Python files:
"testclass.py":
class TestClass:
Result = 0
def __init__(self):
self.Result = 1
return
Manager = TestClass()
and "hostapp.py":
import testclass
print Manager.Result # should equal 1
I'd prefer to simply include the accessory class (testclass) in my main class, then use an accessor that's already been initialized, but when I run hostapp.py, I get the following error:
NameError: name 'Manager' is not defined
Would someone please explain to me why the "global" variable Manager (which should be an instance of TestClass) is only accessible from within the class? I know I can access it using:
testclass.Manager
but that's not how I planned to access it. Help?
Edit:
After making the change suggested by Martineau, the accessor works as intended:
from testclass import Manager
I created the following example to understand the instances in python
import time;
class test:
mytime = time.time();
def __init__(self):
#self.mytime = time.time();
time.sleep(1);
pass
from test import test
test1 = test()
test2 = test()
print test1.mytime
print test2.mytime
test1.mytime = 12
print test1.mytime
print test2.mytime
in this case the output id the following:
1347876794.72
1347876794.72
12
1347876794.72
I expected that the test2.mytime is bigger with 1 second than the test1.mytime. Why doesn't created a copy about the mytime in each instance?
Let's look at those lines:
class test:
mytime = time.time();
Here you set class member value, which is calculated once when class definition is executed, so time.time() is calculated once when module that contains class test is loaded.
Every instance of the class test will receive that precalculated value and you must override that value (e.g. in __init__ method), accessing it via self (which is a special argument that stores reference to an instance), thus setting instance member value.
the mytime = time.time() is executed when the class is defined(when the interpreter runs the class-definition-code, and this will be run only once, so all instances will get the same mytime.
if you want different mytime in different instances, you have to use the self's one, and access it with instance name rather than class name.
The reason the value never changes is because it is a class variable meaning when the class is defined and evaluated but not when instances are made then the value is set.
If you want the value to change make it set inside the initialiser
The mytime variable is first created as a class variable and not an instance variable.
Python tries to locate a name on an instance first and if it is not found it will lookup the name on the class. You can query the namespace of any object (including) classes by looking at the object's __dict__, which is a dictionary containing the instance variables.
As soon as you set test1.mytime = 12, you created a new name in that object's __dict__, which from then on shadowed the class variable with the same name.
let's uncomment "self.mytime = time.time()" line from your code:
class test:
mytime = time.time();
def __init__(self):
self.newtime = time.time();
time.sleep(1);
#pass - no use of pass here
test1 = test()
test2 = test()
print test1.mytime
o/p: 1347883057.638443
print test2.mytime
o/p: 1347883057.638443
In this case, "mytime" variable is like static class member. and all instances of test() class (i.e: test1 and test2) will share same value of class attributes.
print test1.newtime
o/p: 1347883063.421356
print test2.newtime
o/p: 1347883068.7103591
whereas, value of instance variable. will be different for each instance of class.
therefore, to get different timing for each instance. you need to declare instance variable using "self" in "init" method.
self = instance as a first parameter in class method
init = default constructor method in python for defined class
Hope, it will help.
So I'm learning about classes. Why can't I use the third block of code to do the same thing that the second block of code apparently does? Why do I have to assign p1 to person()and not just use person() in the way I do in the third block of code?
#class
class person:
def asdf(self):
self.firstname=""
self.lastname=""
self.id=""
self.email=""
self.friends=[]
#second block of code
p1 = person()
p1.firstname="Dave"
p1.lastname="Johnson"
p1.id="2345239"
p1.email="dave#gmail.com"
print p1.firstname
#third block of code
person().firstname="Dave"
person().lastname="Johnson"
person().id="2345239"
person().email="dave#gmail.com"
print person().firstname
In the second block, you change the properties of the same instance.
p1 = person() # create new instance
p1.firstname="Dave" # change its first name
p1.lastname="Johnson" # change its last name
# ...
print p1.firstname # access its firstname
In the third block, you create a new instance in each line.
person().firstname="Dave" # create new instance and change its firstname
person().lastname="Johnson" # create new instance and change its lastname
# ...
print person().firstname # create new instance and access its firstname
To be more accurate, the problem only occurs in the last line, as you try to access an attirbute that was not yet declared, since the firstname attribute is declared only in the function asdf, or, in the second block, in the line p1.firstname="Dave"
Here's a simple example:
>>> class A:
... def AA(self):
... self.a = 1
...
>>> a = A()
>>> a.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'a'
>>> a.a = 1
>>> a.a
1
In the third block of code, each call to person() creates a new instance of the person class. The code then sets the value of an attribute on that object, then discards the entire object because it is not stored in any variable.
FYI, the python style is to use camel case on classes. This is part of the problem. The initial cap helps distinguish class construction from method calls.
Defining a class:
class Person(object):
def asdf(self):
self.firstname=""
self.lastname=""
self.id=""
self.email=""
self.friends=[]
Making an instance:
p = Person()
Using the class name like a function call constructs an instance, using the class as a prototype. In the second block, you've created an instance and you're changing its attributes.
In the third block, you've created four new instances of person, set one attribute on them, and thrown them away (because they're not assigned to anything).
The writeup on classes is really worth a read:
http://docs.python.org/tutorial/classes.html
There's a fair amount of underlying implementation that you don't need, but there's also some critical details about classes, instances, and attributes.