tags:

views:

78

answers:

5

I have the following code I am trying to understand:

>>> class DistanceFrom(object):
        def __init__(self, origin):
            self.origin = origin
        def __call__(self, x):
            return abs(x - self.origin)  

>>> nums = [1, 37, 42, 101, 13, 9, -20]
>>> nums.sort(key=DistanceFrom(10))
>>> nums
[9, 13, 1, 37, -20, 42, 101]

Can anyone explain how this works? As far as I have understood, __call__ is what is called when object() is called - calling the object as a function.

What I don't understand is how nums.sort(key=DistanceFrom(10)). How does this work? Can anyone please explain this line?

Thanks!

+4  A: 

It sorts list nums in place using a key function object DistanceFrom(10). It needs to be callable because key needs to be callable. The resulting output is sorted by their "remoteness" from 10, that is 9 is the closest value to 10, 101 is the farthest one.

After the object is initialised and passed as a key parameter to the sort method, on each iteration it will be called with the current value (that's what x is) and returned value would be used to determine x's position in the resulting list.

SilentGhost
How is this executed? I mean, DistanceFrom(10) sets self.origin = 10. After that?
A A
@Alfred: see my edit
SilentGhost
"__ init __" is a constructor that gets called during creation of the Object key
Oops
Thanks, I will try it out to check whether I have understood it completely.
A A
+8  A: 

__call__ in python allows a class to be run as if it's a function. You can try this out manually:

>>> dis = DistanceFrom(10)
>>> print dis(10), dis(5), dis(0)
0 5 10
>>> 

What sort does is call that function for every item in your list and uses the returned value as sort key. In this example you'll get a list back with the items closest to 10 first, and the one further away more towards the end.

Aah. This is good.
A A
@user: Your answer was perfect, but I accepted gnibbler's answer since it would be beneficial to beginners in case they search for it.
A A
+1  A: 

When you call something that means you are expecting it to return a value. When you create a class that has the __call__ method defined, you are dictating that an instance of that class can behave as a function does.

For the purpose of this question, this:

class DistanceFrom(object):
        def __init__(self, origin):
            self.origin = origin
        def __call__(self, x):
            return abs(x - self.origin) 

Is functionally equivalent to:

def distance_from(origin, other):
    return abs(other - origin)

As for the key argument to sort, here is your explanation straight from the Python documentation:

key specifies a function of one argument that is used to extract a comparison key from each list element: key=str.lower. The default value is None (compare the elements directly)

jathanism
+7  A: 

Here I have defined a function DistanceFrom() which can be used in a similar way to your class, but might be easier to follow

>>> def DistanceFrom(origin):
...     def f(x):
...         retval = abs(x - origin)
...         print "f(%s) = %s"%(x, retval)
...         return retval
...     return f
... 
>>> nums = [1, 37, 42, 101, 13, 9, -20]
>>> nums.sort(key=DistanceFrom(10))
f(1) = 9
f(37) = 27
f(42) = 32
f(101) = 91
f(13) = 3
f(9) = 1
f(-20) = 30
>>> nums
[9, 13, 1, 37, -20, 42, 101]

So you see that the object returned by DistanceFrom is called once for each item of nums and then nums is returned sorted in accordance with the returned values

gnibbler
Thank you! This is perfect.
A A
@Alfred, you're most welcome
gnibbler
+1  A: 

The Python docs are quite good whenever I find I don't understand the fundamentals. I located these with google.

The key parameter is a function that sort will call on the elements of the list. I located this doc by googling sort site:http://docs.python.org/ and then searching for key=.

__call__ is a function you can add to an object to make that object callable as if it were a function. I found this doc by googling __call__ site:http://docs.python.org/ and then following the link to the doc for __call__.

Dave Aaron Smith
I understand what they are, my question was specific for this example.
A A