裝飾器方法
類的另外的特性,裝飾器方法:靜態方法(staticmethod)、類方法(classmethod)、屬性方法(property)
1、靜態方法
在方法名前加上@staticmethod裝飾器,表示此方法為靜態方法
class Dog(object): def __init__(self, name): self.name = name @staticmethod # 在方法前加上staticmethod 裝飾器定義靜態方法 def eat(): print("dog is eating")
靜態方法特性
特性:只是名義上歸類管理,實際上在靜態方法里訪問不了類或實例中的任何屬性
靜態方法,是不可以傳入self參數的,但是想傳也可以,調用時必須傳入實例本身
class Dog(object): def __init__(self, name): self.name = name @staticmethod # 定義靜態方法 def eat(self, food): # 可以定義,但是需傳入實例本身 print("{0} is eating {1}".format(self.name, food)) d = Dog("shabi") d.eat(d, "hotdog") # 傳入實例d本身,否則會報錯 # 輸出 shabi is eating hotdog
靜態方法可以用類直接調用,直接調用時,不可以直接傳入self,否則會報錯
class Dog(object): def __init__(self,name): self.name = name @staticmethod def eat(food): print("is eating {0}".format(food)) Dog.eat("hotdog") #輸出 is eating hotdog
靜態方法的使用場景,這種場景挺常見,就像os模塊的中某些函數一樣,都是使用了靜態方法
import os os.system() os.mkdir()
2、類方法
在方法名前加上@classmethod裝飾器,表示此方法為類方法
class Dog(object): name = "honggege" #定義靜態屬性 def __init__(self,name): self.name = name @classmethod #定義類方法 def eat(self,food): print("{0} is eating {1}".format(self.name,food))
類方法特性
特性:只能訪問類變量(又叫靜態屬性),不能訪問實例變量
class Dog(object): def __init__(self, name): self.name = name @classmethod # 定義類方法 def eat(self, food): print("{0} is eating {1}".format(self.name, food)) d = Dog("shabihong") d.eat("hotdog") # 輸出 Traceback (most recent call last): d.eat("hotdog") print("{0} is eating {1}".format(self.name, food)) AttributeError: type object 'Dog' has no attribute 'name'
訪問類變量(又叫靜態屬性)
class Dog(object): name = "honggege" #定義類變量 def __init__(self,name): self.name = name @classmethod def eat(self,food): print("{0} is eating {1}".format(self.name,food)) d = Dog("shabihong") d.eat("hotdog") #輸出 honggege is eating hotdog #調用的是類變量
使用場景:一般是需要去訪問寫死的變量,才會用到類方法裝飾器
3、屬性方法
在方法名前加上@property裝飾器,表示此方法為屬性方法
class Dog(object): def __init__(self,name): self.name = name @property #定義屬性方法 def eat(self): print("{0} is eating".format(self.name))
屬性方法特性
特性:把一個方法變成一個靜態屬性
靜態屬性的調用
class Dog(object): def __init__(self,name): self.name = name @property #定義屬性方法 def eat(self): print("{0} is eating".format(self.name)) d = Dog("shabihong") d.eat #把方法變成靜態屬性調用 #輸出 shabihong is eating
給轉成的靜態屬性賦值
用@靜態方法名.setter(屬性裝飾器)去裝飾方法,來給轉換后的靜態屬性賦值
class Dog(object): def __init__(self,name): self.name = name @property #定義屬性方法 def eat(self): print("{0} is eating {1}".format(self.name,"honggege")) @eat.setter #定義一個可以傳參的方法 def eat(self,food): print("set to food:",food) # self.__food = food d = Dog("shabihong") d.eat = "hotdog" #給轉成的靜態變量賦值 d.eat #輸出 set to food: hotdog shabihong is eating honggege
上面代碼沒有把food傳上去,那是因為傳參方法,沒有把接收之前的food的賦值,修改成如下代碼就能成功上傳:
class Dog(object): def __init__(self,name): self.name = name self.__food = None @property #定義屬性方法 def eat(self): print("{0} is eating {1}".format(self.name,self.__food)) @eat.setter #定義可以設置變量賦值 def eat(self,food): print("set to food:",food) self.__food = food d = Dog("shabihong") d.eat #第一份賦值的是None d.eat = "hotdog" d.eat #第二個賦值是hotdog #輸出 shabihong is eating None set to food: hotdog shabihong is eating hotdog #說明賦值成功
刪除轉變的靜態屬性
用@靜態方法名.deleter(屬性裝飾器)去裝飾,表明可以刪除轉化后的靜態屬性
class Dog(object): def __init__(self,name): self.name = name self.__food = None @property def eat(self): print("{0} is eating {1}".format(self.name,self.__food)) @eat.setter def eat(self,food): print("set to food:",food) self.__food = food @eat.deleter #定義可以刪除eat這個靜態屬性 def eat(self): del self.__food print("food 變量刪除完畢") d = Dog("shabihong") del d.eat #刪除靜態屬性eat #輸出 food 變量刪除完畢
靜態屬性使用場景
一個航班當前的狀態,是到達了、延遲了、取消了、還是已經飛走了, 想知道這種狀態必須經歷以下幾步:
- 連接航空公司API查詢
- 對查詢結果進行解析
- 返回結果給你的用戶
因此這個status屬性的值是一系列動作后才得到的結果,所以你每次調用時,其實它都要經過一系列的動作才返回你結果,但這些動作過程不需要用戶關心, 用戶只需要調用這個屬性就可以
class Flight(object): def __init__(self,name): self.flight_name = name def checking_status(self): print("checking flight %s status " % self.flight_name) return 1 @property def flight_status(self): status = self.checking_status() if status == 0 : print("flight got canceled...") elif status == 1 : print("flight is arrived...") elif status == 2: print("flight has departured already...") else: print("cannot confirm the flight status...,please check later") @flight_status.setter #修改 def flight_status(self,status): status_dic = { 0 : "canceled", 1 :"arrived", 2 : "departured" } print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) ) @flight_status.deleter #刪除 def flight_status(self): print("status got removed...") f = Flight("CA980") f.flight_status f.flight_status = 2 #觸發@flight_status.setter del f.flight_status #觸發@flight_status.deleter
裝飾器方法總結:
- 靜態方法是訪問不了類或實例中的任何屬性,它已經脫離了類,一般會用在一些工具包中
- 類方法,只能訪問類變量,不能訪問實例變量
- 屬性方法是把一個方法變成一個靜態屬性
類的特殊成員方法
類的方法,有普通方法,就是我們自己定義的方法,還有裝飾器方法(靜態方法,類方法,屬性方法),其實類還有另外一種方法,叫做類的特殊成員方法
1、 __doc__
說明:表示類的描述信息
class Dog(object): """此類是形容Dog這個類""" #類的描述信息 def __init__(self,name): self.name = name print(Dog.__doc__) #打印類的描述信息 #輸出 此類是形容Dog這個類
2、 __module__和__class__
說明:
- __module__: 表示當前操作的對象在哪個模塊
- __class__:表示當前操作的對象的類是什么
class C(object): def __init__(self): self.name = "shuaigaogao"
from aa import C obj = C() print(obj.__module__) # 表示當前操作的對象在哪個模塊 print(obj.__class__) # 表示當前操作的對象的類是什么 # 輸出 aa <class 'aa.C'>
3 、__init__
說明:構造方法,通過類創建對象時,自動觸發執行
4、 __del__
注:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的
說明:析構方法,當對象在內存中被釋放時,自動觸發執行
5、 __call__
注:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象后加括號觸發的,即:對象() 或者 類()()
說明: 對象后面加括號,觸發執行
class Foo(object): def __init__(self): self.name = "shuaigaogao" def __call__(self, *args, **kwargs): #重寫call方法 print("running call",args,kwargs) f = Foo() #執行__init__ f(1,2,3,name=333) # 執行call方法,也可以寫成 Foo()(1,2,3,name=333) #輸出 running call (1, 2, 3) {'name': 333}
6 、__dict__
說明: 查看類或對象中的所有成員
①類.__dict__
效果:打印類中所有的屬性,不包括實例屬性
class Province(object): country = 'China' def __init__(self, name, count): self.name = name self.count = count def func(self, *args, **kwargs): print("func") print(Province.__dict__) #類.__dict__ #輸出 {'__module__': '__main__', 'country': 'China', '__init__': <function Province.__init__ at 0x033D5C00>, 'func': <function Province.func at 0x033D5AE0>, '__dict__': <attribute '__dict__' of 'Province' objects>, '__weakref__': <attribute '__weakref__' of 'Province' objects>, '__doc__': None} #打印類中所有的屬性,不包括實例屬性
②實例名.__dict__
效果:打印該實例的所有屬性,不包括類屬性
class Province(object): country = 'China' def __init__(self, name, count): self.name = name self.count = count def func(self, *args, **kwargs): print("func") p = Province("jiangsu",20000) #實例化 print(p.__dict__) #實例名.__dict__ #輸出 {'count': 20000, 'name': 'jiangsu'} #打印該實例的所有屬性,不包括類屬性
7 、__str__
說明:如果一個類中定義了__str__方法,那么在打印 對象 時,默認輸出該方法的返回值
class Province(object): country = 'China' def __init__(self, name): self.name = name def __str__(self): return "<obj:{0}>".format(self.name) p = Province("jiangsu") print(p) #打印這個對象 #輸出 <obj:jiangsu> #給對象重新起了一個名字
注:這個會在django框架里面會用到
8 、__getitem__、__setitem__、__delitem__
說明:用於索引操作,如字典。以上分別表示獲取、設置、刪除數據
class Foo(object): def __getitem__(self, key): print('__getitem__:',key) def __setitem__(self, key, value): print('__setitem__:',key,value) def __delitem__(self, key): print('__delitem__',key) f = Foo() f["name"] = "shuaigaogao" #自動觸發__setitem__方法 f["name"] #自動觸發__getitem__方法 del f["name"] #自動觸發__delitem__方法 #輸出 __setitem__: name shuaigaogao __getitem__: name __delitem__ name
注:這邊的__delitem__沒有做真正的刪除,只是觸發這個方法,想要真正刪除,只需要在__delitem__函數中添加刪除功能即可
9、__new__ \ __metaclass__
__new__概念
new方法是類自帶的一個方法,可以重構,__new__方法在實例化的時候也會執行,並且先於__init__方法之前執行
class Foo(object): def __init__(self, name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__", cls, *args, **kwargs) return object.__new__(cls) f = Foo("shuaigaogao") # 輸出 Foo __new__ <class '__main__.Foo'> shuaigaogao Foo __init__
__new__方法作用
作用:所有對象都是通過new方法來實例化的,new里面調用了init方法,所以在實例化的過程中先執行的是new方法,而不是init方法。
①重構__new__方法
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs) f = Foo("shuaigaogao") #實例化 #輸出 Foo __new__ <class '__main__.Foo'> shuaigaogao
由上面的例子看出,沒有執行__init__方法
②重構__new__方法,並繼承父類的__new__方法
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): #cls相當於傳入類Foo print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls) #繼承父類的__new__方法,這邊必須以返回值的形式繼承 f = Foo("shuaigaogao") #輸出 Foo __new__ <class '__main__.Foo'> shuaigaogao
由上面不難看出,大多數情況下,你都不要去重構你的__new__方法,因為你父類中已經有__new__方法了,已經幫你寫好了怎么去創建類,如果你重寫的話,就會覆蓋父類的里面的__new__方法。但是你重構可以增加一點小功能,但是你覆蓋了以后還是需要繼承父類回來,要不然你的這個實力就創建不了。
__new__使用場景
我想對我自己寫的一些類進行定制,就在它實例化之前就進行定制,就可以用到__new__方法,new方法就是用來創建實力的,重構new方法,必須以返回值的形式繼承父類的new方法。
在創建對象時候,同時創建一個類變量
class Foo(object): def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): #cls相當於是傳入的類名Foo cls.name = "shuaigaogao" #創建對象是定義靜態變量 print(cls.name) return object.__new__(cls) #繼承父類的__new__方法 f = Foo("shuaigaogao") print(Foo.name) #輸出 shuaigaogao Foo __init__ shuaigaogao
__metaclass__
metaclass這個屬性叫做元類,它是用來表示這個類是由誰來幫他實例化創建的,說白了,就是相當於自己定制一個類。
class MyType(type): def __init__(self,*args,**kwargs): print("Mytype __init__",*args,**kwargs) def __call__(self, *args, **kwargs): print("Mytype __call__", *args, **kwargs) obj = self.__new__(self) print("obj ",obj,*args, **kwargs) print(self) self.__init__(obj,*args, **kwargs) return obj def __new__(cls, *args, **kwargs): print("Mytype __new__",*args,**kwargs) return type.__new__(cls, *args, **kwargs) class Foo(object,metaclass=MyType): #python3統一用這種 #__metaclass__ = MyType #python2.7中的寫法 def __init__(self,name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__",cls, *args, **kwargs) return object.__new__(cls) f = Foo("shuaigaogao") print("f",f) print("fname",f.name) #輸出 Mytype __new__ Foo (<class 'object'>,) {'__new__': <function Foo.__new__ at 0x0000025EF0EFD6A8>, '__init__': <function Foo.__init__ at 0x0000025EF0EFD620>, '__qualname__': 'Foo', '__module__': '__main__'} Mytype __init__ Foo (<class 'object'>,) {'__new__': <function Foo.__new__ at 0x0000025EF0EFD6A8>, '__init__': <function Foo.__init__ at 0x0000025EF0EFD620>, '__qualname__': 'Foo', '__module__': '__main__'} Mytype __call__ shuaigaogao Foo __new__ <class '__main__.Foo'> obj <__main__.Foo object at 0x0000025EF0F05048> shuaigaogao <class '__main__.Foo'> Foo __init__ f <__main__.Foo object at 0x0000025EF0F05048> fname shuaigaogao
創建過程如下:

類的生成 調用 順序依次是 __new__ --> __init__ --> __call__
