python中的元类_python中的元类
類也是對象,但是類有創建對象的能力
動態創建一個類:
classmonkey():defbanana(self):print 'banana!'
defapple(self):print 'i want apple!'monkey_child= type('monkey_child', (monkey,), {'apple': apple})
hasattr(monkey,'apple')
false
hasattr(monkey_child,'apple')
true
type的語法:type(類名,父類的元組(針對繼承的情況,可以為空),包含屬性的字典(名稱和值))
創建類的就是元類,type是所有類的元類,類屬性__class__可以看到元類是什么
>>> a=1
>>>type(a)
>>> type(a.__class__)
創建一個類的過程:搜索__metaclass__是否有指定,否則搜索父類中的__metaclass__,最終應該找到type或是type的子類
由于python中鴨子類型的概念,__metaclass__實際上不一定是一個類,也可以是一個函數
defupper_attr(future_class_name, future_class_parents, future_class_attr):
attrs= ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
uppercase_attr= dict((name.upper(), value) for name, value inattrs)returntype(future_class_name, future_class_parents, uppercase_attr)classFoo(object):__metaclass__ =upper_attr
bar= 'aip'
printFoo.BAR>>>'aip'
在Python3中我們在定義類時通過傳入metaclass的參數來設定,如上代碼就應該寫成class Foo(metaclass=upper_attr)。
metaclass可以是一個類
classUpperAttrMetaclass(type):def __new__(cls, name, bases, dct):
attrs= ((name, value) for name, value in dct.items() if not name.startswith('__')
uppercase_attr= dict((name.upper(), value) for name, value inattrs)return type.__new__(cls, name, bases, uppercase_attr)
__new__在__init__之前被調用,用于創建和返回對象,由__new__是一個類方法,我們需要傳入實例對象cls。
為了表明繼承關系,以上代碼可以寫成
classUpperAttrMetaclass(type):def __new__(cls, name, bases, dct):
attrs= ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr= dict((name.upper(), value) for name, value inattrs)return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
為什么要用metaclass類而不是函數?
由于__metaclass__可以接受任何可調用的對象,那為何還要使用類呢,因為很顯然使用類會更加復雜啊?這里有好幾個原因:
1) 意圖會更加清晰。當你讀到UpperAttrMetaclass(type)時,你知道接下來要發生什么。
2) 你可以使用OOP編程。元類可以從元類中繼承而來,改寫父類的方法。元類甚至還可以使用元類。
3) 你可以把代碼組織的更好。當你使用元類的時候肯定不會是像我上面舉的這種簡單場景,通常都是針對比較復雜的問題。將多個方法歸總到一個類中會很有幫助,也會使得代碼更容易閱讀。
4) 你可以使用__new__, __init__以及__call__這樣的特殊方法。它們能幫你處理不同的任務。就算通常你可以把所有的東西都在__new__里處理掉,有些人還是覺得用__init__更舒服些。
根據http://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p07_calling_method_on_parent_class.html 可以知道,我們應該在繼承并改寫的代碼中盡量使用super訪問父類,而不是直接訪問父類。
classUpperAttrMetaclass(type):def __new__(cls, name, bases, dct):
attrs= ((name, value) for name, value in dct.items() if not name.startswith('__'))
uppercase_attr= dict((name.upper(), value) for name, value inattrs)return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
參考:http://blog.jobbole.com/21351/
其中有一個Django的ORM的例子,學習之
總結
以上是生活随笔為你收集整理的python中的元类_python中的元类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python爬取晋江_[Arcpy] 爬
- 下一篇: 求一个关于流星雨的个性签名!