運(yùn)算符重載的概念如下:
運(yùn)算符重載讓類攔截常規(guī)的Python運(yùn)算;
類可重載所有Python表達(dá)式運(yùn)算符;
類也可重載打印、函數(shù)調(diào)用、屬性點(diǎn)號(hào)運(yùn)算等內(nèi)置運(yùn)算;
重載是類實(shí)例的行為想內(nèi)置類型;
重載是通過提供特殊名稱的類方法來實(shí)現(xiàn)的;
方法 | 重載 | 調(diào)用 |
---|---|---|
__init__ | 構(gòu)造函數(shù) | 對(duì)象建立:X = Class(args) |
__del__ | 解析函數(shù) | X對(duì)象收回 |
__add__ | 運(yùn)算符+ | 如果沒有__iadd__,X+Y,X+=Y |
__or__ | 運(yùn)算符或 | 如果沒有__ior__ |
__repr__,__str__ | 打印、轉(zhuǎn)換 | print(X)、repr(X)、str(X) |
__call__ | 函數(shù)調(diào)用 | X(args, *kwargs) |
__getattr__ | 點(diǎn)號(hào)運(yùn)算 | X.undefined |
__setattr__ | 屬性賦值語句 | X.any = value |
__delattr__ | 屬性刪除 | del X.any |
__getattribute__ | 屬性獲取 | X.any |
__getitem__ | 索引運(yùn)算 | X[key],X[i:j],沒__iter__時(shí)的for循環(huán)和其他迭代器 |
__setitem__ | 索引賦值語句 | X[key]=value,X[i:k]=sequence |
__delitem__ | 索引和分片刪除 | del X[key], del X[i:j] |
__len__ | 長(zhǎng)度 | len(X),如果沒有__bool__,真值測(cè)試 |
__bool__ | 布爾測(cè)試 | bool(X),真測(cè)試 |
__lt__,__gt__,__le__,__ge__,__eq__,__ne__ | 特定的比較 | XY…,x> |
__radd__ | 右側(cè)加法 | Other + X |
__iadd__ | 增強(qiáng)的加法 | X += Y |
__iter__,__next__ | 迭代環(huán)境 | I=iter(X),next(I) |
__contains__ | 成員關(guān)系測(cè)試 | item in X(任何可迭代對(duì)象) |
__index__ | 整數(shù)值 | hex(X),bin(X),oct(X),o[X],O[X:] |
__enter__,__exit__ | 環(huán)境管理器 | with obj as var: |
__get__,__set__,__delete__ | 描述符屬性 | X.attr,X.attr=Value,del X.attr |
__new__ | 創(chuàng)建 | 在__init__之前創(chuàng)建對(duì)象 |
所有重載方法的名稱前后都有兩個(gè)下劃線字符,以便把同類中定義的變量名區(qū)別開來。
>>> class Number:
... def __init__(self, start):
... self.data = start
... def __sub__(self, other):
... return Number(self.data - other)
...
>>> X = Number(5)
>>> Y = X - 2
>>> Y
<__main__.Number object at 0x10224d550>
>>> Y.data
3
基本索引
>>> class Index:
... def __getitem__(self, item):
... return item ** 2
...
>>>
>>> for i in range(5):
... I = Index()
... print(I[i], end=' ')
...
0 1 4 9 16
切片索引
>>> class Index:
... data = [5, 6, 7, 8, 9]
... def __getitem__(self, item):
... print('getitem: ', item)
... return self.data[item]
... def __setitem__(self, key, value):
... self.data[key] = value
...
>>> X = Index()
>>> print(X[1:4])
getitem: slice(1, 4, None)
[6, 7, 8]
>>> X[1:4] = (1, 1, 1)
>>> print(X[1:4])
getitem: slice(1, 4, None)
[1, 1, 1]
如果重載了這個(gè)方法,for循環(huán)每次循環(huán)時(shí)都會(huì)調(diào)用類的getitem方法;
>>> class stepper:
... def __getitem__(self, item):
... return self.data[item].upper()
...
>>>
>>> X = stepper()
>>> X.data = 'ansheng'
>>> for item in X:
... print(item)
...
A
N
S
H
E
N
G
>>> class Squares:
... def __init__(self, start, stop):
... self.value = start - 1
... self.stop = stop
... def __iter__(self):
... return self
... def __next__(self):
... if self.value == self.stop:
... raise StopIteration
... self.value += 1
... return self.value ** 2
...
>>> for i in Squares(1, 5):
... print(i)
...
1
4
9
16
25
class Iters:
def __init__(self, value):
self.data = value
def __getitem__(self, item):
print('get[%s]' % item, end='')
return self.data[item]
def __iter__(self):
print('iter>==', end='')
self.ix = 0
return self
def __next__(self):
print('next:', end='')
if self.ix == len(self.data): raise StopIteration
item = self.data[self.ix]
self.ix += 1
return item
def __contains__(self, item):
print('contains: ', end=' ')
return item in self.data
X = Iters([1, 2, 3, 4, 5])
print(3 in X)
for i in X:
print(i, end='|')
print([i ** 2 for i in X])
print(list(map(bin, X)))
I = iter(X)
while True:
try:
print(next(I), end=' @')
except StopIteration as e:
break
當(dāng)通過未定義的屬性名稱和實(shí)例通過點(diǎn)號(hào)進(jìn)行訪問時(shí),就會(huì)用屬性名稱作為字符串調(diào)用這個(gè)方法,但如果類使用了繼承,并且在超類中可以找到這個(gè)屬性,那么就不會(huì)觸發(fā)。
>>> class empty:
... def __getattr__(self, item):
... if item == 'age':
... return 40
... else:
... raise AttributeError(item)
...
>>>
>>> x = empty()
>>> print(x.age)
40
>>> print(x.name)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __getattr__
AttributeError: name
>>> class accesscontrol:
... def __setattr__(self, key, value):
... if key == 'age':
... self.__dict__[key] = value
... else:
... raise AttributeError(key + ' not allowed')
...
>>>
>>> x = accesscontrol()
>>> x.age = 40
>>> print(x.age)
40
>>> x.name = 'Hello'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __setattr__
AttributeError: name not allowed
__repr__和__str__都是為了更友好的顯示,具體來說,如果在終端下print(Class)則會(huì)調(diào)用__repr__,非終端下會(huì)調(diào)用__str__方法,且這兩個(gè)方法只能返回字符串;
class adder:
def __init__(self, value=0):
self.data = value
def __add__(self, other):
self.data += other
def __repr__(self):
return 'addrepr(%s)' % self.data
def __str__(self):
return 'N: %s' % self.data
x = adder(2)
x + 1
print(x)
print((str(x), repr(x)))
只有當(dāng)+右側(cè)的對(duì)象是類實(shí)例,而左邊對(duì)象不是類實(shí)例的時(shí)候,Python才會(huì)調(diào)用__radd__
class Commuter:
def __init__(self, val):
self.val = val
def __add__(self, other):
print('add', self.val, other)
return self.val + other
def __radd__(self, other):
print('radd', self.val, other)
return other + self.val
x = Commuter(88)
y = Commuter(99)
print(x + 1)
print('')
print(1 + y)
print('')
print(x + y)
使用__iadd__進(jìn)行原處加法
class Number:
def __init__(self, val):
self.val = val
def __iadd__(self, other):
self.val += other
return self
x = Number(5)
x += 1
x += 1
print(x.val)
class Number:
def __init__(self, val):
self.val = val
def __add__(self, other):
return Number(self.val + other)
x = Number(5)
x += 1
x += 1
print(x.val)
當(dāng)調(diào)用類實(shí)例時(shí)執(zhí)行__call__方法
class Callee:
def __call__(self, *args, **kwargs):
print('Callee:', args, kwargs)
C = Callee()
C(1, 2, 3)
C(1, 2, 3, x=1, y=2, z=3)
class Prod:
def __init__(self, value):
self.value = value
def __call__(self, other):
return self.value * other
x = Prod(3)
print(x(3))
print(x(4))
類可以定義方法來捕獲所有的6種比較運(yùn)算符:<、>、<=、>=、==和!=
class C:
data = 'spam'
def __gt__(self, other):
return self.data > other
def __lt__(self, other):
return self.data < other
x = C()
print(x > 'han')
print(x < 'han')
class Truth:
def __bool__(self):
return True
X = Truth()
if X: print('yes')
class Truth:
def __bool__(self):
return False
X = Truth()
print(bool(X))
如果沒有這個(gè)方法,Python退而求其次的求長(zhǎng)度,因?yàn)橐粋€(gè)非空對(duì)象看作是真:
>>> class Truth:
... def __len__(self): return 0
...
>>> X = Truth()
>>> if not X: print('no')
...
no
如果兩個(gè)方法都有,__bool__會(huì)勝過__len__:
>>> class Truth:
... def __bool__(self): return True
... def __len__(self): return 0
...
>>> X = Truth()
>>> bool(X)
True
如果兩個(gè)方法都沒有定義,對(duì)象毫無疑義的看作為真:
>>> class Truth: pass
...
>>> bool(Truth)
True
每當(dāng)實(shí)例產(chǎn)生時(shí),就會(huì)調(diào)用init構(gòu)造函數(shù),每當(dāng)實(shí)例空間被收回時(shí),它的對(duì)立面__del__,也就是解析函數(shù),就會(huì)自動(dòng)執(zhí)行;
class Life:
def __init__(self, name='unknown'):
print('Hello, ', name)
self.name = name
def __del__(self):
print('Goodbye', self.name)
brian = Life('Brian')
brian = 'loretta'
本文出自 “一盞燭光” 博客,謝絕轉(zhuǎn)載!
更多建議: