Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

python

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?

like image 378
Michael Ekoka Avatar asked Jan 18 '12 07:01

Michael Ekoka


2 Answers

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.

like image 110
Rob Wouters Avatar answered Nov 14 '22 23:11

Rob Wouters


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.

like image 20
newtover Avatar answered Nov 15 '22 00:11

newtover