python特殊方法(魔術(shù)方法)

例子

  • 用于print的__str__方法
  • 用于len的__len__方法
  • 用于cmp的__cmp__方法

特點(diǎn)

  • 特殊方法定義在class中
  • 不需要直接調(diào)用
  • python的某些函數(shù)或操作符會(huì)調(diào)用相應(yīng)的特殊方法

用法

  • 只需要編寫(xiě)用到的特殊方法
  • 有關(guān)聯(lián)性的特殊方法必須一并實(shí)現(xiàn)(或不實(shí)現(xiàn))如 __getattr__ __setattr__ __delattr__

__str__
把類的實(shí)例變成str。值得注意的是__str__顯示給用戶,與之類似的__repr__顯示給開(kāi)發(fā)人員??梢杂猛祽械姆椒ǘx__repr__ = __str__。

class Person(object):

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):

    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

    def __str__(self):
        return '(student: %s, %s, %s)' % (self.name, self.gender, self.score)

s = Student('Bob', 'male', 88)
print s

__cmp__
對(duì)于int、str等類型數(shù)據(jù),排序可以調(diào)用python默認(rèn)的cmp函數(shù)。對(duì)于自己實(shí)現(xiàn)的類,sorted函數(shù)的參數(shù)要實(shí)現(xiàn)__cmp__()。例如:

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score

    def __str__(self):
        return '(%s: %s)' % (self.name, self.score)

    __repr__ = __str__

        
    def __cmp__(self, s):
        if self.score == s.score:
            return cmp(self.name, s.name)
        return -cmp(self.score, s.score)
            

L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
print sorted(L)

__len__
返回個(gè)數(shù)。

任務(wù)
斐波那契數(shù)列是由 0, 1, 1, 2, 3, 5, 8...構(gòu)成。
請(qǐng)編寫(xiě)一個(gè)Fib類,F(xiàn)ib(10)表示數(shù)列的前10個(gè)元素,print Fib(10) 可以打印出數(shù)列的前 10 個(gè)元素,len(Fib(10))可以正確返回?cái)?shù)列的個(gè)數(shù)10。

class Fib(object):
    def __init__(self, num):
        a, b, L = 0, 1, []
        for i in range(num):
            L.append(a)
            a, b = b, a + b
        self.L = L
    def __str__(self):
        # return '['+','.join(map(str, self.L))+']'
        str(self.L)
    def __len__(self):
        return len(self.L)

f = Fib(10)
print f
print len(f)

數(shù)學(xué)運(yùn)算
包括__add__, __sub__, __mul__, __div__等。例子:有理數(shù)(分?jǐn)?shù))

def gcd(a, b):
    while b:
        a, b = b, a % b
    return a

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q
    def __add__(self, r):
        return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
    def __sub__(self, r):
        return Rational(self.p * r.q - self.q * r.p, self.q * r.q)
    def __mul__(self, r):
        return Rational(self.p * r.p, self.q * r.q)
    def __div__(self, r):
        return Rational(self.p * r.q, self.q * r.p)
    def __str__(self):
        g = gcd(self.p, self.q)
        return '%s/%s' % (self.p / g, self.q / g)
    __repr__ = __str__

r1 = Rational(1, 2)
r2 = Rational(1, 4)
print r1 + r2
print r1 - r2
print r1 * r2
print r1 / r2

__int__和__float__
輸出其整數(shù)(浮點(diǎn)數(shù))類型。
例子:

class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q

    def __int__(self):
        return self.p // self.q

    def __float__(self):
        # return 1. * self.p / self.q
        return float(self.p) / self.q

print float(Rational(7, 2))
print float(Rational(1, 3))

@property
這是最神奇的一個(gè)方法。
考察 Student 類:

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

當(dāng)我們想要修改一個(gè) Student 的 scroe 屬性時(shí),可以這么寫(xiě):

s = Student('Bob', 59)
s.score = 60

但是也可以這么寫(xiě):
s.score = 1000
顯然,直接給屬性賦值無(wú)法檢查分?jǐn)?shù)的有效性。

如果利用兩個(gè)方法:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    def get_score(self):
        return self.__score
    def set_score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

這樣一來(lái),s.set_score(1000) 就會(huì)報(bào)錯(cuò)。

這種使用 get/set 方法來(lái)封裝對(duì)一個(gè)屬性的訪問(wèn)在許多面向?qū)ο缶幊痰恼Z(yǔ)言中都很常見(jiàn)。

但是寫(xiě) s.get_score() 和 s.set_score() 沒(méi)有直接寫(xiě) s.score 來(lái)得直接。

有沒(méi)有兩全其美的方法?----有。

因?yàn)镻ython支持高階函數(shù),在函數(shù)式編程中我們介紹了裝飾器函數(shù),可以用裝飾器函數(shù)把 get/set 方法“裝飾”成屬性調(diào)用:

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

注意: 第一個(gè)score(self)是get方法,用@property裝飾,第二個(gè)score(self, score)是set方法,用@score.setter裝飾,@score.setter是前一個(gè)@property裝飾后的副產(chǎn)品。

現(xiàn)在,就可以像使用屬性一樣設(shè)置score了:

>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
ValueError: invalid score

說(shuō)明對(duì) score 賦值實(shí)際調(diào)用的是 set方法。

任務(wù)
如果沒(méi)有定義set方法,就不能對(duì)“屬性”賦值,這時(shí),就可以創(chuàng)建一個(gè)只讀“屬性”。
請(qǐng)給Student類加一個(gè)grade屬性,根據(jù) score 計(jì)算 A(>=80)、B、C(<60)。

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.__score = score

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

    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

    @property
    def grade(self):
        if self.__score >= 80:
            return "A"
        if self.__score < 60:
            return "C"
        return "B"

s = Student('Bob', 59)
print s.grade

s.score = 60
print s.grade

__slots__()
限制添加屬性。__slots__()中添寫(xiě)允許的屬性列表。比如:

class Student(object):
    __slots__ = ('name', 'gender', 'score')
    def __init__(self, name, gender, score):
        self.name = name
        self.gender = gender
        self.score = score

操作:

>>> s = Student('Bob', 'male', 59)
>>> s.name = 'Tim' # OK
>>> s.score = 99 # OK
>>> s.grade = 'A'
Traceback (most recent call last):
  ...
AttributeError: 'Student' object has no attribute 'grade'

任務(wù)
假設(shè)Person類通過(guò)slots定義了name和gender,請(qǐng)?jiān)谂缮怱tudent中通過(guò)slots繼續(xù)添加score的定義,使Student類可以實(shí)現(xiàn)name、gender和score 3個(gè)屬性。

class Person(object):

    __slots__ = ('name', 'gender')

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):

    __slots__ = ('score')

    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 要點(diǎn): 函數(shù)式編程:注意不是“函數(shù)編程”,多了一個(gè)“式” 模塊:如何使用模塊 面向?qū)ο缶幊蹋好嫦驅(qū)ο蟮母拍?、屬性?..
    victorsungo閱讀 1,707評(píng)論 0 6
  • 定義類并創(chuàng)建實(shí)例 在Python中,類通過(guò) class 關(guān)鍵字定義。以 Person 為例,定義一個(gè)Person類...
    績(jī)重KF閱讀 4,123評(píng)論 0 13
  • Python進(jìn)階框架 希望大家喜歡,點(diǎn)贊哦首先感謝廖雪峰老師對(duì)于該課程的講解 一、函數(shù)式編程 1.1 函數(shù)式編程簡(jiǎn)...
    Gaolex閱讀 6,037評(píng)論 6 53
  • 外面有放炮的聲音,應(yīng)該是放煙花吧。昨晚不注意手機(jī)直接摔下來(lái),外屏整個(gè)碎了。三十號(hào)那天出發(fā)前往蘭州,凌晨才到,同行的...
    一只渴望擁抱的刺猬閱讀 297評(píng)論 0 0
  • 命令行方式: 顯示隱藏文件: 不顯示隱藏文件: 快捷鍵方式: 用快捷鍵會(huì)更方便: 就可以神奇的來(lái)回切換隱藏不隱藏了。
    葛朋1990閱讀 318評(píng)論 0 1

友情鏈接更多精彩內(nèi)容