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__ 函数。