|
|||
|
Hi everyone,
What is the simplest way to access the attributes of a function from inside it, other than using its explicit name? In a function like f below: def f(*args): f.args = args print args is there any other way? I am guessing the next question will be: should I really care? It just feels like there should be a way, but I am not able to verbalise a valid one at the moment, sorry. Regards, Muhammad Alkarouri |
|
|
||||
|
||||
|
|
|
|||
|
On Wed, 10 Feb 2010 05:59:41 -0800, Muhammad Alkarouri wrote:
> Hi everyone, > > What is the simplest way to access the attributes of a function from > inside it, other than using its explicit name? In a function like f > below: > > def f(*args): > f.args = args > print args > > is there any other way? Not built-in. > I am guessing the next question will be: should I really care? It just > feels like there should be a way, but I am not able to verbalise a valid > one at the moment, sorry. I completely agree with you. It is a wart that functions are only able to refer to themselves by name, because if the name changes, things break. Consider: old_f = f # save the old version of the function def f(x): return old_f(x+1) # make a new function and call it f This won't work correctly, because old_f still tries to refer to itself under the name "f", and things break very quickly. -- Steven |
|
|||
|
On Wed, Feb 10, 2010 at 2:59 PM, Muhammad Alkarouri
<malkarouri@gmail.com> wrote: > Hi everyone, > > What is the simplest way to access the attributes of a function from > inside it, other than using its explicit name? > In a function like f below: > > def f(*args): > * *f.args = args > * *print args > > is there any other way? > I am guessing the next question will be: should I really care? It just > feels like there should be a way, but I am not able to verbalise a > valid one at the moment, sorry. > > Regards, > > Muhammad Alkarouri > -- > http://mail.python.org/mailman/listinfo/python-list > This sounds like something you shouldn't be doing. You should probably use a class instead. (Sending again to get it on the list >_<) |
|
|||
|
On 2/10/2010 9:36 AM, Steven D'Aprano wrote:
> On Wed, 10 Feb 2010 05:59:41 -0800, Muhammad Alkarouri wrote: > >> Hi everyone, >> >> What is the simplest way to access the attributes of a function from >> inside it, other than using its explicit name? In a function like f >> below: >> >> def f(*args): >> f.args = args >> print args >> >> is there any other way? > > Not built-in. > > >> I am guessing the next question will be: should I really care? It just >> feels like there should be a way, but I am not able to verbalise a valid >> one at the moment, sorry. > > I completely agree with you. It is a wart that functions are only able to > refer to themselves by name, because if the name changes, things break. > Consider: > > old_f = f # save the old version of the function > > def f(x): > return old_f(x+1) # make a new function and call it f > > This won't work correctly, because old_f still tries to refer to itself > under the name "f", and things break very quickly. They didn't break immediately for me -- what am I missing?: #------------------- def f(): return "old func" g = f print "name attr of f:", f.__name__ print "name attr of g:", g.__name__ def f(): return "new func" print "name attr of f:", f.__name__ print "name attr of g:", g.__name__ print "*** calling function currently named f:" print f() print "*** calling function currently named g:" print g() #------------------- program output (Python 2.6.4): name attr of f: f name attr of g: f name attr of f: f name attr of g: f *** calling function currently named f: new func *** calling function currently named g: old func -John |
|
|||
|
John Posner a écrit :
> On 2/10/2010 9:36 AM, Steven D'Aprano wrote: >> On Wed, 10 Feb 2010 05:59:41 -0800, Muhammad Alkarouri wrote: >> (snip) >>> def f(*args): >>> f.args = args >>> print args >>> (snip) >> I completely agree with you. It is a wart that functions are only able to >> refer to themselves by name, because if the name changes, things break. >> Consider: >> >> old_f = f # save the old version of the function >> >> def f(x): >> return old_f(x+1) # make a new function and call it f >> >> This won't work correctly, because old_f still tries to refer to itself >> under the name "f", and things break very quickly. > > They didn't break immediately for me -- what am I missing?: The fact that in the OP's snippet, code inside f's body refers to f by its name. |
|
|||
|
On Wed, 10 Feb 2010 10:08:47 -0500, John Posner wrote:
>> This won't work correctly, because old_f still tries to refer to itself >> under the name "f", and things break very quickly. > > They didn't break immediately for me -- what am I missing?: The original function f doesn't try to refer to itself in any way. With no recursive call or access, it doesn't matter what f is named. See this example instead: >>> def f(x): .... if x < 0: .... print "original" .... return f(-x) .... else: .... return x+1 .... >>> f(2) 3 >>> f(-2) original 3 >>> >>> old_f = f >>> def f(x): .... if x > 0: .... return old_f(-x) .... else: .... return x .... >>> f(-1) -1 >>> f(1) original original original original original original [...] File "<stdin>", line 3, in f File "<stdin>", line 4, in f File "<stdin>", line 3, in f RuntimeError: maximum recursion depth exceeded -- Steven |
|
|||
|
Stephen Hansen wrote:
> On Wed, Feb 10, 2010 at 6:36 AM, Steven D'Aprano > <steve@remove-this-cybersource.com.au > <mailto:steve@remove-this-cybersource.com.au>> wrote: > > On Wed, 10 Feb 2010 05:59:41 -0800, Muhammad Alkarouri wrote: > > What is the simplest way to access the attributes of a function from > > inside it, other than using its explicit name? In a function like f > > Not built-in. > > > I am guessing the next question will be: should I really care? It > just > > feels like there should be a way, but I am not able to verbalise > a valid > > one at the moment, sorry. > > I completely agree with you. It is a wart that functions are only > able to > refer to themselves by name, because if the name changes, things break. > > > I agree its slightly... in-elegant, or sub-optimal, but I'm not sure I > want to call it a *wart*. If one calls it a wart, there might be > inspiration to fix it. > > And this sounds like a precursor to making "self" non-explicit, and I > *really* like my explicit self. ![]() > > Then again, I have been slightly bruised by this sub-optimal situation > before. > > I tried to do a function using a frame hack to get the information > easily, but failed. My long years of avoiding frame hacks like the > plague have left me deficient. ![]() > Does this mean that Python needs, say, __function__ (and perhaps also __module__)? |
|
|||
|
On 2/10/2010 10:24 AM, Bruno Desthuilliers wrote:
>> >> They didn't break immediately for me -- what am I missing?: > > The fact that in the OP's snippet, code inside f's body refers to f by > its name. Of course! Tx. -John |
|
|||
|
Steven D'Aprano <steve@REMOVE-THIS-cybersource.com.au> writes:
> On Wed, 10 Feb 2010 10:08:47 -0500, John Posner wrote: > >>> This won't work correctly, because old_f still tries to refer to itself >>> under the name "f", and things break very quickly. >> >> They didn't break immediately for me -- what am I missing?: > > The original function f doesn't try to refer to itself in any way. With > no recursive call or access, it doesn't matter what f is named. > > See this example instead: > > >>>> def f(x): > ... if x < 0: > ... print "original" > ... return f(-x) > ... else: > ... return x+1 > ... >>>> f(2) > 3 >>>> f(-2) > original > 3 >>>> >>>> old_f = f >>>> def f(x): > ... if x > 0: > ... return old_f(-x) > ... else: > ... return x > ... >>>> f(-1) > -1 >>>> f(1) > original > original > original > original > original > original > [...] > File "<stdin>", line 3, in f > File "<stdin>", line 4, in f > File "<stdin>", line 3, in f > RuntimeError: maximum recursion depth exceeded It's not ideal, but you can use a decorator like this to solve this problem: def bindfunction(f): def bound_f(*args, **kwargs): return f(bound_f, *args, **kwargs) bound_f.__name__ = f.__name__ return bound_f >>> @bindfunction .... def factorial(this_function, n): .... if n > 0: .... return n * this_function(n - 1) .... else: .... return 1 .... >>> factorial(15) 1307674368000L >>> fac = factorial >>> fac(15) 1307674368000L >>> factorial = 'foobar' >>> fac(15) 1307674368000L -- Arnaud |
|
|||
|
On Wed, 10 Feb 2010 17:23:36 +0000, MRAB wrote:
> Stephen Hansen wrote: >> On Wed, Feb 10, 2010 at 6:36 AM, Steven D'Aprano >> <steve@remove-this-cybersource.com.au >> <mailto:steve@remove-this-cybersource.com.au>> wrote: >> >> On Wed, 10 Feb 2010 05:59:41 -0800, Muhammad Alkarouri wrote: >> > What is the simplest way to access the attributes of a function >> > from inside it, other than using its explicit name? In a >> > function like f >> >> Not built-in. [...] > Does this mean that Python needs, say, __function__ (and perhaps also > __module__)? Python already has __module__, except that it is spelled: import __main__ As for __function__, perhaps, but a solution I would be satisfied with would be to make it optional. Most functions are not recursive, and do not attach attributes to themselves. For the few that do need to refer to themselves, it would be sufficient to call a decorator to get the behaviour needed. I thought I had come up with such a thing, once before, but I can't find it now ![]() -- Steven |
|
|||
|
On Wed, 10 Feb 2010 18:31:23 +0000, Arnaud Delobelle wrote:
> It's not ideal, but you can use a decorator like this to solve this > problem: > > def bindfunction(f): > def bound_f(*args, **kwargs): > return f(bound_f, *args, **kwargs) > bound_f.__name__ = f.__name__ > return bound_f Ah, very nice. Perhaps it's better to use functools.wraps? import functools def bindfunction(f): @functools.wraps(f) def bound_f(*args, **kwargs): return f(bound_f, *args, **kwargs) return bound_f -- Steven |
|
|||
|
Steven D'Aprano <steve@REMOVE-THIS-cybersource.com.au> writes:
> On Wed, 10 Feb 2010 18:31:23 +0000, Arnaud Delobelle wrote: > >> It's not ideal, but you can use a decorator like this to solve this >> problem: >> >> def bindfunction(f): >> def bound_f(*args, **kwargs): >> return f(bound_f, *args, **kwargs) >> bound_f.__name__ = f.__name__ >> return bound_f > > Ah, very nice. Perhaps it's better to use functools.wraps? > > import functools > > def bindfunction(f): > @functools.wraps(f) > def bound_f(*args, **kwargs): > return f(bound_f, *args, **kwargs) > return bound_f I think I wrote this before functools . Anyway it still doesn't workwith mutually recursive functions. I also tried another approach (can't find the file anymore, so I've redone it, sorry no time to make it very readable) as below. It doesn't require an extra first argument for the function and it takes care of mutually recursive functions if used as in the example. def bindglobals(*args): """ Binds all the globals in all the arguments which must be functions. return the new bound functions. When called with a single argument, return the bound function so it can be used as a decorator. It is assumed that all argument are functions and have the same global namespace """ function_names = [f.__name__ for f in args] def get_global(f, n): d = f.func_globals if n not in d: d = d['__builtins__'].__dict__ return d[n] bound_globals = dict( (n, get_global(f, n)) for f in args for n in f.func_code.co_names if n not in function_names ) bound_functions = [ type(f)(f.func_code, bound_globals, f.func_name, f.func_defaults, f.func_closure) for f in args ] bound_globals.update(zip(function_names, bound_functions)) if len(args) == 1: return bound_functions[0] else: return bound_functions # Example @bindglobals def fac(n): return 1 if n <= 1 else n*fac(n - 1) # Decorator syntax cannot be used with mutually recursive functions: def even(n): return True if not n else odd(n - 1) def odd(n): return False if not n else even(n - 1) even, odd = bindglobals(even, odd) # Example in action: >>> fac(10) 3628800 >>> f = fac >>> fac = 'foo' >>> f(10) 3628800 >>> even(5), odd(5) (False, True) >>> e, o = even, odd >>> even, odd = 'spam', 'eggs' >>> e(5), o(5) (False, True) This is proof of concept stuff - probably very fragile! -- Arnaud |
|
|||
|
MRAB <python@mrabarnett.plus.com> writes:
> Does this mean that Python needs, say, __function__ (and perhaps also > __module__)? See PEP 3130 "Access to Current Module/Class/Function" (rejected) (http://www.python.org/dev/peps/pep-3130/) -- Arnaud |
|
|||
|
En Wed, 10 Feb 2010 10:59:41 -0300, Muhammad Alkarouri
<malkarouri@gmail.com> escribió: > What is the simplest way to access the attributes of a function from > inside it, other than using its explicit name? > In a function like f below: > > def f(*args): > f.args = args > print args > > is there any other way? See this: >>> def foo(): pass .... >>> import sys >>> sys.getrefcount(foo) 2 The 2 means that there is a *single* reference to the function - the foo name in the global namespace. No other reference exists, there is no hidden attribute somewhere that you may use. If you want another way to reach the function, you'll have to add it yourself. I've written a decorator for "injecting" a __function__ name into the function namespace, but I can't find it anywhere. I think I implemented it by adding a fake additional argument and replacing LOAD_GLOBAL with LOAD_NAME in the bytecode. > I am guessing the next question will be: should I really care? It just > feels like there should be a way, but I am not able to verbalise a > valid one at the moment, sorry. One reason would be to write truly recursive functions (currently, a recursive call involves a name lookup, which could potentially return a different function). Another one, to implement some kind of tail call optimization. -- Gabriel Genellina |
|
|||
|
On 2/10/2010 4:49 PM, Gabriel Genellina wrote:
> I've written a decorator for "injecting" a __function__ name into the > function namespace, but I can't find it anywhere. I think I implemented > it by adding a fake additional argument and replacing LOAD_GLOBAL with > LOAD_NAME in the bytecode. The decorator only needs to replace the defaults args tuple. It does not even need to know the parameter name, just that it is the only (or last) with a default . def f(n, me=None): if n > 0: return n*me(n-1) elif n==0: return 1 f.__defaults__ = (f,) # 3.1 print(f(5)) # 120 To generalize: def g(a,b=1,me=None): if a: return me(0) else: return 41+b g.__defaults__ = g.__defaults__[:len(g.__defaults__)-1] + (g,) print(g(3)) #42 Of course, user could still screw up recursion by providing another value for 'me'. This strikes me as about a likely (low) as a user screwing up recursion in a library module function by rebinding the name in the imported module. Terry Jan Reedy |
|
|
|
|
![]() |
| Popular Tags in the Forum |
| attributes, function |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Attributes VS Properties | Ivan S | Newsgroup comp.lang.javascript | 62 | 01-24-2010 12:16 AM |
| Function pointers: performance penalty? | Rui Maciel | Newsgroup comp.lang.c | 126 | 10-27-2009 11:33 PM |
| using local static variable inside a function | subramanian100in@yahoo.com, India | Newsgroup comp.language.c++ | 16 | 10-02-2009 11:40 PM |
| Re: need a sas function analagous to LAG function | Joe Matise | Newsgroup comp.soft-sys.sas | 0 | 05-30-2009 06:54 PM |
| Named function expressions in Safari 2.x | kangax | Newsgroup comp.lang.javascript | 2 | 05-06-2009 03:51 AM |