書....接...上...回...python
先試着用python2和python3分別把下面代碼執行一邊程序員
class A: def __init__(self): self.n = 'A' class B(A): def __init__(self): self.n = 'B' class C(A): def __init__(self): self.n = 'C' class D(B,C): def __init__(self): self.n = 'D' obj = D() print(obj.n)
而後分別用python2和python3按照順序,分別把D、B、C的構造函數註釋掉換成pass執行,你會發現,在python2中,幾回輸出分別是D、B、A、C,在python3中幾回輸出分別是D、B、C、A。但若是咱們在A後面加上一個(object),那麼它就從經典類變成了一個新式類,而後你再次在python2中像剛纔那樣運行。你會發現此次的輸出結果由上次的D、B、A、C變成了D、B、C、A。python3再次運行無變化。ide
由此咱們能夠得出結果:函數
python2:spa
python33d
@staticmethod裝飾器便可把其裝飾的方法變爲一個靜態方法,什麼是靜態方法呢?其實不難理解,普通的方法,能夠在實例化後直接調用,而且在方法裏能夠經過self.調用實例變量或類變量,但靜態方法是不能夠訪問實例變量或類變量的,一個不能訪問實例變量和類變量的方法,其實至關於跟類自己已經沒什麼關係了,它與類惟一的關聯就是須要經過類名來調用這個方法。code
class Person(object): def __init__(self,name): self.name = name @staticmethod #把eat方法變爲靜態方法 def eat(self): print("%s is eating" % self.name) p = Person("jack") p.eat()
上面的調用會出錯誤,說是eat須要一個self參數,但調用時卻沒有傳遞,沒錯,當eat變成靜態方法後,再經過實例調用時就不會自動把實例自己看成一個參數傳給self了。對象
解決方法有兩種:blog
類方法經過@classmethod裝飾器實現,類方法和普通方法的區別是,類方法只能訪問類變量,不能訪問實例變量。而且類方法傳入的第一個參數爲cls,是類自己。類方法能夠經過類直接調用,或經過實例直接調用。但不管哪一種調用方式,最左側傳入的參數必定是類自己。內存
class Dog(object): name = 'jack' def __init__(self, name): self.name = name @classmethod def eat(cls): print("%s is eating" % cls.name) Dog.eat() d = Dog("tom") d.eat()
但不管上哪種的調用方式,結果打印的都是同樣的:
jack is eating jack is eating
屬性方法的做用就是經過@property把一個方法變成一個靜態屬性
class Dog(object): def __init__(self,name): self.name = name @property def eat(self): print(" %s is eating" %self.name) d = Dog("Jack") d.eat()
上面這種代碼的運行會報錯這種錯誤,TypeError: 'NoneType' object is not callable,由於此時的eat已是一個靜態屬性了,不能再經過加()來調用。
正常調用以下:
d = Dog("jack") d.eat 輸出 jack is eating
PS:若是屬性方法還傳入了固定參數,想對這個固定參數進行修改怎麼辦呢?由於咱們知道,屬性方法的調用是不能加括號的,既然不能加括號,那就不能傳參數,擦,這樣的話,參數不就寫死了。。。固然是能夠改的,能夠在屬性方法的下方再寫一個同名的函數,用下面這種裝飾器 @函數名.setter 來進行裝飾,能夠在這個函數中進行參數的修改,固然還有裝飾器 @函數名.deleter 來裝飾函數,對屬性進行刪除操做。
一、__doc__ 表示類的描述信息
class Foo: """ 這是一個神奇的類 """ def func(self): pass print(Foo.__doc__) f = Foo() print(f.__doc__) 輸出結果: 這是一個神奇的類 這是一個神奇的類
PS:用類或者實例均可以進行調用該方法。
二、__module__、__class__
class C: def __init__(self): self.name = 'wusir'
from lib.aa import C obj = C() print (obj.__module__ ) # 輸出 lib.aa,即:輸出模塊 print (obj.__class__) # 輸出 lib.aa.C,即:輸出類
三、__init__ 構造函數,經過類建立對象時自動執行,用於完成對類的初始化操做
四、__del__ 析構函數,當對象在內存中被釋放時,自動觸發執行。此方法通常無須定義,由於Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,由於此工做都是交給Python解釋器來執行,因此,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。
五、__call__ 對象後面加括號,觸發執行。即:對象()或者類()()會觸發執行。
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('我是call') obj = Foo() # 執行 __init__ obj() # 執行 __call__ 輸出結果: 我是call
六、__dict__ 查看類或對象中的全部成員
class Province: country = 'China' def __init__(self, name, count): self.name = name self.count = count def func(self, *args, **kwargs): print('func') # 獲取類的成員,即:靜態字段、方法、 print(Province.__dict__) # 獲取對象obj1的成員 obj1 = Province('HeBei', 10000) print(obj1.__dict__) # 獲取對象obj2的成員 obj2 = Province('HeNan', 3888) print(obj2.__dict__)
輸出結果:
{'__module__': '__main__', 'country': 'China', '__init__': <function Province.__init__ at 0x000001875B266598>, 'func': <function Province.func at 0x000001875B266620>, '__dict__': <attribute '__dict__' of 'Province' objects>, '__weakref__': <attribute '__weakref__' of 'Province' objects>, '__doc__': None} {'name': 'HeBei', 'count': 10000} {'name': 'HeNan', 'count': 3888}
七、 __str__ 若是一個類中定義了該方法,那麼在打印對象時,默認輸出該方法的返回值
class Foo: def __str__(self): return 'wusir' obj = Foo() print(obj) # 輸出結果 wusir
八、 __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) obj = Foo() result = obj['k1'] # 自動觸發執行 __getitem__ obj['k2'] = 'wusir' # 自動觸發執行 __setitem__ del obj['k1'] #自動觸發執行 __delitem__,按上述寫法並未真正刪除,如需刪除,需在 #__delitem__ 方法中寫刪除操做 輸出: __getitem__ k1 __setitem__ k2 wusir __delitem__ k1
九、__new__ \ __metaclass__
class Foo(object): def __init__(self,name): self.name = name f = Foo("wusir")
上述代碼中,f是經過 Foo 類實例化的對象,其實,不只 f 是一個對象,Foo類自己也是一個對象,由於在python中,一切皆對象,那麼若是按照一切皆對象的理論:f對象是經過執行Foo類的構造方法建立,那麼Foo類對象應該也是經過執行某個類的構造方法建立。
print type(f) # 輸出:<class '__main__.Foo'> 表示,obj 對象由Foo類建立 print type(Foo) # 輸出:<type 'type'> 表示,Foo類對象由 type 類建立
由上述打印結果咱們能夠發現:f是Foo的一個實例,Foo是type的一個實例,即:Foo類對象 是經過type類的構造方法建立。
那麼,建立類就能夠有兩種方式:
通常方式:
class Foo(): def func(self): pass
特殊方式:
def func(self): pass Foo = type('Foo',(object,),{"func":func})
#type第一個參數:類名
#type第二個參數:當前類的基類
#type第三個參數:類的成員
def func(self): print("hello %s"%self.name) def __init__(self,name,age): self.name = name self.age = age Foo = type('Foo',(object,),{'func':func,'__init__':__init__}) f = Foo("wusir",22) f.func()
因此,要牢記:類是由type類實例化產生的!
那麼問題來了,類默認是由 type 類實例化產生,type類中如何實現的建立類?類又是如何建立對象?
答:類中有一個屬性 __metaclass__,其用來表示該類由誰來實例化建立,因此,咱們能夠爲 __metaclass__ 設置一個type類的派生類,從而查看類建立的過程。
class MyType(type): def __init__(self, what, bases=None, dict=None): print("--MyType init---") super(MyType, self).__init__(what, bases, dict) def __call__(self, *args, **kwargs): print("--MyType call---") obj = self.__new__(self, *args, **kwargs) self.__init__(obj, *args, **kwargs) class Foo(object): __metaclass__ = MyType def __init__(self, name): self.name = name print("Foo ---init__") def __new__(cls, *args, **kwargs): print("Foo --new--") return object.__new__(cls) # 第一階段:解釋器從上到下執行代碼建立Foo類 # 第二階段:經過Foo類建立obj對象 obj = Foo("Alex")
類的生成 調用 順序依次是 __new__ --> __init__ --> __call__
經過字符串映射或修改程序運行時的狀態、屬性、方法, 內置函數分別爲:getattr、hasattr、setattr、delattr 獲取成員、檢查成員、設置成員、刪除成員。
class Foo(object): def __init__(self): self.name = 'wusir' def func(self): return 'jack' obj = Foo() #### 檢查是否含有成員 #### print(hasattr(obj, 'name')) print(hasattr(obj, 'func')) #### 獲取成員 #### print(getattr(obj, 'name')) print(getattr(obj, 'func')()) #### 設置成員 #### print(hasattr(obj,'age')) setattr(obj, 'age', 18) print(getattr(obj,'age')) #### 刪除成員 #### delattr(obj, 'name') print(hasattr(obj,'name'))
輸出結果:
True True wusir jack False 18 False