class ClassName(object): """docstring for ClassName""" def __init__(self, arg): super(ClassName, self).__init__() self.arg = arg def method(self, args): pass
Python中的類也是一個對象,類與其實例擁有不一樣級別的做用域.java
當試圖經過實例訪問一個屬性時,Python會先在實例的做用域中搜索該屬性,若實例做用域中不存在該屬性則繼續搜索類做用域.python
若在類做用域中找到了該屬性,Python將把這個屬性複製一個副本(淺拷貝),加入到對象的做用域中。sql
一般咱們在類中直接定義方法, 在初始化方法中__init__
中定義並初始化屬性.數據庫
Python中沒有this參數,self是表示對象自身引用的關鍵字(即其它語言中的this).app
定義方法時須要顯式聲明self參數做爲第一個參數,使用Object.method()
調用類方法時self沒必要顯式傳遞,python將自動傳遞.框架
在類方法中訪問對象屬性或調用方法時須要顯式使用self,不然將被解釋爲訪問同名的方法局部變量(Python在訪問對象前是無需聲明的)。函數
類的私有屬性或方法以兩個下劃線__
開頭,只容許類內部訪問不容許類外訪問. 公有屬性或方法禁止以兩個下劃線開頭。this
採用兩個下劃線開頭和結尾的方法通常爲特殊方法,除非重寫這些方法不然不要佔用這些標識符。編碼
__init__
方法是類的構造函數,在生成對象時調用;設計
__del__
爲析構函數,釋放對象時使用完成清理工做
__repr__
相似java中的toString方法,用於顯示對象時將對象轉換爲可顯示的形式(通常爲字符串)。
class SubClass(BaseClass1, BaseClass2): pass
須要注意圓括號中基類的順序。再調用方法時首先調用本類方法,而後搜索基類方法。調用方法或訪問屬性時本類採用self,基類則使用括號中基類的名字指定。
Python中還提供了super()
來解決多重繼承問題,直接用類名調用父類方法在使用單繼承的時候沒問題,可是若是使用多繼承,會涉及到查找順序(MRO)、重複調用(鑽石繼承)等種種問題。super機制裏能夠保證公共父類僅被執行一次,執行的順序由__mro__
決定。
class SubClass(Baseclass): def __init__(*args): super(SubClass, self).__init__(args)
如果基類中有相同的方法名,而在子類使用時未指定,Python從左至右搜索 即方法在子類中未找到時,從左到右查找基類中是否包含方法。
class circle: radium = 0 def area(self): return math.pi * self.radium ** 2 class cylinder(circle): height = 0 def volume(self): c = circle() c.radium=1 return c.area() * self.height
「鴨子類型」是動態面嚮對象語言設計中的一個概念,即若是一個東西行走像鴨子,游泳像鴨子,進食像鴨子那它就是鴨子
即一個對象具備某一類的特徵,便可做爲該類實例來對待,沒必要強制實現接口.
Python容許重寫某些特殊方法來定義使用某些操做符
能夠經過重寫某些方法模擬字典和列表的行爲:
__setitem__
按照key爲元素賦值
__getitem__
按照key取元素
__delitem__
按照key刪除元素
__call__
容許將對象做爲函數進行調用
__len__
得到長度,調用len(obj)時即調用obj.__len__()
__iter__()
返回iterable, for-in循環會調用這個對象的next()方法進行迭代
__call__
重載函數調用,調用obj(args)
即調用obj.__call__(args)
模擬dict:
class MyDict: def __init__(self): self.data = dict() def __getitem__(self, key): return self.data.get(key) def __setitem__(self, key, val): self.data[key] = val def __delitem__(self, key): self.data.pop(key) def __iter__(self): for item in self.data: yield item def __len__(self): return len(self.data) if __name__ == '__main__': d = MyDict() # set item d['first'] = 1 d['second'] = 2 # get item print(d['first'], d['second']) # len print(len(d)) # iter for item in d: print(item) # del item del(d['first']) print(d['first'])
模擬list:
class MyList: def __init__(self): self.data = list() def __getitem__(self, key): return self.data[key] def __setitem__(self, key, val): self.data[key] = val def __delitem__(self, key): self.data.pop(key) def __iter__(self): for item in self.data: yield item def __len__(self): return len(self.data) if __name__ == '__main__': l = MyList() l.data.extend([0,0]) # set item l[0] = 1 l[1] = 2 # get item print(l[0], l[1]) # len print(len(l)) # iter for item in l: print(item) # del item del(l[0]) print(l[0])
做爲函數:
class MyFunc(): def __call__(self): print('I am callable') if __name__ == '__main__': f = MyFunc() f()
重載算術與關係運算:
__cmp__
比較運算
__add__
加運算
__sub__
減運算
__mul__
乘運算
__div__
除運算;
__mod__
求餘運算
__pow__
乘方
Python中類的類型爲"type",type()函數能夠創建一個"type"類型對象即一個類。type函數有三個參數,class的名稱,基類元組和成員名-成員對象字典。
def func(args): print("fuck"); ClassObj = type('ClassName',(object,),dict(method1=func)) print(ClassObj) print(dir(ClassObj))
Python的class語法其實是調用type()函數進行動態編譯。元類metaclass是進行類動態建立與修改的另外一種方式。
def func(args): pass class aMetaclass(type): def __new__(classObj, className, bases, attrs): attrs.update(dict(aMethod=func)); return type.__new__(classObj,className,bases,attrs) class aClass(object, metaclass=aMetaclass): pass obj = aClass(); print(dir(obj))
一般類的建立由type()
或type.__new__()
完成,在指定了一個類的metaclass參數以後,該類對象的建立將交由metaclass來完成。metaclass.__new__
將會攔截類的建立,進行處理後調用type.__new__
進行建立。
相對於使用type()動態建立類,metaclass可使用繼承等OOP機制且做爲類其功能比函數更爲強大。metaclass擁有其它成員和類動態添加成員機制,而函數只能以硬編碼編制建立邏輯。
示例,使用metaclass編寫ORM:
ORM(Object Relational Mapping,對象-關係映射)把關係數據庫的一行映射爲一個對象,也就是一個類對應一個表,這樣,寫代碼更簡單,不用直接操做SQL語句。要編寫一個ORM框架,全部的類都只能動態定義,由於只有使用者才能根據表的結構定義出對應的類來。
tinyORM中首先定義了表中域的類型,而後定義Model類執行建立數據表的邏輯,類Users定義數據表'users'。
Users類建立時首先封裝建立類的參數,而後封裝Model的建立參數執行基類Model的建立。Model建立過程被ModelMetaclass.__new__
攔截,傳入的name參數爲'users'(__new__
只處理Model派生類的創建,對Model類的創建不進行處理)。
__new__
將一個成員映射爲一列,並存入__mapping__
中和保存數據表名字的__table__
一塊兒添加到Users的屬性中。__new__
返回修改後的類, 執行Model.__init__
進行初始化。
#tinyORM.py #Define field types class Field(object): def __init__(self, name, column_type): self.name = name self.column_type = column_type def __repr__(self): return '<%s:%s>' % (self.__class__.__name__, self.name) class StringField(Field): def __init__(self, name): super(StringField, self).__init__(name, 'varchar(100)') class IntegerField(Field): def __init__(self, name): super(IntegerField, self).__init__(name, 'bigint') #define Model class ModelMetaclass(type): def __new__(cls, name, bases, attrs): if name=='Model': return type.__new__(cls, name, bases, attrs) print('Found model: %s' % name) mappings = dict() for k, v in attrs.items(): if isinstance(v, Field): print('Found mapping: %s ==> %s' % (k, v)) mappings[k] = v for k in mappings.keys(): attrs.pop(k) attrs['__mappings__'] = mappings # save mapping of attribute-column attrs['__table__'] = name # name the table after the class name return type.__new__(cls, name, bases, attrs) class Model(dict, metaclass=ModelMetaclass): def __init__(self, **kw): super(Model, self).__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value): self[key] = value def save(self): fields = [] params = [] args = [] for k, v in self.__mappings__.items(): fields.append(v.name) params.append('?') args.append(getattr(self, k, None)) sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params)) print('SQL: %s' % sql) print('ARGS: %s' % str(args)) #send sql and args to database #The end of ORM, the following code should be created by ORM's users. #define table 'user' and its structure class Users(Model): # 定義類的屬性到列的映射: id = IntegerField('id') name = StringField('username') password = StringField('password') def test() u = Users(id=2333, name='username', password='password') u.save() test()