摘自謬雪峰https://www.liaoxuefeng.com/wiki/1016959663602400/1017501655757856
給一個‘類’綁定屬性和方法
給實例綁定屬性和方法
>>> s = Student()
>>> s.name = 'Michael' # 動態給實例綁定一個屬性
>>> def set_age(self, age): # 定義一個函數作為實例方法
... self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 給實例綁定一個方法
>>> s.set_age(25) # 調用實例方法
>>> s.age # 測試結果
25
給一個類綁定方法
>>> def set_score(self, score):
... self.score = score
...
>>> Student.set_score = set_score
通常情況下,上面的set_score方法可以直接定義在class中,但動態綁定允許我們在程序運行的過程中動態給class加上功能,這在靜態語言中很難實現。
限制屬性的綁定__slots__
為了達到限制的目的,Python允許在定義class的時候,定義一個特殊的__slots__變量,來限制該class實例能添加的屬性:
class Student(object):
__slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱
>>> s.score = 99 # 綁定屬性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
由於'score'沒有被放到__slots__中,所以不能綁定score屬性,試圖綁定score將得到AttributeError的錯誤。
使用__slots__要注意,__slots__定義的屬性僅對當前類實例起作用,對繼承的子類是不起作用的:
class GraduateStudent(Student):
... pass
...g = GraduateStudent()
g.score = 9999
除非在子類中也定義__slots__,這樣,子類實例允許定義的屬性就是自身的__slots__加上父類的__slots__。
@property用來在類中定義規則,並且外部簡單調用
@property用來在類中定義規則,並且外部簡單調用,即外部實例話后,不用調用方法來設置屬性,而是直接設置屬性
class Student(object):
@property
def score(self):
return self._score
@score.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
結果:
>>> s = Student()
>>> s.score = 60 # OK,實際轉化為s.set_score(60)
>>> s.score # OK,實際轉化為s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
多重繼承
class Dog(Mammal, Runnable):
pass
類中的默認方法
getattr
只有在沒有找到屬性的情況下,才調用__getattr__,已有的屬性,比如name,不會在__getattr__中查找。
class Student(object):
def __init__(self):
self.name = 'Michael'
def __getattr__(self, attr):
if attr=='score':
return 99
else:
raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)
__call__調用實例本身
class Student(object):
def init(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
調用方式如下:
s = Student('Michael')
s() # self參數不要傳入
My name is Michael.
callable()
通過callable()函數,我們就可以判斷一個對象是否是“可調用”對象。
callable(Student())
Truecallable(max)
Truecallable([1, 2, 3])
Falsecallable(None)
Falsecallable('str')
False
常量的定義——枚舉類Enum
from enum import Enum
Month = Enum('Monster', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
#類似於字典的鍵值對的形式
print(Month.Jan)#返回Monster.Jan
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
#結果如下
'''Jan => Monster.Jan , 1
Feb => Monster.Feb , 2
Mar => Monster.Mar , 3
Apr => Monster.Apr , 4
May => Monster.May , 5
Jun => Monster.Jun , 6
Jul => Monster.Jul , 7
Aug => Monster.Aug , 8
Sep => Monster.Sep , 9
Oct => Monster.Oct , 10
Nov => Monster.Nov , 11'''
另一種方法,可見,既可以用成員名稱引用枚舉常量,又可以直接根據value的值獲得枚舉常量。
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被設定為0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
@unique裝飾器可以幫助我們檢查保證沒有重復值。
訪問這些枚舉類型可以有若干種方法:
day1 = Weekday.Mon
print(day1)
Weekday.Monprint(Weekday.Tue)
Weekday.Tueprint(Weekday['Tue'])
Weekday.Tueprint(Weekday.Tue.value)
2print(day1 == Weekday.Mon)
Trueprint(day1 == Weekday.Tue)
Falseprint(Weekday(1))
Weekday.Monprint(day1 == Weekday(1))
TrueWeekday(7)
Traceback (most recent call last):
...
ValueError: 7 is not a valid Weekdayfor name, member in Weekday.members.items():
... print(name, '=>', member)
...
Sun => Weekday.Sun
Mon => Weekday.Mon
Tue => Weekday.Tue
Wed => Weekday.Wed
Thu => Weekday.Thu
Fri => Weekday.Fri
Sat => Weekday.Sat