Python面向對象編程

類定義

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__ 乘方

metaclass

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()
相關文章
相關標籤/搜索