Uniform Function Call Syntax (UFCS)

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Jun 9 00:33:22 EDT 2014


On Sun, 08 Jun 2014 18:56:47 +0300, Marko Rauhamaa wrote:

> Paul Sokolovsky <pmiscml at gmail.com>:
> 
>> Python already has that - like, len(x) calls x.__len__() if it's
>> defined
> 
> In fact, what's the point of having the duality?
> 
>    len(x) <==> x.__len__()
>
>    x < y <==> x.__lt__(y)
> 
>    str(x) <==> x.__str__()


Interface on the left, implementation on the right. That's especially 
obvious when you consider operators like < + - * etc.

Consider x + y. What happens?

#1 First, Python checks whether y is an instance of a *subclass* of x. If 
so, y gets priority, otherwise x gets priority.

#2 If y gets priority, y.__radd__(x) is called, if it exists. If it 
returns something other than NotImplemented, we are done.

#3 However if y.__radd__ doesn't exist, or it returns NotImplemented, 
then Python continues as if x had priority.

#3 If x has priority, then x.__add__(y) is called, if it exists. If it 
returns something other than NotImplemented, we are done. 

#4 However if it doesn't exist, or it returns NotImplemented, then 
y.__radd__(x) is called, provided it wasn't already tried in step #2.

#5 Finally, if neither object has __add__ or __radd__, or both return 
NotImplemented, then Python raises TypeError.


That's a lot of boilerplate if you were required to implement it yourself 
in every single operator method. Better, Python handles all the boiler 
plate, all you have to do is just handle the cases you care about, and 
return NotImplemented for everything else.




-- 
Steven D'Aprano
http://import-that.dreamwidth.org/



More information about the Python-list mailing list