Python-物件導向進階,python-進階

來源:互聯網
上載者:User

Python-物件導向進階,python-進階

一、isinstance(obj, cls) and issubclass(sub, super)

1. isinstance(obj, cls),檢查obj是否是類cls的對象

1 class A:2     pass3 4 obj = A()5 print(isinstance(obj, A))6 7 #運行結果8 #True

2. issubclass(sub, super),檢查sub類是否是super類的衍生類別(子類)

 1 class A: 2     pass 3  4 class B(A): 5     pass 6  7 print(issubclass(B, A)) 8  9 #運行結果10 #True

二、反射

1. 什麼是反射

反射的概念是由Smith在1982年首次提出的,主要是指程式可以訪問、檢測和修改它本身狀態或行為的一種能力(自省)。這一概念的提出很快引發了電腦科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,並在Lisp和物件導向方面取得了成績。

2. python物件導向中的反射:通過字串的形式操作對象相關的屬性。python中的一切事物都是對象(都可以使用反射)。

 1 class People: 2     country = 'China' 3     def __init__(self, name, age): 4         self.name = name 5         self.age = age 6  7     def info(self): 8         print('%s is %d years old' % (self.name, self.age)) 9 10 p = People('jack', 18)11 12 #hasattr(obj, name),檢查屬性13 print(hasattr(p, 'info'))   #檢查對象p是否有‘info’屬性,結果True14 print(hasattr(p, 'name'))   #檢查對象p是否有‘name’屬性,結果True15 16 #getattr(obj, name)擷取屬性17 print(getattr(p, 'name'))   #獲得對象p的‘name’屬性,結果:返回p.name的值,即jack18 print(getattr(p, 'info'))   #獲得對象p的‘info’屬性,結果:返回p.info的值,19                             # 即Binder 方法info的記憶體位址:<bound method People.info of <__main__.People object at 0x000001B64317ABE0>>20 getattr(p, 'info')()        #由於getattr返回的是對象方法屬性的記憶體位址,加()就可以調用,結果:jack is 18 years old21 22 #setattr(x, y, v)設定屬性23 setattr(p, 'age', 21)       #修改對象p的‘age’屬性,結果:p.age的值變為2124 setattr(p, 'sex', 'male')   #新增對象p的‘sex’屬性,結果:p.sex的值為male25 print(p.__dict__)           #查看對象p的資料屬性,結果:{'name': 'jack', 'age': 21, 'sex': 'male'}26 27 #delattr(x, y)刪除屬性28 delattr(p, 'sex')           #刪除對象p的‘sex’屬性29 print(p.__dict__)           #結果:{'name': 'jack', 'age': 21}
四個可以實現自省的函數:hasattr(obj, name);getattr(obj, name);setattr(x, y, v);delattr(x, y)
 1 #類也是對象 2 class Foo(object): 3     staticField = "old boy" 4  5     def __init__(self): 6         self.name = 'wupeiqi' 7  8     def func(self): 9         return 'func'10 11     @staticmethod12     def bar():13         return 'bar'14 15 16 print(getattr(Foo, 'staticField'))  #擷取類的'staticField'屬性,結果:old boy17 18 print(getattr(Foo, 'func'))         #擷取類的'func'屬性,結果:<function Foo.func at 0x0000018156FBB950>19 print(getattr(Foo, 'func')('self'))     #加()調用方法,結果:func20 21 print(getattr(Foo, 'bar'))          #擷取類的'bar'屬性,結果:<function Foo.bar at 0x00000192D2AFB9D8>22 print(getattr(Foo, 'bar')())        #加()調用方法,結果:bar
類也是對象,能夠應用反射
 1 #反射當前模組成員 2 #!/usr/bin/env python 3 # -*- coding:utf-8 -*- 4  5 import sys 6  7  8 def s1(): 9     print('s1')10 11 12 def s2():13     print('s2')14 15 16 this_module = sys.modules[__name__]17 18 print(this_module)                      #結果:<module '__main__' from '......'>19 print(hasattr(this_module, 's1'))       #結果:True20 print(getattr(this_module, 's2'))       #結果:<function s2 at 0x0000020590EAB8C8>21 getattr(this_module, 's2')()            #結果:s2
模組也是對象,能夠應用反射

3. 反射的好處

好處一:實現可插拔機制

有倆程式員,一個lili,一個是egon,lili在寫程式的時候需要用到egon所寫的類,但是egon去跟女朋友度蜜月去了,還沒有完成他寫的類,lili想到了反射,使用了反射機制lili可以繼續完成自己的代碼,等egon度蜜月回來後再繼續完成類的定義並且去實現lili想要的功能。

總之反射的好處就是,可以事先定義好介面,介面只有在被完成後才會真正執行,這實現了隨插即用,這其實是一種‘後期綁定’,什麼意思?即你可以事先把主要的邏輯寫好(只定義介面),然後後期再去實現介面的功能。

 1 class FtpClient: 2     'ftp用戶端,但是還麼有實現具體的功能' 3     def __init__(self,addr): 4         print('正在串連伺服器[%s]' %addr) 5         self.addr=addr 6  7 ############################## 8 #不影響lili的代碼編寫 9 10 from module import FtpClient11 f1=FtpClient('192.168.1.1')12 if hasattr(f1,'get'):13     func_get=getattr(f1,'get')14     func_get()15 else:16     print('---->不存在此方法')17     print('處理其他的邏輯')

好處二:動態匯入模組(基於反射當前模組成員)

 1 #兩種匯入使用者輸入模組得方法,官方推薦方法2 2 #方法1 3 m = input('input your module:')     #使用者輸入要匯入的模組名,以time模組為例 4 m1 = __import__(m) 5 print(m1)                           #結果:<module 'time' (built-in)> 6 print(m1.time())                    #結果:1493023753.0157707,目前時間 7  8 #方法2 9 import importlib                    #先匯入importlib模組10 t = importlib.import_module(m)11 print(t)                            #結果:<module 'time' (built-in)>12 print(t.time())                     #結果:1493023753.0238242,目前時間

三、內建attr

 1 class Foo: 2     x = 1 3     def __init__(self, y): 4         self.y = y 5  6     def __getattr__(self, item): 7         print('----> from getattr:你找的屬性不存在') 8  9     def __setattr__(self, key, value):10         print('----> from setattr')11         # self.key=value                    #這就無限遞迴了12         self.__dict__[key] = value          #應該使用它13 14     def __delattr__(self, item):15         print('----> from delattr')16         # del self.item                     #無限遞迴了17         self.__dict__.pop(item)             #應該使用它18 19 #__setattr__添加/修改屬性會觸發它的執行20 f1 = Foo(10)                #因為重寫了__setattr__,凡是賦值操作都會觸發它的運行21 print(f1.__dict__)          #結果:----> from setattr {'y': 10}22 f1.z = 3                    #添加屬性23 print(f1.__dict__)          #結果:----> from setattr {'y': 10, 'z': 3}24 25 #__delattr__刪除屬性的時候會觸發26 f1.__dict__['a'] = 3        #我們可以直接修改屬性字典,來完成添加/修改屬性的操作27 del f1.a                    #觸發__delattr__28 print(f1.__dict__)          #結果:----> from delattr {'y': 10, 'z': 3}29 30 #__getattr__只有在使用對象調用屬性且屬性不存在的時候才會觸發31 print(f1.y)                 #屬性存在,結果:1032 f1.a                        #屬性a不存在,觸發__getattr__,結果:----> from getattr:你找的屬性不存在

四、二次加工標準類型(封裝)

封裝:python為大家提供了標準資料類型,以及豐富的內建方法,其實在很多情境下我們都需要基於標準資料類型來定製我們自己的資料類型,新增/改寫方法,這就用到了我們剛學的繼承/派生知識(其他的標準類型均可以通過下面的方式進行二次加工)

 

 1 #二次加工標準類型(基於繼承實現) 2 class List(list):               #繼承list所有的屬性,也可以派生出自己新的,比如append和mid 3     def append(self, p_object): 4         ' 派生自己的append:加上類型檢查' 5         if not isinstance(p_object, int): 6             raise TypeError('must be int') 7         super().append(p_object) 8  9     @property10     def mid(self):11         '新增自己的屬性'12         index = len(self)//213         return self[index]14 15 l = List([1, 2, 3, 4])16 print(l)17 l.append(5)18 print(l)                        #結果:[1, 2, 3, 4, 5]19 # l.append('1111111')           #報錯,必須為int類型20 21 print(l.mid)                    #結果:322 23 #其餘的方法都繼承list的24 l.insert(0, -123)               #插入元素25 print(l)                        #結果:[-123, 1, 2, 3, 4, 5]26 l.clear()                       #清空列表27 print(l)                        #結果:[]

授權:授權是封裝的一個特性, 封裝一個類型通常是對已存在的類型的一些定製,這種做法可以建立,修改或刪除原有產品的功能。其它的則保持原樣。授權的過程,即是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象的預設屬性。

實現授權的關鍵點就是覆蓋__getattr__方法

 1 # 授權示範 2 import time 3  4  5 class FileHandle: 6     def __init__(self, filename, mode='r', encoding='utf-8'): 7         self.file = open(filename, mode, encoding=encoding)         #獲得檔案控制代碼 8  9     def write(self, line):      #重新定義write方法,新增添加時間的功能10         t = time.strftime('%Y-%m-%d %T')11         self.file.write('%s %s' % (t, line))12 13     def __getattr__(self, item):    #檔案操作的其它屬性在FileHandle類中找不到時,觸發__getattr__14         return getattr(self.file, item)15 16 17 f1 = FileHandle('b.txt', 'w+')      #建立檔案b.txt,獲得檔案控制代碼,賦給對象f118 f1.write('你好啊')                 #調用類中的定製方法write19 f1.seek(0)                         #重設檔案位置於文首,觸發__getattr__,正常調用20 print(f1.read())                   #列印檔案內容,觸發__getattr__,正常調用,結果:2017-04-24 17:30:37 你好啊21 f1.close()                         #關閉檔案,觸發__getattr__,正常調用

 

 

參考資料:

1. http://www.cnblogs.com/linhaifeng/articles/6204014.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.