python學習第十七天 --定製類

何爲定製類?

Python的class容許定義許多特殊方法,可讓咱們很是方便地生成特定的類。在類中應用或者重寫python的特殊方法,獲得的類,就是定製類。python

你們都知道print的用法。見下面例子shell

>>> lst = [2,3,4]
>>> print lst
[2, 3, 4]
>>> class Animal(object):
    pass

>>> a = Animal()
>>> print a
<__main__.Animal object at 0x01E6E990>

爲何print都能識別出lst和p的數據類型呢?app

當咱們執行以下代碼的時候,就知道爲何了?函數

>>> print lst.__str__
<method-wrapper '__str__' of list object at 0x01E641E8>
>>> print a.__str__
<method-wrapper '__str__' of Animal object at 0x01E6E990>

__str__特殊方法,能識別出每個數據類型。若是但願類的實例print a 打印出 ‘object of Animal class’.怎麼辦?從新定義__str__方法。spa

>>> class Animal(object):
    def __str__(self):
        return 'object of Animal class'

    
>>> a = Animal()
>>> print a
object of Animal class

可是有時候發現直接敲code

>>> a
<__main__.Animal object at 0x01E6E990>

__str__不會被調用。由於當直接敲a這行代碼的時候,直接調用的並非__str__.而是__repr__.對象

>>> class Animal(object):
    def __str__(self):
        return 'object of Animal class'
    __repr__ = __str__ //偷懶一下

    
>>> a = Animal()
>>> a
object of Animal class

python的特殊方法不少,這裏就不作一一介紹。下面主要介紹 __slots__,__call__,@property用法。blog

__slots__

python是一個動態語言,任何實例能夠再運行期間都能動態添加實例的屬性。可是有時候,想限制實例的添加屬性,就使用__slot__方法。見下面例子:繼承

>>> class Person(object):
    __slots__ = ('name','age')//限制只有name和age的屬性
    def __init__(self,name,age):
        self.name = name
        self.age = age

        
>>> p = Person('zhangsan',25)
>>> p.age
25
>>> p.name
'zhangsan'
>>> p.gender ='man'//直接動態賦屬性gender,會出現錯誤

Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    p.gender ='man'
AttributeError: 'Person' object has no attribute 'gender'

__slot__目的是限制當前類所能擁有的屬性。因此在繼承的環境下,子類不受影響。get

>>> class Student(Person):
    pass

>>> s = Student('zhangsan',26)
>>> s.age
26
>>> s.name
'zhangsan'
>>> s.gender = 'man'//能夠動態添加屬性
>>> s.gender
'man'

因此子類Student若是想本身限制添加屬性的話,也要經過__slots__來控制。

__call__

一個類的實例能夠變成一個可調用的對象,只須要實現一個特殊的方法__call__就能夠了。

接下來咱們把Student類變成一個可調用的對象:

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

        
>>> class Student(Person):
    def __init__(self,name,score):
        self.name = name
        self.score = score
    def __call__(self,age):
        print 'my name is %s'% self.name
        print 'my age is %d'% age

        
>>> s = Student('lixi',89)
>>> s(25)
my name is lixi
my age is 25

有時候你會發現s(25)乍一眼感受不出來是一個函數仍是對象的實例。python語言函數和對象的實例不是區分的很明顯。

@property

上述的class Student中,當修改s實例的score值時,

>>> s.score = 89
>>> s.score = 9999

可是這樣沒法檢查s實例的分數有效性。目前只能這樣作:

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

>>> s = Student('wangwu',89)
>>> s.set_score(89)
>>> s.set_score(9999) //非法值,ValueError

Traceback (most recent call last):
  File "<pyshell#75>", line 1, in <module>
    s.set_score(9999)
  File "<pyshell#71>", line 7, in set_score
    raise ValueError('invalid score')
ValueError: invalid score

有時候以爲寫s.set_score和s.get_score沒有直接寫s.score那麼直接。有沒有其餘辦法?既能直接的s.score又能檢查score的有效性?python提供@property高階函數這樣功能需求的裝飾器。

>>> 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

>>> s = Student('liunx',98)
>>> s.score = 89
>>> s.score = 9999

Traceback (most recent call last):
  File "<pyshell#82>", line 1, in <module>
    s.score = 9999
  File "<pyshell#79>", line 12, in score
    raise ValueError('invalid score')
ValueError: invalid score

 

小結:

特殊方法:

1.任何數據實例都有特殊方法

2.特殊方法定義在class中

3.不須要直接調用

4.python的某些方法或者函數會直接調用數據實例的特殊方法

實現特殊方法:

1.從新編寫用到的特殊方法

2.若是從新一些特殊方法,有些關聯的特殊方法也要一併實現。例如:__setattr__,__getattr__,__delattr__

相關文章
相關標籤/搜索