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