Self function

Arnaud Delobelle arnodel at googlemail.com
Tue May 5 03:09:27 EDT 2009


On 5 May, 07:08, Steven D'Aprano
<ste... at REMOVE.THIS.cybersource.com.au> wrote:
> On Mon, 04 May 2009 17:54:50 -0400, Terry Reedy wrote:
> > bearophileH... at 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



More information about the Python-list mailing list