class Student(object): def __init__(self, name): self.name = name def __str__(self): return "Student object name:{}".format(self.name) __repr__ = __str__
若是一個類想被用於for ... in循環,相似list或tuple那樣,就必須實現一個__iter__()方法,該方法返回一個迭代對象,而後,Python的for循環就會不斷調用該迭代對象的next()方法拿到循環的下一個值,直到遇到StopIteration錯誤時退出循環,咱們以斐波那契數列爲例,寫一個Fib類,能夠做用於for循環:django
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化2個計數器 def __iter__(self): return self # 實例自己就是迭代器,返回self def next(self): self.a, self.b = self.b, self.a + self.b # 計算下一個值 if self.a > 100000: # 退出循環條件 raise StopIteration() return self.a # 返回下一個值 for n in Fib(): print n
Fib實例雖然能做用於for循環,看起來和list有點像,可是,把它當成list來使用仍是不行,好比,取第5個元素,要表現得像list那樣按照下標取出元素,須要實現__getitem__()方法:函數
class Fab(object): def __getitem__(self, item): a, b = 1, 1 for x in xrange(item): a, b = b, a + b return a f = Fab() print f[1] print f[2]
正常狀況下,當咱們調用類的方法或屬性時,若是不存在,就會報錯。StudentTest類.調用name屬性,沒問題,可是,調用不存在的arg屬性,就有問題了,在getattr裏面能夠作判斷而且返回一個對象:工具
代碼實現:測試
class StudentTest(object): def __init__(self): self.name = "Hero" def __getattr__(self, item): if item == 'arg': return 27 else: raise ValueError("The key is not found") st = StudentTest() print st.name print st.arg print st.sexy
實際用例: 將一個字典設置成類屬性訪問調試
經常使用方法:code
class Eleme(object): def __init__(self): self._dict = {"method": "get"} self._list = ["name", "sexy"] for key,val in self._dict.items(): setattr(self, key,val) e = Eleme() print e.method # result : get
更好的方法:orm
# -*- coding: utf-8 -*- class Eleme(object): def __init__(self): self._dict = {"method": "get"} self._list = ["name", "sexy"] def __getattr__(self, item): return self._dict[item] e = Eleme() print e.method # result : get
一個對象實例能夠有本身的屬性和方法,當咱們調用實例方法時,咱們用instance.method()來調用。能不能直接在實例自己上調用呢?相似instance()?在Python中,答案是確定的。 任何類,只須要定義一個__call__()方法,就能夠直接對實例進行調用。請看示例:對象
class CallTest(object): def __init__(self, name): self.name = name def __call__(self, arg = None): return "My name is {}. {} old".format(self.name,arg) c = CallTest("hero") print c(12) My name is hero. 12 old
#仿django orm繼承
# -*- coding: utf-8 -*- class User(object): class objects(): @classmethod def create(cls, **kwargs): key, val = kwargs.items()[0] return "Create successful.key is {key} values is {val}".format( key=key, val=val) print User.objects.create(name="Hero") # 輸出結果: Create successful.key is name values is Hero
動態語言和靜態語言最大的不一樣,就是函數和類的定義,不是編譯時定義的,而是運行時動態建立的。 比方說咱們要定義一個Hello的class,就寫一個hello.py模塊:utf-8
class Hello(object): def hello(self, name='world'): print('Hello, %s.' % name)
當Python解釋器載入hello模塊時,就會依次執行該模塊的全部語句,執行結果就是動態建立出一個Hello的class對象,測試以下:
>>> from hello import Hello >>> h = Hello() >>> h.hello() Hello, world. >>> print(type(Hello)) <class 'type'> >>> print(type(h)) <class 'hello.Hello'>
type()函數能夠查看一個類型或變量的類型,Hello是一個class,它的類型就是type,而h是一個實例,它的類型就是class Hello。
咱們說class的定義是運行時動態建立的,而建立class的方法就是使用type()函數。
type()函數既能夠返回一個對象的類型,又能夠建立出新的類型,好比,咱們能夠經過type()函數建立出Hello類,而無需經過class Hello(object)...的定義:
>>> def fn(self, name='world'): # 先定義函數 ... print('Hello, %s.' % name) ... >>> Hello = type('Hello', (object,), dict(hello=fn)) # 建立Hello class >>> h = Hello() >>> h.hello() Hello, world. >>> print(type(Hello)) <class 'type'> >>> print(type(h)) <class '__main__.Hello'>
要建立一個class對象,type()函數依次傳入3個參數:
一、class的名稱; 二、繼承的父類集合,注意Python支持多重繼承,若是隻有一個父類,別忘了tuple的單元素寫法; 三、class的方法名稱與函數綁定,這裏咱們把函數fn綁定到方法名hello上。
經過type()函數建立的類和直接寫class是徹底同樣的,由於Python解釋器遇到class定義時,僅僅是掃描一下class定義的語法,而後調用type()函數建立出class。
正常狀況下,咱們都用class Xxx...來定義類,可是,type()函數也容許咱們動態建立出類來,也就是說,動態語言自己支持運行期動態建立類,這和靜態語言有很是大的不一樣,要在靜態語言運行期建立類,必須構造源代碼字符串再調用編譯器,或者藉助一些工具生成字節碼實現,本質上都是動態編譯,會很是複雜。