1. 程式人生 > >Day7 - 面向對象高級語法

Day7 - 面向對象高級語法

err dep 字典 close 事物 高級 不能訪問 都是 ive

參考文章:http://www.cnblogs.com/alex3714/articles/5213184.html

本節內容:

  • 面向對象高級語法部分
    • 靜態方法、類方法、屬性方法
    • 類的特殊成員方法
    • 反射

靜態方法

通過 @staticmethod 裝飾器即可把其裝飾的方法變為一個靜態方法,什麽是靜態方法呢?其實不難理解,普通的方法,可以在實例化後直接調用,並且在方法裏可以通過self.調用實例變量或類變量,但靜態方法是不可以訪問實例變量或類變量的

(只是名義上歸類管理),一個不能訪問實例變量和類變量的方法,其實跟類本身已經沒什麽關系了,它與類唯一的關聯就是需要通過類名來調用這個方法

 1 class Dog(object):
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     @staticmethod  # 把eat方法變為靜態方法
 6     def eat(self):
 7         print("%s is eating" % self.name)
 8 
 9 d = Dog("abc")
10 d.eat()

上面的調用會出以下錯誤,說是 eat 需要一個 sel f參數,但調用時卻沒有傳遞,沒錯,當 eat 變成靜態方法後,再通過實例調用時就不會自動把實例本身當作一個參數傳給 self 了

1 Traceback (most recent call last):
2   File "D:/python_code/day6/001.py", line 10, in <module>
3     d.eat()
4 TypeError: eat() missing 1 required positional argument: self

想讓上面的代碼可以正常工作有兩種辦法

1. 調用時主動傳遞實例本身給 eat 方法,即 d.eat(d) ,可以通過 obj. 調用示例中的其它變量。

2. 在eat方法中去掉 sel f參數,但這也意味著,在 eat 中不能通過 self.

調用實例中的其它變量了

 1 class Dog(object):
 2 
 3     def __init__(self,name):
 4         self.name = name
 5 
 6     @staticmethod
 7     def eat():
 8         print(" is eating")
 9 
10 d = Dog("abc")
11 d.eat()

類方法   

類方法通過 @classmethod 裝飾器實現,類方法和普通方法的區別是, 類方法只能訪問類變量(公有屬性),不能訪問實例變量

 1 class Dog(object):
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     @classmethod
 6     def eat(self):
 7         print("%s is eating" % self.name)
 8 
 9 d = Dog("abc")
10 d.eat()

執行報錯如下,說Dog沒有name屬性,因為name是個實例變量,類方法是不能訪問實例變量的

1 Traceback (most recent call last):
2   File "D:/python_code/day6/001.py", line 10, in <module>
3     d.eat()
4   File "D:/python_code/day6/001.py", line 7, in eat
5     print("%s is eating" % self.name)
6 AttributeError: type object Dog has no attribute name

此時可以定義一個類變量(公有屬性),也叫name,看下執行效果

 1 class Dog(object):
 2 
 3     name = "我是類變量"
 4 
 5     def __init__(self, name):
 6         self.name = name
 7 
 8     @classmethod
 9     def eat(self):
10         print("%s is eating" % self.name)
11 
12 d = Dog("abc")
13 d.eat()
14 
15 執行結果:
16     我是類變量 is eating

屬性方法   

屬性方法的作用就是通過 @property 裝飾器把一個方法變成一個靜態屬性

 1 class Dog(object):
 2 
 3     def __init__(self, name):
 4         self.name = name
 5 
 6     @property
 7     def eat(self):
 8         print("%s is eating" % self.name)
 9 
10 d = Dog("abc")
11 d.eat()

調用會出以下錯誤, 說NoneType is not callable, 因為eat此時已經變成一個靜態屬性了, 不是方法了, 想調用已經不需要加()號了,直接d.eat就可以了

1 ChenRonghua is eating
2 Traceback (most recent call last):
3   File "D:/python_code/day6/001.py", line 11, in <module>
4     d.eat()
5 TypeError: NoneType object is not callable

正常調用如下

1 d = Dog("abc")
2 d.eat
3  
4 輸出
5  ChenRonghua is eating

變成靜態屬性後, 想調用已經不需要加()號,也不可以給它傳參數了,還不可以直接通過 del 語法刪除,因為靜態屬性默認無法刪除傳參數、刪除都必須在類裏在重新定義一個同名的方法。

 1 class Dog(object):
 2     def __init__(self, name):
 3         self.name = name
 4         self.__food = None
 5 
 6     @property  # attribute
 7     def eat(self):
 8         print("%s is eating %s" % (self.name, self.__food))
 9     @eat.setter
10     def eat(self, food):    #修改(賦值)
11         print("set to food:", food)
12         self.__food = food
13     @eat.deleter
14     def eat(self):        #刪除
15         del self.__food
16         print("刪完了")
17 
18 d = Dog("abc")
19 d.eat
20 d.eat = "包子"    [email protected]
21 d.eat
22 del d.eat       [email protected]

執行結果:

1 abc is eating None
2 set to food: 包子
3 abc is eating 包子
4 刪完了

屬性方法的應用實例:

好吧,把一個方法變成靜態屬性有什麽卵用呢?既然想要靜態變量,那直接定義成一個靜態變量不就得了麽?well, 以後你會需到很多場景是不能簡單通過 定義 靜態屬性來實現的, 比如 ,你想知道一個航班當前的狀態,是到達了、延遲了、取消了、還是已經飛走了, 想知道這種狀態你必須經歷以下幾步:

1. 連接航空公司API查詢

2. 對查詢結果進行解析

3. 返回結果給你的用戶

因此這個status屬性的值是一系列動作後才得到的結果,所以你每次調用時,其實它都要經過一系列的動作才返回你結果,但這些動作過程不需要用戶關心, 用戶只需要調用這個屬性就可以,明白 了麽?

技術分享
 1 class Flight(object):
 2     def __init__(self, name):
 3         self.flight_name = name
 4 
 5     def checking_status(self):
 6         print("checking flight %s status " % self.flight_name)
 7         return 1
 8 
 9     @property
10     def flight_status(self):
11         status = self.checking_status()
12         if status == 0:
13             print("flight got canceled...")
14         elif status == 1:
15             print("flight is arrived...")
16         elif status == 2:
17             print("flight has departured already...")
18         else:
19             print("cannot confirm the flight status...,please check later")
20 
21     @flight_status.setter  # 修改
22     def flight_status(self, status):
23         status_dic = {
24             0: "canceled",
25             1: "arrived",
26             2: "departured"
27         }
28         print("\033[31;1mHas changed the flight status to \033[0m", status_dic.get(status))
29 
30     @flight_status.deleter  # 刪除
31     def flight_status(self):
32         print("status got removed...")
33 
34 
35 f = Flight("CA980")
36 f.flight_status
37 f.flight_status = 2  # [email protected]_status.setter
38 del f.flight_status  # [email protected]_status.deleter
flight_status

類的特殊成員方法

1. __doc__  表示類的描述信息

技術分享
1 class Dog(object):
2     ‘‘‘這個類是描述狗這個對象的‘‘‘
3 
4     def func(self):
5         pass
6 
7 print(Dog.__doc__)
8 
9 #輸出:這個類是描述狗這個對象的
__doc__

2. __module__ 和 __class__

  __module__ 表示當前操作的對象在那個模塊

  __class__ 表示當前操作的對象的類是什麽

技術分享
1 class C:
2 
3     def __init__(self):
4         self.name = abc
lib/aa.py 技術分享
1 from lib.aa import C
2 
3 obj = C()
4 print obj.__module__  # 輸出 lib.aa,即:輸出模塊
5 print obj.__class__      # 輸出<class ‘ lib.aa.C‘>,即:輸出類
index.py

3. __init__ 構造方法,通過類創建對象時,自動觸發執行。

4.__del__

 析構方法,當對象在內存中被釋放時,自動觸發執行。通常用於做一些收尾工作,如關閉一些數據庫連接,關閉打開的臨時文件。

註:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的 

5. __call__ 對象後面加括號,觸發執行。

註:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()

技術分享
 1 class Foo(object):
 2     def __init__(self,name):
 3         self.name =name
 4         print(__init__)
 5 
 6     def __call__(self, *args, **kwargs):
 7         print(__call__)
 8 
 9 
10 obj = Foo(abc)     # 執行 __init__
11 #輸出:__init__
12 obj()              # 執行 __call__
13 #輸出:__call__
14 Foo(abc)()        # 執行 __call__    
15 #輸出:__init__、__call__
__call__

6. __dict__ 查看類或對象中的所有成員   

技術分享
 1 class Province(object):
 2     country = China
 3 
 4     def __init__(self, name, count):
 5         self.name = name
 6         self.count = count
 7 
 8     def func(self, *args, **kwargs):
 9         print(func)
10 
11 # 獲取類的所有屬性,不包括實例屬性,即:公有屬性(靜態字段)、方法
12 print(Province.__dict__)
13 # 輸出:{‘func‘: <function Province.func at 0x000001A21E77EC80>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Province‘ objects>, ‘country‘: ‘China‘, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Province‘ objects>, ‘__init__‘: <function Province.__init__ at 0x000001A21E77EBF8>, ‘__doc__‘: None, ‘__module__‘: ‘__main__‘}
14 
15 obj1 = Province(HeBei, 10000)
16 obj1.func()
17 # 獲取實例 obj1 的所有屬性,不包括類屬性
18 print(obj1.__dict__)
19 # 輸出:{‘count‘: 10000, ‘name‘: ‘HeBei‘}
20 
21 obj2 = Province(HeNan, 3888)
22 obj2.func()
23 print(obj2.__dict__)
24 # 獲取 對象 obj2 的成員
25 # 輸出:{‘count‘: 3888, ‘name‘: ‘HeNan‘}
__dict__

7.__str__ 如果一個類中定義了__str__方法,那麽在打印 對象 時,默認輸出該方法的返回值。

技術分享
1 class Foo(object):
2     def __str__(self):
3         return "__str__"
4 
5 obj = Foo()
6 print(obj)
7 # 輸出:__str__
__str__

8.__getitem__、__setitem__、__delitem__

用於索引操作,如字典。以上分別表示獲取、設置、刪除數據

技術分享
 1 __author__ = "Alex Li"
 2 
 3 
 4 class Foo(object):
 5     def __init__(self):
 6         self.data = {}
 7     def __getitem__(self, key): #獲取
 8         print(__getitem__, key)
 9         return self.data.get(key)
10     def __setitem__(self, key, value):  #設置
11         print(__setitem__, key, value)
12         self.data[key] =value
13     def __delitem__(self, key): #刪除
14         print(__delitem__, key)
15 
16 obj = Foo()
17 obj[name] = "abc"          # 自動觸發執行 __setitem__
18 print(obj[name])  #輸出:abc
19 print(obj.data)     #輸出:{‘name‘: ‘abc‘}
20 del obj["sdfdsf"]           # 自動觸發執行 __delitem__,刪沒刪除看 __delitem__ 方法裏有沒有刪除
21 result = obj[name]        # 自動觸發執行 __getitem__
22 print(result)       #輸出:abc
23 obj[k2] = abc           # 自動觸發執行 __setitem__
24 del obj[k1]
25 print(obj[name])  #輸出:abc
26 print(obj.data)     #輸出:{‘name‘: ‘abc‘, ‘k2‘: ‘abc‘}
__getitem__、__setitem__、__delitem__

9. __new__ \ __metaclass__

技術分享
1 class Foo(object):
2     def __init__(self, name):
3         self.name = name
4 
5 f = Foo("abc")
Foo

上述代碼中,f 是通過 Foo 類實例化的對象,其實,不僅 obj 是一個對象,Foo類本身也是一個對象,因為在Python中一切事物都是對象

如果按照一切事物都是對象的理論:obj對象是通過執行Foo類的構造方法創建,那麽Foo類對象應該也是通過執行某個類的 構造方法 創建。

1 print(type(f))      # 輸出:<class ‘__main__.Foo‘>   表示:f 對象由Foo類創建
2 print(type(Foo))    # 輸出:<type ‘type‘>            表示,Foo類對象由 type 類創建

所以,f對象是Foo類的一個實例Foo類對象是 type 類的一個實例,即:Foo類對象 是通過type類的構造方法創建。

那麽,創建類就可以有兩種方式:

a). 普通方式

1 class Foo(object):
2   
3     def func(self):
4         print (hello world!)

b). 特殊方式

1 def func(self):
2     print(hello world!)
3 
4 # type --> 類的類
5 Foo = type(Foo, (object,), {func: func})    #新式類
6 #Foo = type(‘Foo‘, (), {‘func‘: func})        #經典類
7 # type第一個參數:類名
8 # type第二個參數:當前類的基類; 新式類:(object,) 、經典類:()
9 # type第三個參數:類的成員
技術分享
 1 def func(self):
 2     print(hello %s %self.name)
 3 
 4 def __init__(self,name,age):
 5     self.name = name
 6     self.age = age
 7 # type --> 類的類
 8 Foo = type(Foo, (object,), {talk: func,
 9                        __init__:__init__})
10 f = Foo("world",22)
11 f.talk()            #輸出:hello world
12 print(type(f))      #輸出:<class ‘__main__.Foo‘>
13 print(type(Foo))    #輸出:<class ‘type‘>
加上構造方法

所以說,類 是由 type 類實例化產生

那麽問題來了,類默認是由 type 類實例化產生,type類中如何實現的創建類?類又是如何創建對象?

答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化創建,所以,我們可以為 __metaclass__ 設置一個type類的派生類,從而查看 類 創建的過程。

技術分享

技術分享
 1 class MyType(type):
 2     def __init__(self, what, bases=None, dict=None):
 3         print("MyType __init__")
 4         super(MyType, self).__init__(what, bases, dict)
 5 
 6     def __call__(self, *args, **kwargs):
 7         print("MyType __call__")
 8         obj = self.__new__(self, *args, **kwargs)
 9         #obj.data = {"name":111}
10         self.__init__(obj, *args, **kwargs)
11 
12 class Foo(object):
13     __metaclass__ = MyType  #元類:__metaclass__,跟 MyType 關聯
14 
15     def __init__(self, name):
16         self.name = name
17         print("Foo __init__")
18 
19     def __new__(cls, *args, **kwargs):  #用來創建實例的
20         print("Foo __new__")
21         #print(object.__new__(cls))
22         return object.__new__(cls) #繼承父類的__new__方法,一定要用 return
23 
24 # 第一階段:解釋器從上到下執行代碼創建Foo類
25 # 第二階段:通過Foo類創建obj對象
26 # 類的生成調用順序依次是 __new__ --> __init__ --> __call__
27 obj = Foo("Alex")
28 print(obj.name)
自定義元類

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

  __new__ : 用來創建實例的,一般無須定義,自動存在,定義就是重構__new__方法

Day7 - 面向對象高級語法