简体   繁体   中英

Python: functions returned by itemgetter() not working as expected in classes

The operator.itemgetter() function works like this:

>>> import operator
>>> getseconditem = operator.itemgetter(1)
>>> ls = ['a', 'b', 'c', 'd']
>>> getseconditem(ls) 
'b'

EDIT I've added this portion to highlight the inconsitency

>>> def myitemgetter(item):
...     def g(obj):
...         return obj[item]
...     return g
>>> mygetseconditem = myitemgetter(1)

Now, I have this class

>>> class Items(object):
...     second = getseconditem
...     mysecond = mygetseconditem
...
...     def __init__(self, *items):
...         self.items = items
...
...     def __getitem__(self, i):
...         return self.items[i]

Accessing the second item with its index works

>>> obj = Items('a', 'b', 'c', 'd')
>>> obj[1] 
>>> 'b'

And so does accessing it via the mysecond method

>>> obj.mysecond()
'b'

But for some reason, using the second() method raises an exception

>>> obj.second()
TypeError: itemgetter expected 1 arguments, got 0

What gives?

obj.second is the function getseconditem . A function which expects an argument to operate on. Since you call obj.second without any arguments the error you gave is raised. To solve it you can do obj.second(obj.items) or define second differently:

class Items(object):
    def __init__(self, *items):
        self.items = items

    def __getitem__(self, i):
        return self.items[i]

    def second(self):
        return getseconditem(self.items)

Edit

It's clear what you mean now after you edited your question. I think what's going on here is that because getseconditem is not a user-defined function it does not get transformed to a method upon accessing obj.second . It simply stays a function. The following can be found in the docs :

Note that the transformation from function object to (unbound or bound) method object happens each time the attribute is retrieved from the class or instance. In some cases, a fruitful optimization is to assign the attribute to a local variable and call that local variable. Also notice that this transformation only happens for user-defined functions; other callable objects (and all non-callable objects) are retrieved without transformation.

the problem seem to be in the following:

>>> print (getseconditem, mygetseconditem)
(<operator.itemgetter object at 0x01EE5BD0>, <function g at 0x00504DB0>)

In other words, a function can be bound, but a callable can not.

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