On 5 May, 07:08, Steven D'Aprano <ste...@remove.this.cybersource.com.au> wrote: > 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- Hide quoted text - > > - Show quoted text -
Are you aware of PEP 3130? http://www.python.org/dev/peps/pep-3130/ (BTW, it seems to me that your implementation breaks as soon as two functions are decorated - not tested!) -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list