一、静态方法
通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?
其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量。
但静态方法是不可以访问实例变量或类变量的,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法;
静态方法不可访问实例变量跟类变量,内部其他函数可通过self.静态方法执行,需要实例化
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 6 # 静态方法 7 class Schoolmate(object): 8 def __init__(self, name): 9 self.name = name 10 11 @staticmethod # 把eat方法变为静态方法 12 def eat(self): 13 print("%s is eating" % self.name) 14 15 16 p = Schoolmate("VisonWong") 17 p.eat() 18 19 20 # Traceback (most recent call last): 21 # File "E:/Python/PythonLearing/class/静态方法.py", line 17, in <module> 22 # p.eat() 23 # TypeError: eat() missing 1 required positional argument: 'self'
上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递。
当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。
想让上面的代码正常工作有两种办法
-
- 调用时主动传递实例本身给eat方法,即p.eat(p)
- 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 # 静态方法 6 class Schoolmate(object): 7 def __init__(self, name): 8 self.name = name 9 10 @staticmethod # 把ea变成静态方法 11 def eat(self): 12 print("%s is eating" % self.name) 13 14 15 p = Schoolmate("VisonWong") 16 p.eat(p) #变成静态方法后,调用时不会自动传递实例参数,需主动传递 17 18 19 # VisonWong is eating
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 6 # 静态方法 7 class Schoolmate(object): 8 def __init__(self, name): 9 self.name = name 10 11 @staticmethod # 把eat方法变为静态方法 12 def eat(): 13 print("eating") 14 15 16 p = Schoolmate("visonwong") 17 p.eat() 18 19 20 # eating
内部其他函数可通过self.静态方法调用,需实例化。
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 6 # 静态方法 7 class Schoolmate(object): 8 def __init__(self, name): 9 self.name = name 10 11 def resting(self): 12 print("%s is resting" %self.name) 13 self.sleeping(self) #内部调用静态方法 14 15 @staticmethod # 把eat方法变为静态方法 16 def sleeping(self): 17 print("%s is eating" %self.name) 18 19 20 p = Schoolmate("VisonWong") 21 p.resting() 22 23 24 # VisonWong is resting 25 # VisonWong is eating
二、类方法
类方法顾名思义跟类有关,类方法通过@classmethod装饰器实现,
类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量,不用实例化,通过类名直接执行。
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 # 类方法 6 class Schoolmate(object): 7 def __init__(self, name): 8 self.name = name 9 10 @classmethod # 把eat方法变为类方法 11 def eat(self): 12 print("%s is eating" % self.name) 13 14 15 p = Schoolmate("visonwong") 16 p.eat() 17 18 19 # Traceback (most recent call last): 20 # File "E:/Python/PythonLearing/class/类方法.py", line 16, in <module> 21 # p.eat() 22 # File "E:/Python/PythonLearing/class/类方法.py", line 12, in eat 23 # print("%s is eating" % self.name) 24 # AttributeError: type object 'Schoolmate' has no attribute 'name'
执行报错如下,说schoolmat没有name属性,这是因为name是个实例变量,类方法是不能访问实例变量的,只能访问类变量
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 # 类方法 6 class Schoolmate(object): 7 name = "Schoolmate的类变量" 8 9 def __init__(self, name): 10 self.name = name 11 12 @classmethod # 把eat方法变为类方法 13 def eat(self): 14 print("%s is eating" % self.name) 15 16 17 p = Schoolmate("visonwong") 18 p.eat() 19 20 21 # Schoolmate的类变量 is eating
此时定义一个名为name的类变量,即可解决。
三、属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性(变量)。
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 # 属性方法 6 7 class Schoolmate(object): 8 name = ("Schoolmat的类变量") 9 10 def __init__(self, name): 11 self.name = name 12 13 @property # 把eat方法变为属性方法 14 def eat(self): 15 print("%s is eating" % self.name) 16 17 18 p = Schoolmate("visonwong") 19 p.eat() 20 21 22 # Traceback (most recent call last): 23 # File "E:/Python/PythonLearing/class/属性方法.py", line 19, in <module> 24 # p.eat() 25 # TypeError: 'NoneType' object is not callable
调用会出现以下错误, NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了。
想调用已经不需要加()号了,直接p.eat就可以了.
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 # 属性方法 6 7 class Schoolmate(object): 8 name = ("Schoolmat的类变量") 9 10 def __init__(self, name): 11 self.name = name 12 13 @property # 把eat方法变为属性方法 14 def eat(self): 15 print("%s is eating" % self.name) 16 17 18 p = Schoolmate("visonwong") 19 p.eat 20 21 22 # visonwong is eating
好吧,把一个方法变成静态属性有什么卵用呢?
既然想要静态变量,那直接定义成一个静态变量不就得了么?
但是,以后我们会遇到静态变量不固定或者变量值需要通过外部接口查询的情况,不能简单通过定义静态属性来实现。
比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了?
想知道这种状态你必须经历以下几步:
-
- 连接航空公司API查询
- 对查询结果进行解析
- 返回结果给你的用户
因此航班状态属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果。
然而这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白了么?
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 6 # 属性方法实例 7 8 class Flight(object): 9 def __init__(self, name): 10 self.flight_name = name 11 12 def checking_status(self): #模拟整个查询过程,并返回结果 13 print("checking flight %s status " % self.flight_name) 14 return 1 15 16 @property 17 def flight_status(self): 18 status = self.checking_status() #模拟调用航空公司API接口 19 if status == 0: 20 print("flight got canceled...") 21 elif status == 1: 22 print("flight is arrived...") 23 elif status == 2: 24 print("flight has departured already...") 25 else: 26 print("cannot confirm the flight status...,please check later") 27 28 29 f = Flight("CA980") 30 f.flight_status 31 32 33 # checking flight CA980 status 34 # flight is arrived...
cool , 那现在我只能查询航班状态, 既然这个flight_status已经是个属性了, 那我能否给它赋值呢?试试吧。
1 f = Flight("CA980") 2 f.flight_status 3 4 f.flight_status = 2 5 6 7 # Traceback (most recent call last): 8 # File "E:/Python/PythonLearing/class/flight_status.py", line 32, in <module> 9 # f.flight_status = 2 10 # AttributeError: can't set attribute
输出显示不能更改这个属性。
修改方法是需要通过@proerty.setter装饰器再装饰一下,此时 你需要写一个新方法, 对这个flight_status进行更改。
通过@property.deleter可以删除类中的任意变量(除了静态属性本身)。
1 #!/user/bin/env ptyhon 2 # -*- coding:utf-8 -*- 3 # Author: VisonWong 4 5 6 # 属性方法实例 7 8 class Flight(object): 9 def __init__(self, name): 10 self.flight_name = name 11 self.__status = None #定义航班状态查询变量,储存属性方法中静态变量的值(相当于静态变量的“替身”) 12 self.__check = None #定义航班状态查询变量 13 14 def checking_status(self): #模拟整个查询过程,并返回结果 15 print("checking flight %s status " % self.flight_name) 16 self.__check = True 17 return 1 18 19 @property 20 def flight_status(self): 21 if not self.__check: #如果未查询,调用航空API接口,如果已调用,采用后续修改值 22 self.__status = self.checking_status() #模拟调用航空公司API接口 23 if self.__status == 0: 24 print("flight got canceled...") 25 elif self.__status == 1: 26 print("flight is arrived...") 27 elif self.__status == 2: 28 print("flight has departured already...") 29 else: 30 print("cannot confirm the flight status...,please check later") 31 32 @flight_status.setter #修改静态方法 33 def flight_status(self,status): 34 self.__status = status 35 status_dic = { 36 0:"canceled", 37 1:"arrived", 38 2:"departured" 39 } 40 print('