On Mon, 04 May 2009 17:54:50 -0400, Terry Reedy wrote: > bearophileh...@lycos.com wrote: > >> Another possible syntax: >> >> def fact(n): >> return 1 if n <= 1 else n * return(n - 1) >> >> But I guess most people don't see this problem as important&common >> enough to justify changing the language. > > Actually, I would like a way to refer to the current function from > inside a function. but I would like support in the language, so that > the compiler patched the code after the function object is created to > directly refer to the function object (or can the code object call the > code object?) without any name lookup at all.
I don't know about avoiding name lookup, that smacks of deepest black magic, and Python doesn't usually do that. It does however do parlour tricks like `__name__` and `self`, suggests a solution. I propose a small piece of sugar. When a function is entered, Python creates an ordinary local name in the function's local namespace, and binds the function itself to that name. Two possibilities for the name are `this` or `__this__`, analogous to `self` in methods and `__name__` in modules. If there is any support for this, I propose to send the following (long) post to python-ideas. Feedback, corrections and suggestions welcome. * * * Summary: Most objects in Python don't need to know what name, or names (if any) they are bound to. Functions are a conspicuous exception to that rule: there are good reasons for a function to refer to itself, and the only straightforward way to do so is by name. I propose that on calling a function, Python should create a local name which refers to the function itself, giving the programmer the ability to have a function refer to itself without using its name. There are (at least) four reasons for a function to refer to itself. In no particular order: (1) User-friendly messages (for logging, errors or other): def parrot(): print "Error feeding cracker to function %r" % parrot (2) Recursion: def spam(n): if n < 0: return spam(-n).upper() return "spam "*n (3) Introspection: def spanish_inquisition(): print inspect.getmembers(spanish_inquisition) (4) Storing data between function calls: def cheeseshop(): if hasattr(cheeseshop, 'cheeses'): print "We have many fine cheeses" else: print "I'm sorry, I have been wasting your time" I call these self-reflective functions. In some cases there are alternatives e.g. cheeseshop could be written as a functor object, or some recursive functions can be re-written as iteration. Nevertheless such self-reflective functions are acceptable to many people, and consequently in moderately common use. How to have a function refer to itself is a common question, e.g. for newbies: http://www.mail-archive.com/tutor%40python.org/msg35114.html and even more experienced programmers: http://article.gmane.org/gmane.comp.python.general/622020 (An earlier draft of this proposal was sent to that thread.) However, none of these functions are robust in the face of the function being renamed, either at runtime or in the source code. In general, this will fail for any of the above functions: func = spam del spam func() Self-reflective functions like these are (almost?) unique in Python in that they require a known name to work correctly. You can rename a class, instance or module and expect it to continue to work, but not so for such functions. When editing source code, it is very easy to forget to change all the references to the function name within the body of itself function, even for small functions, and refactoring tools are overkill. My proposal is for Python to automatically generate a local variable named either `this` or `__this__` when entering a function. This will allow any of the above functions to be re-written using the special name, and become robust against name changes. def spanish_inquisition(): print inspect.getmembers(__this__) fang = spanish_inquisition del spanish_inquisition fang() It will also allow lambda to use recursion: lambda n: 0 if n <= 1 else __this__(n-1) (This may count as a point against it, for those who dislike lambda.) It is often useful to create two similar functions, or a variant of a function, without duplicating the source code. E.g. you might want a function that uses a cache, while still keeping around the version without a cache: cached_function = memoize(function) Currently, this does not give the expected results for recursive functions, nor does it give an error. It simply fails to behave as expected. Re-writing function() to use __this__ for the recursive call will solve that problem. Q: Will `__this__` or `this` clash with existing variables? I prefer `this` over `__this__`, for analogy with `self` inside methods. However it is more likely that existing code already uses the name `this`, since double-leading-and-trailing-underscore names are reserved for use by Python. Because `this` is an ordinary local variable, if a function assigns to it the function will work as expected. The only meaningful clash I can think of will occur when a function refers to a non-local name `this` without declaring it first. Another obvious clash may be: def function(): import this ... Both of these are likely to be very rare. Q: Will there be a performance penalty if every function defines the name `__this__` on entry? I don't expect so, but if it is found to be a problem, a slightly more sophisticated strategy would be to only define `__this__` inside the function if the body of the function refers to that variable. That will allow the majority of functions which are not self-reflective to avoid paying that (probably minuscule) cost. Q: Is this really necessary? This is sugar, a convenience for the programmer. None of the problems it solves cannot be solved, or worked around, by other methods. Nevertheless, that the question "how do I have my function refer to itself?" keeps being asked over and over again suggests that the current solutions are (1) not obvious to newbies, and (2) not entirely satisfactory to more experienced programmers. Here is a proof-of-concept pure Python implementation, using a decorator, and abusing a global variable. This is NOT to imply that `__this__` should be a global if this proposal goes ahead. from functools import wraps def make_this(func): global __this__ __this__ = func @wraps(func) def f(*args, **kwargs): return func(*args, **kwargs) return f >>> @make_this ... def spam(n): ... if n < 0: return __this__(-n).upper() ... return ' '.join([__this__.__name__] * n) ... >>> tasty_meat_like_product = spam >>> del spam >>> tasty_meat_like_product(-3) 'SPAM SPAM SPAM' -- Steven -- http://mail.python.org/mailman/listinfo/python-list