Uniform Function Call Syntax (UFCS)
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Sun Jun 8 23:53:13 EDT 2014
On Mon, 09 Jun 2014 02:48:13 +1000, Chris Angelico wrote:
> class Circle:
> def squared(self):
> raise NotImplementedError("Proven impossible in 1882")
>
> The trouble is that logically Circle does have a 'squared' attribute,
> while 3 doesn't; and yet Python guarantees this:
>
> foo.squared()
> # is equivalent [1] to
> func = foo.squared
> func()
>
> Which means that for (3).squared() to be 9, it has to be possible to
> evaluate (3).squared,
Given UFCS, that ought to return the global squared function, curried
with 3 as its first (and only) argument.
UFCS would be a pretty big design change to Python, but I don't think it
would be a *problem* as such. It just means that x.y, hasattr(x, y) etc.
would mean something different to what they currently mean.
> which means that hasattr (which is defined by
> attempting to get the attribute and seeing if an exception is thrown)
> has to return True.
Yes. And this is a problem why?
Obviously it would mean that the semantics of hasattr will be different
than they are now, but it's still a coherent set of semantics.
In fact, one can already give a class a __getattr__ method which provides
UFCS functionality. (Hmmm, you need a way to get the caller's globals.
You know, this keeps coming up. I think it's high-time Python offered
this as a supported function.) That's no more a problem than any other
dynamically generated attribute.
Stick that __getattr__ in object itself, and UFCS is now language wide.
That would make an awesome hack for anyone wanting to experiment with
this!
> Except that it's even more complicated than that, because hasattr wasn't
> defined in your module, so it has a different set of globals.
hasattr doesn't care about globals, nor does it need to. hasattr behaves
like the equivalent to:
def hasattr(obj, name):
try:
obj.name
except AttributeError:
return False
return True
give or take. And yes, if accessing your attribute has side effects,
using hasattr does too:
py> class Spam(object):
... @property
... def spam(self):
... print("Spam spam spam spam LOVERLY SPAAAAM!!!!")
... return "spam"
...
py> x = Spam()
py> hasattr(x, "spam")
Spam spam spam spam LOVERLY SPAAAAM!!!!
True
If that's a worry to you, you can try inspect.getattr_static.
> In fact,
> this would mean that hasattr would become quite useless. (Hmm, PEP 463
> might become a prerequisite of your proposal...) It also means that
> attribute lookup becomes extremely surprising any time the globals
> change; currently, "x.y" means exactly the same thing for any given
> object x and attribute y, no matter where you do it.
*cough*
class Example:
def __getattr__(self, name):
if name == 'module_name':
if __name__ == '__main__':
return "NOBODY expects the Spanish Inquisition!"
else:
return __name__
raise AttributeError("no attribute %r" % name)
:-)
--
Steven D'Aprano
http://import-that.dreamwidth.org/
More information about the Python-list
mailing list