简体   繁体   中英

How does Property work with Itemgetter im Python?

I was learning the python. And when comes to the collection module in official library, I found a code snipet of the NamedTuple like:

for i, name in enumerate(field_names):
    template += "        %s = _property(_itemgetter(%d), doc='Alias for field number %d')\n" % (name, i, i)

And it's one part of the code that generated by the NamedTuple. The code generated is listed below:

name = property(itemgetter(0), doc='Alias for field number 0')
age = property(itemgetter(1), doc='Alias for field number 1')

And here is my question:

Itemgetter(0) is a function which needs an object as arguments. But property will not pass any arguments to the itemgetter. So how does this work?

Thank you!

This is the whole code that property is used:

class Person(tuple):
    'Person(name, age)' 

    __slots__ = () 

    _fields = ('name', 'age') 

    def __new__(_cls, name, age):
        'Create new instance of Person(name, age)'
        print sys._getframe().f_code.co_name

        return _tuple.__new__(_cls, (name, age)) 

    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new Person object from a sequence or iterable'
        print sys._getframe().f_code.co_name

        result = new(cls, iterable)
        if len(result) != 2:
            raise TypeError('Expected 2 arguments, got %d' % len(result))
        return result 

    def __repr__(self):
        'Return a nicely formatted representation string'
        print sys._getframe().f_code.co_name

        return 'Person(name=%r, age=%r)' % self 

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values'
        print sys._getframe().f_code.co_name

        return OrderedDict(zip(self._fields, self)) 

    def _replace(_self, **kwds):
        'Return a new Person object replacing specified fields with new values'
        print sys._getframe().f_code.co_name

        result = _self._make(map(kwds.pop, ('name', 'age'), _self))
        if kwds:
            raise ValueError('Got unexpected field names: %r' % kwds.keys())
        return result 

    def __getnewargs__(self):
        'Return self as a plain tuple.  Used by copy and pickle.'
        print sys._getframe().f_code.co_name

        return tuple(self) 

    name = property(itemgetter(0), doc='Alias for field number 0')
    age = property(itemgetter(1), doc='Alias for field number 1')

itemgetter is not a function, it's a class whose instances are callable (cf the FineManual). The property instance will call it with the current object as argument (that's what properties are for).

Let's summarize... assuming this:

point = tuple(1, 2)
getx = itemgetter(0)

passing point to getx() will return point[0] (actually, point.__getitem__[0] for which point[0] is syntactic sugar)

Now if we subclass tuple and add a property :

class Point(tuple):
    @property
    def x(self):
        return self[0]

The @decorator syntax is actually syntactic sugar for :

class Point(tuple):
    def x(self):
        return self[0]
    x = property(fget=x)

so the function x becomes the fget attribute of the property instance, and the name x in the class statement's namespace is rebound to this property instance.

Now let's create a Point instance:

point = Point(1, 2)

then when evaluating point.x , the attributes lookup rules will find the "x" property object on Point (actually on point.__class__ ), notice that it has a __get__() method, and according to the descriptor protocol will return the result of Point.x.__get__(point, Point.__class__) . Since property.__get__(obj, cls) is mainly implemented as return self.fget(obj) , this will return the result of the x function called with point as self param. IOW:

point.x

is equivalent to

Point.x.__get__(point, point.__class__)

which is equivalent to

Point.x.fget(point)

which is equivalent to (NB : here 'x' refers the x function that has been passed as fget argument to property , not to Point.x

x(point)

which is equivalent to

point[0]

And since itemgetter(0)(point) is equivalent to point[0] , one can see how x = property(itemgetter(0)) works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM