我们在https://www.cnblogs.com/yinsedeyinse/p/9976280.html中学习了面向对象的编程方法。现在学习他的进阶用法。
1. 静态方法
2. 类方法
3. 属性方法
4. 类的特殊功能方法
静态方法、类方法以及属性方法:我们先定义一个类,在类里定义一个方法
1 class Person(object): 2 def __init__(self,name): 3 self.name = name 4 5 6 def eat(self,food): 7 print("%s is eating %s"%(self.name,food)) 8 9 10 peaple = Person("Jack") 11 peaple.eat("cake")
Jack is eating cake
这个是常规的类的使用,一切正常,
然后我们把方法前加一个@staticmethod,把eat()转变成一个静态方法,运行一下,程序报错了!
TypeError: eat() missing 1 required positional argument: 'food'
发现少了个参数,我们把程序简化一下,看看是怎么回事!
1 class Person(object): 2 def __init__(self,name): 3 self.name = name 4 self.__food = None 5 @staticmethod 6 def eat(self): 7 print(self.name) 8 peaple = Person("Jack") 9 peaple.eat()
TypeError: eat() missing 1 required positional argument: 'self'
再改一下
1 class Person(object): 2 def __init__(self,name): 3 self.name = name 4 self.__food = None 5 @staticmethod 6 def eat(name,food): 7 print("%s is eating %s"%(name,food)) 8 peaple = Person("Jack") 9 peaple.eat("David","cake")
David is eating cake
可以发现,静态方法无法调用类里的属性了!
所以,静态方法就是实际上已经跟类没什么关系了,也就是名义上归类管理。在方法内无法调用类或实例里的任何属性。还有个用法相当于类的工具包(高级语法,有机会再说!)。
我们再看看类方法,在方法前加上@classmethod运行一下
1 class Person(object): 2 def __init__(self,name): 3 self.name = name 4 @classmethod #类方法 5 def eat(self,food): 6 print("%s is eating %s"%(self.name,food)) 7 peaple = Person("Jack") 8 peaple.eat("cake")
AttributeError: type object 'Person' has no attribute 'name'
提示没有“name”的变量,为什么呢?我们把name定义成类变量试一试。
1 class Person(object): 2 name = "Jeff" 3 def __init__(self,name): 4 self.name = name 5 @classmethod 6 def eat(self,food): 7 print("%s is eating %s"%(self.name,food)) 8 peaple = Person("Jack") 9 peaple.eat("cake")
Jeff is eating cake
类变量只能访问类变量,不能访问实例变量。
属性方法
1 class Person(object): 2 def __init__(self,name): 3 self.name = name 4 @property 5 def eat(self): 6 print("%s is eating"%self.name) 7 p1 = Person("Jack") 8 p1.eat #这里的p1.eat调用的是属性,不是方法
Jack is eating
在这个方法前加了@property,就把原来的方法改成了属性方法。在实例化后,不能用访问方法的形式(p1.eat())去访问,而要用属性的形式(p1.eat)。
但是有个问题,如果在属性方法里有参数需要传递的话,就要用到装饰器了!
1 class Person(object): 2 def __init__(self,name): 3 self.name = name 4 self.__food = None #先定义个私有属性 5 @property 6 def eat(self): 7 print("%s is eating %s"%(self.name,self.__food)) 8 @eat.setter #定义装饰器 9 def eat(self,food): 10 print("set to food:",food) 11 self.__food = food 12 p1 = Person("Jack") 13 p1.eat 14 p1.eat = "bread" #对属性方法赋值 15 p1.eat
Jack is eating None set to food: bread Jack is eating bread
完成效果,如果我们想把属性方法删除,用一般的删除方法是不行的
1 del p1.eat
这时候我们必须在类里重新定义个方法
1 class Person(object): 2 def __init__(self,name): 3 self.name = name 4 self.__food = None #先定义个私有属性 5 @property 6 def eat(self): 7 print("%s is eating %s"%(self.name,self.__food)) 8 @eat.setter #定义装饰器 9 def eat(self,food): 10 print("set to food:",food) 11 self.__food = food 12 @eat.deleter #删除方法 13 def eat(self): 14 del self.__food 15 print("已删除!") 16 p1 = Person("Jack") 17 p1.eat 18 p1.eat = "bread" #对属性方法赋值 19 p1.eat 20 del p1.eat #删除属性方法 21 p1.eat #重新调用测试一下
Jack is eating None set to food: bread Jack is eating bread 已删除! Traceback (most recent call last): File "D:/python/week7/属性方法.py", line 45, in <module> p1.eat File "D:/python/week7/属性方法.py", line 31, in eat print("%s is eating %s"%(self.name,self.__food)) AttributeError: 'Person' object has no attribute '_Person__food'
那有什么用呢?几个例子,航空公司都能提供航班状态,而其他的三方运营商需要调用这个值,显而易见的是运营商不能修改航班状态
1 class Flight(object): 2 def __init__(self,name): 3 self.name = name 4 5 def checking_status(self): 6 print("checking flight %s status"%self.name) 7 @property 8 def flight_status(self): 9 status = self.checking_status() 10 if status == 0: 11 print("flight is caceled!") 12 elif status == 1: 13 print("flight is arrived!") 14 elif status == 2: 15 print("flight has departured already!") 16 else: 17 print("cannot confirm the flight status,please check later!") 18 19 @flight_status.setter #航空公司返回航班的状态关键字 20 def flight_status(self,status): 21 status_dic = { 22 0:'caceled', 23 1:'arrived', 24 2:'departured' 25 } 26 27 @flight_status.deleter #删除该航班状态 28 def flight_status(self): 29 print("status is deleted!") 30 f = Flight("MU2388") #要查的航班编号 31 f.flight_status = 1 #航空公司每次只返回一个值描述出该航班状态 32 f.flight_status #其他的运营商直接访问属性的值,而不能改变其状态
现在来看一看一些类的特殊方法:
1.__doc__ 获取类的描述信息
1 # Author:Aaron 2 class People(): 3 ''' 4 该类描述了人类 5 ''' 6 def func1(self): 7 pass 8 print(People.__doc__)
C:\Users\Aaron\Anaconda3\python.exe D:/python/week7/类的特殊成员.py
该类描述了人类
在对类进行描述时,只能用‘’‘——’‘’来注释,用#注释时返回值为None。并且__doc__可以在不进行实例化时直接对类使用,也可以对实例使用。
2.__module__和__class__
1 from lib.aa import C 2 obj = C() 3 print(obj.__module__) #输出lib.aa,即为输出该功能所属模块 4 print(obj.__class__) #输出lib.aa.C,即为输出该类
在大量调用模块时,用这两个方法可以显示调用的类是属于那个模块的。
3.__call__
在实例后加(),执行功能
1 class Dog(): 2 def __call__(self, *args, **kwargs): 3 print("__call__的用法") 4 d1 = Dog() 5 d1()
C:\Users\Aaron\Anaconda3\python.exe D:/python/week7/类的特殊成员.py __call__的用法
在功能中,可以传递各种参数。
4.__dict__查看类或对象中的所有成员
1 class People(): 2 def __init__(self,name,age,sex): 3 self.name = name 4 self.age = age 5 self.sex = sex 6 def eat(self): 7 pass 8 def talk(self): 9 pass 10 11 p1= People("Jack",22,"male") 12 print(p1.__dict__) #打印所有实例属性,不包括类属性 13 print(People.__dict__) #打印所有类属性,不包括实例属性
C:\Users\Aaron\Anaconda3\python.exe D:/python/week7/类的特殊成员.py {'name': 'Jack', 'age': 22, 'sex': 'male'} {'__module__': '__main__', '__init__': <function People.__init__ at 0x00000243C1246510>, 'eat': <function People.eat at 0x00000243C1246598>, 'talk': <function People.talk at 0x00000243C1246620>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
以一个字典的形式把类或实例的方法打印出来,作用是在程序运行以后,如果有新加的属性,可以用这个方式查看。
5.__str__ 可以直接用print打印字符串
1 class People(): 2 def __init__(self,name): 3 self.name = name 4 def __str__(self): 5 return 'obj:%s'%self.name 6 7 p = People('Jeck') 8 print(p)
C:\Users\Aaron\Anaconda3\python.exe D:/python/week7/类的特殊成员.py
obj:Jeck
django中常用的用法,可以用来返回实例。
6. __getitem__,__setitem__,__delitem__
可以把一个字典封装成一个实例(类),用字典的方式添加类的属性等。然后控制字典的权限。用户可以访问这个字典其实是访问了一个类,但可以对用户进行权限控制。