Python 學(xué)習(xí)筆記7 - 面向?qū)ο蟾呒壘幊?/h1>

slots —— 限制實例能添加的屬性

我們可以給該實例綁定任何屬性和方法

class Student(object):
    pass

s = Student()

給實例綁定屬性

s.name = 'Michael'
print(s.name)

給實例綁定方法

from types import MethodType

def set_age(self, age):
    self.age = age

s.set_age = MethodType(set_age, s)
s.set_age(25)
s.age

給class綁定方法东且,則對該類的所有實例都有該方法

def set_score(self, score):
    self.score = score

Student.set_score = set_score

使用slots

試圖綁定不在允許列表里的屬性將得到 AttributeError 的錯誤

class Student(object):
    # 用tuple定義允許綁定的屬性名稱
    __slots__ = ('name', 'age') 

__slots__ 定義的屬性僅對當(dāng)前類實例起作用义钉,對繼承的子類是不起作用的

如果在子類中也定義 __slots__ ,子類實例允許定義的屬性就是自身的 __slots__ 加上父類的 __slots__

@property —— 把一個方法變成屬性調(diào)用

class Student(object):

    @property
    def score(self):
        return self._score

    # @property本身又創(chuàng)建了另一個裝飾器@score.setter典唇,負(fù)責(zé)把一個setter方法變成屬性賦值
    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

只定義getter方法,不定義setter方法就是一個只讀屬性

class Student(object):

    # birth 是可讀寫屬性
    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    # age 是只讀屬性
    @property
    def age(self):
        return 2015 - self._birth

多重繼承

在設(shè)計類的繼承關(guān)系時胯府,通常介衔,主線都是單一繼承下來的,例如骂因,Ostrich繼承自Bird炎咖。但是,如果需要“混入”額外的功能寒波,通過多重繼承就可以實現(xiàn)乘盼,比如,讓Ostrich除了繼承自Bird外影所,再同時繼承Runnable蹦肴。這種設(shè)計通常稱之為MixIn。

為了更好地看出繼承關(guān)系猴娩,我們把Runnable和Flyable改為RunnableMixIn和FlyableMixIn

定制類

str() & repr() —— 打印實例的信息

__str__() 返回用戶看到的字符串

class Student(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'Student object (name: %s)' % self.name
        
print(Student('Michael')) ==> Student object (name: Michael)

__repr__() 返回程序開發(fā)者看到的字符串阴幌,即 __repr__() 是為調(diào)試服務(wù)的

class Student(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'Student object (name: %s)' % self.name

    # 通常 __str__() 和 __repr__() 代碼都是一樣的,所以卷中,用偷懶的寫法:
    __repr__ = __str__

iter() & next() —— 使一個對象可迭代

__iter__() 方法矛双,該方法返回一個迭代對象,然后蟆豫,Python的for循環(huán)就會不斷調(diào)用該迭代對象的 __next__() 方法拿到循環(huán)的下一個值

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        # 返回實例本身议忽,因為實例實現(xiàn)了 __next__() 方法,所以是個可迭代對象
        return self
        
    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 100000:
            raise StopIteration()
        return self.a

getitem() —— 使一個對象能像list那樣按照下標(biāo)取出元素

class Fib(object):
    def __getitem__(self, n):
        # n是索引
        if isinstance(n, int):
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        # n是切片
        # 這里沒有對step參數(shù)作處理十减,也沒有對負(fù)數(shù)作處理
        if isinstance(n, slice):
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x > start:
                    L.append(a)
                a, b = b, a + b
            return L
        
f = Fib()
f[3]
print(f[0:5])
print(f[:10])

如果把對象看成 dict 栈幸,__getitem__() 的參數(shù)也可能是一個可以作 key 的 object ,例如str

與之對應(yīng)的是 __setitem__() 方法帮辟,把對象視作list或dict來對集合賦值

還有一個 __delitem__() 方法速址,用于刪除某個元素

getattr() 動態(tài)返回一個屬性

當(dāng)調(diào)用不存在的屬性時,比如score由驹,Python解釋器會試圖調(diào)用getattr(self, 'score')來嘗試獲得屬性芍锚,這樣,我們就有機(jī)會返回score的值

class Student(object):

    def __init__(self):
        self.name = 'Michael'

    def __getattr__(self, attr):
        if attr=='score':
            return 99
        
        # __getattr__默認(rèn)返回就是None
        # 要讓class只響應(yīng)特定的幾個屬性,我們就要按照約定并炮,拋出AttributeError的錯誤
        raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)

call —— 調(diào)用實例本身

對實例進(jìn)行直接調(diào)用就好比對一個函數(shù)進(jìn)行調(diào)用一樣默刚,所以你完全可以把對象看成函數(shù),把函數(shù)看成對象逃魄,因為這兩者之間本來就沒啥根本的區(qū)別荤西。

class Student(object):
    def __init__(self, name):
        self.name = name

    # __call__()還可以定義參數(shù)
    def __call__(self):
        print('My name is %s.' % self.name)

s = Student('Michael')
s() ==> My name is Michael.

判斷一個對象是否能被調(diào)用,能被調(diào)用的對象就是一個Callable對象嗅钻,比如函數(shù)和我們上面定義的帶有call()的類實例

callable(Student()) ==> True
callable(max) ==> True
callable([1, 2, 3]) ==> False
callable(None) ==> False
callable('str') ==> False

其他特殊的方法名見:special-method-names

枚舉類

from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

這樣我們就獲得了Month類型的枚舉類皂冰,可以直接使用Month.Jan來引用一個常量,或者枚舉它的所有成員

for name, member in Month.__members__.items():
    # value屬性則是自動賦給成員的int常量养篓,默認(rèn)從1開始計數(shù)
    print(name, '=>', member, ',', member.value)

如果需要更精確地控制枚舉類型秃流,可以從Enum派生出自定義類:

from enum import Enum, unique

# @unique裝飾器可以幫助我們檢查保證沒有重復(fù)值
@unique
class Weekday(Enum):
    Sun = 0 # Sun的value被設(shè)定為0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

訪問這些枚舉類型的方法:

print(Weekday.Tue)

day1 = Weekday.Tue
print(day1)

print(Weekday['Tue'])

print(Weekday(2))

print(Weekday.Tue.value) ==> 2

使用元類

type() —— 動態(tài)創(chuàng)建類

假設(shè)有一 hello.py 模塊

class Hello(object):
    def hello(self, name='world'):
        print('Hello, %s.' % name)
from hello import Hello

h = Hello()
h.hello() ==> Hello, world.

# Hello是一個class,它的類型就是type
print(type(Hello)) ==> <class 'type'>
# h是一個實例柳弄,它的類型就是class Hello
print(type(h)) ==> <class 'hello.Hello'>

type() 函數(shù)既可以返回一個對象的類型舶胀,又可以創(chuàng)建出新的類型

比如,我們可以通過type()函數(shù)創(chuàng)建出Hello類碧注,而無需通過class Hello(object)...的定義:

# 先定義函數(shù)
def fn(self, name='world'): 
     print('Hello, %s.' % name)


# 參數(shù):
# 1. class的名稱
# 2. 繼承的父類集合嚣伐,注意Python支持多重繼承,如果只有一個父類萍丐,別忘了tuple的單元素寫法
# 3. class的方法名稱與函數(shù)綁定轩端,這里我們把函數(shù)fn綁定到方法名hello上
Hello = type('Hello', (object,), dict(hello=fn)) # 創(chuàng)建Hello class


h = Hello()
h.hello() ==> Hello, world.

print(type(Hello)) ==> <class 'type'>
print(type(h)) ==> <class '__main__.Hello'>

type() 函數(shù)也允許我們動態(tài)創(chuàng)建出類來,也就是說逝变,動態(tài)語言本身支持運行期動態(tài)創(chuàng)建類

metaclass —— 控制類的創(chuàng)建行為(缺)

先定義metaclass基茵,就可以創(chuàng)建類,最后創(chuàng)建實例

所以壳影,metaclass允許你創(chuàng)建類或者修改類拱层。換句話說,你可以把類看成是metaclass創(chuàng)建出來的“實例”

一個簡單的例子:

# 這個metaclass可以給我們自定義的MyList增加一個add方法
# metaclass是類的模板宴咧,所以必須從`type`類型派生:
class ListMetaclass(type):
    # __new__()方法參數(shù)
    # 1. 當(dāng)前準(zhǔn)備創(chuàng)建的類的對象
    # 2. 類的名字
    # 3. 類繼承的父類集合
    # 4. 類的方法集合
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)
# 指示Python解釋器在創(chuàng)建MyList時根灯,要通過ListMetaclass.__new__()來創(chuàng)建
class MyList(list, metaclass=ListMetaclass):
    pass

動態(tài)修改的意義在于:總會遇到需要通過metaclass修改類定義的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個濱河市掺栅,隨后出現(xiàn)的幾起案子烙肺,更是在濱河造成了極大的恐慌,老刑警劉巖氧卧,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桃笙,死亡現(xiàn)場離奇詭異,居然都是意外死亡假抄,警方通過查閱死者的電腦和手機(jī)怎栽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宿饱,“玉大人熏瞄,你說我怎么就攤上這事∶裕” “怎么了强饮?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長为黎。 經(jīng)常有香客問我邮丰,道長,這世上最難降的妖魔是什么铭乾? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任剪廉,我火速辦了婚禮,結(jié)果婚禮上炕檩,老公的妹妹穿的比我還像新娘斗蒋。我一直安慰自己,他們只是感情好笛质,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布泉沾。 她就那樣靜靜地躺著,像睡著了一般妇押。 火紅的嫁衣襯著肌膚如雪跷究。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天敲霍,我揣著相機(jī)與錄音俊马,去河邊找鬼。 笑死色冀,一個胖子當(dāng)著我的面吹牛潭袱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锋恬,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼屯换,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了与学?” 一聲冷哼從身側(cè)響起彤悔,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎索守,沒想到半個月后晕窑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡卵佛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年杨赤,在試婚紗的時候發(fā)現(xiàn)自己被綠了敞斋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡疾牲,死狀恐怖植捎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阳柔,我是刑警寧澤焰枢,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站舌剂,受9級特大地震影響济锄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜霍转,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一荐绝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧避消,春花似錦很泊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至均驶,卻和暖如春昏兆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背妇穴。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工爬虱, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腾它。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓跑筝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瞒滴。 傳聞我的和親對象是個殘疾皇子曲梗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容