property() 很容易理解, itemgetter也很容易理解。但是當兩者相遇的時候就擦出了魔法的火花。
先來看一段代碼。
import operator
class StructTupleMeta(type):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
print(cls)
for n, name in enumerate(cls._fields):
setattr(cls, name, property(operator.itemgetter(n)))
class StructTuple(tuple, metaclass=StructTupleMeta):
_fields = []
def __new__(cls, *args, **kwargs):
if len(args) != len(cls._fields):
raise ValueError("The arg number is not right")
return super().__new__(cls, args)
class Stock(StructTuple):
_fields = ['name', 'shares', 'price']
def __getitem__(self, item):
print("__getitem__", [0])
if __name__ == "__main__":
stock = Stock("abc", 10, 20)
print(stock.name)
注意一下StructTupleMeta下面兩句話
for n, name in enumerate(cls._fields):
setattr(cls, name, property(operator.itemgetter(n)))
這裏看起來很簡單,但是卻包含很多東西。
這句話的功能是,給類cls添加一個屬性。屬性的getter函數是operator.itemgetter(0)。 有點想不通的是,operaor.itemgetter(0)返回的是可調用對象,需要傳參才能使用。比如
f=operator.itemgetter(0). a = [1,2,3]
c = f(a)
上一段代碼的結果應該是 1,即返回a[0].
那麼問題來了,類中的屬性的getter函數時operator.itemgetter(0). 這個函數的參數時如何傳進去的?
看一下官網的解釋.
Return a callable object that fetches item from its operand using the operand’s getitem() method. If multiple items are specified, returns a tuple of lookup values. For example:
其實operaor.itemgetter本質上時調用對象的__getitem__ 函數。這樣就說的通了。stock.name 本質上調用的時 stock的__getitem__ 函數。