472,111 Members | 1,926 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,111 software developers and data experts.

getattr() on nested functions?

Hello,

I can't get getattr() to return nested functions, I tried this :
>>def toto():
.... def titi():
.... pass
.... f = getattr(toto, "titi")
.... print str(f)
....
>>toto()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in toto
AttributeError: 'function' object has no attribute 'titi'
>>>
I thought that since functions are objects, that I could obtain it's
nested functions. How come it doesn't work and what can I do to
fix/replace it? I'm using it in code that is like this :

def __test(self, action, *args):
def request(params):
pass

def submit(params, values):
pass

def update(params, values):
pass

def delete(params):
pass

result = getattr(__test, action)(*args)

return resultToXml(result)

where "action" is a string containing either "request", "submit",
"update", or "delete". I was using an evel() with this form :

result = eval(action + "(params, values)")

but I didn't find that very clean.

Thank you,
Gabriel
Aug 20 '08 #1
9 3810
Gabriel Rossetti <ga**************@arimaz.comwrites:
I can't get getattr() to return nested functions, I tried this :
>>>def toto():
... def titi():
... pass
... f = getattr(toto, "titi")
... print str(f)
...
>>>toto()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in toto
AttributeError: 'function' object has no attribute 'titi'
>>>>

I thought that since functions are objects, that I could obtain it's
nested functions.
Note that the nested function is created anew each time you call
toto(), so there's no reason for it to be stored anywhere. What is
stored is the internal compiled code object used to create the inner
function, but it's not easy to get to it, nor is it all that useful to
try. If you really need this, you can explicitly store the inner
function in the outer one's dict:

def outer():
if not hasattr(outer, 'inner'):
def inner():
pass
outer.inner = inner
f = outer.inner # same as getattr(outer, 'inner')
print f # same as print str(f)
>>outer()
<function inner at 0xb7cfc294>
>>outer.inner
<function inner at 0xb7cfc294>
def __test(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
result = getattr(__test, action)(*args)
return resultToXml(result)

where "action" is a string containing either "request", "submit",
"update", or "delete".
Use locals()[action](*args).
Aug 20 '08 #2
Gabriel Rossetti a écrit :
Hello,

I can't get getattr() to return nested functions,
Of course. Nested functions are not attributes of their container function.
I tried this :
>>def toto():
... def titi():
... pass
... f = getattr(toto, "titi")
... print str(f)
...
>>toto()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in toto
AttributeError: 'function' object has no attribute 'titi'
>>>

I thought that since functions are objects, that I could obtain it's
nested functions.
Well, there's probably a very hackish way, but it's not worth the pain.
The fact that functions are objects doesn't make nested functions
methods of that object. If what you really want are methods, then you
can write your own callable:

class _Test(object):
def request(self, params):
pass
def submit(self, params, values):
pass
def update(self, params, values):
pass
def delete(self, params):
pass
def __call__(self, action, *args):
return resultToXml(getattr(self, action)(*args))

_test = _Test()

But read the remaining before...
How come it doesn't work and what can I do to
fix/replace it? I'm using it in code that is like this :

def __test(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
result = getattr(__test, action)(*args)
return resultToXml(result)

where "action" is a string containing either "request", "submit",
"update", or "delete". I was using an evel() with this form :

result = eval(action + "(params, values)")
Wrong use case for eval, as usual.
but I didn't find that very clean.
indeed !-)

locals() is your friend.

def _test(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
result = locals()[action](*args)
return resultToXml(result)
HTH
Aug 20 '08 #3
Bruno Desthuilliers wrote:
Gabriel Rossetti a écrit :
>Hello,

I can't get getattr() to return nested functions,

Of course. Nested functions are not attributes of their container
function.
Ok
>
>I tried this :
> >>def toto():
... def titi():
... pass
... f = getattr(toto, "titi")
... print str(f)
...
> >>toto()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in toto
AttributeError: 'function' object has no attribute 'titi'
> >>>

I thought that since functions are objects, that I could obtain it's
nested functions.

Well, there's probably a very hackish way, but it's not worth the
pain. The fact that functions are objects doesn't make nested
functions methods of that object. If what you really want are methods,
then you can write your own callable:

class _Test(object):
def request(self, params):
pass
def submit(self, params, values):
pass
def update(self, params, values):
pass
def delete(self, params):
pass
def __call__(self, action, *args):
return resultToXml(getattr(self, action)(*args))

_test = _Test()
Yes, very hackish :-)
But read the remaining before...
>How come it doesn't work and what can I do to fix/replace it? I'm
using it in code that is like this :

def __test(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
result = getattr(__test, action)(*args)
return resultToXml(result)

where "action" is a string containing either "request", "submit",
"update", or "delete". I was using an evel() with this form :

result = eval(action + "(params, values)")

Wrong use case for eval, as usual.
>but I didn't find that very clean.

indeed !-)

locals() is your friend.

def _test(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
result = locals()[action](*args)
return resultToXml(result)

Ok, thanks, that works :-), like I told Gabriel G., I keep on forgetting
locals() exists :-)
HTH
--
http://mail.python.org/mailman/listinfo/python-list
Aug 20 '08 #4


Gabriel Rossetti wrote:
Bruno Desthuilliers wrote:
>Gabriel Rossetti a écrit :
>>I thought that since functions are objects, that I could obtain it's
nested functions.

Well, there's probably a very hackish way, but it's not worth the
pain.
What Bruno meant here, I believe, is that there is probably a hackish
way to get the nested functions, but it indeed would not be worth the pain.
> The fact that functions are objects doesn't make nested
functions methods of that object.
A def statement is ultimately an assignment statement. The name of the
nested function is a local variable just like any other local name.
>If what you really want are methods,
then you can write your own callable:

class _Test(object):
def request(self, params):
pass
def submit(self, params, values):
pass
def update(self, params, values):
pass
def delete(self, params):
pass
def __call__(self, action, *args):
return resultToXml(getattr(self, action)(*args))

_test = _Test()
Yes, very hackish :-)
No, not at all hackish, but one standard way to do what you want.
>locals() is your friend.

def _test(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
result = locals()[action](*args)
return resultToXml(result)

Ok, thanks, that works :-), like I told Gabriel G., I keep on forgetting
locals() exists :-)
Unlike the class approach, this requires recreating the constant
functions and dict with each call to _test. Quick to write but a bit
'dirty', in my opinion. Another standard idiom is to set up the
constants outside the function:

def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
dispatch = {'request':request, 'submit':submit, 'update':update,
'delete':delete}

def _test(self, action, *args):
return resultToXmo(dispatch[action](*args))

Terry Jan Reedy
Aug 20 '08 #5
Terry Reedy wrote:
>

Gabriel Rossetti wrote:
>Bruno Desthuilliers wrote:
>>Gabriel Rossetti a écrit :
>>>I thought that since functions are objects, that I could obtain
it's nested functions.

Well, there's probably a very hackish way, but it's not worth the pain.

What Bruno meant here, I believe, is that there is probably a hackish
way to get the nested functions, but it indeed would not be worth the
pain.
Yes, I understood that :-)
>
The fact that functions are objects doesn't make nested
functions methods of that object.

A def statement is ultimately an assignment statement. The name of
the nested function is a local variable just like any other local name.
Ok
If what you really want are methods,
then you can write your own callable:

class _Test(object):
def request(self, params):
pass
def submit(self, params, values):
pass
def update(self, params, values):
pass
def delete(self, params):
pass
def __call__(self, action, *args):
return resultToXml(getattr(self, action)(*args))

_test = _Test()
Yes, very hackish :-)

No, not at all hackish, but one standard way to do what you want.
>>locals() is your friend.

def _test(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
result = locals()[action](*args)
return resultToXml(result)

Ok, thanks, that works :-), like I told Gabriel G., I keep on
forgetting locals() exists :-)

Unlike the class approach, this requires recreating the constant
functions and dict with each call to _test. Quick to write but a bit
'dirty', in my opinion. Another standard idiom is to set up the
constants outside the function:

def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
dispatch = {'request':request, 'submit':submit, 'update':update,
'delete':delete}

def _test(self, action, *args):
return resultToXmo(dispatch[action](*args))
That's how I had done it originally (before the use of eval()), but in
this case also, since the functions are still nested, they are
re-created and so is the dict, so I don' t see a gain from the locals()
method.
>
Terry Jan Reedy
--
http://mail.python.org/mailman/listinfo/python-list
Aug 21 '08 #6
Gabriel Rossetti a écrit :
Terry Reedy wrote:
(snip)
>Unlike the class approach, this requires recreating the constant
functions and dict with each call to _test. Quick to write but a bit
'dirty', in my opinion. Another standard idiom is to set up the
constants outside the function:

def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
dispatch = {'request':request, 'submit':submit, 'update':update,
'delete':delete}

def _test(self, action, *args):
return resultToXmo(dispatch[action](*args))

That's how I had done it originally (before the use of eval()), but in
this case also, since the functions are still nested,
Uh ??? You probably want to re-read the above code snippet.

Aug 21 '08 #7
Bruno Desthuilliers wrote:
Gabriel Rossetti a écrit :
>Terry Reedy wrote:
(snip)
>>Unlike the class approach, this requires recreating the constant
functions and dict with each call to _test. Quick to write but a
bit 'dirty', in my opinion. Another standard idiom is to set up the
constants outside the function:

def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
dispatch = {'request':request, 'submit':submit, 'update':update,
'delete':delete}

def _test(self, action, *args):
return resultToXmo(dispatch[action](*args))

That's how I had done it originally (before the use of eval()), but
in this case also, since the functions are still nested,

Uh ??? You probably want to re-read the above code snippet.
Uh...yes, I didn't see the external/parent function was no longer there.
I prefer to nest mine though because I have several parent functions for
different tasks, so each child/nested function has a diff.
implementation, I find that cleaner than having n*4+n top-level
functions (+ n dicts), e.g. I prefer this :

def __task1(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
return resultToXml(locals()[action](*args))

def __task2(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
return resultToXml(locals()[action](*args))
over this :

def task1_request(params):
pass
def task1_submit(params, values):
pass
def task1_update(params, values):
pass
def task1_delete(params):
pass

def task2_request(params):
pass
def task2_submit(params, values):
pass
def task2_update(params, values):
pass
def task2_delete(params):
pass

dispatch_task1 = {'request':task1_request, 'submit':task1_submit,
'update':task1_update, 'delete':task1_delete}
dispatch_task2 = {'request':task2_request, 'submit':task2_submit,
'update':task2_update, 'delete':task2_delete}

def _task1(self, action, *args):
return resultToXml(dispatch_task1[action](*args))

def _task2(self, action, *args):
return resultToXml(dispatch_task2[action](*args))
I could use your callable approach, but like you said it may not be
worth the trouble.

Gabriel

Aug 21 '08 #8
Gabriel Rossetti a écrit :
Bruno Desthuilliers wrote:
>Gabriel Rossetti a écrit :
>>Terry Reedy wrote:
(snip)
>>>Unlike the class approach, this requires recreating the constant
functions and dict with each call to _test. Quick to write but a
bit 'dirty', in my opinion. Another standard idiom is to set up the
constants outside the function:

def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
dispatch = {'request':request, 'submit':submit, 'update':update,
'delete':delete}

def _test(self, action, *args):
return resultToXmo(dispatch[action](*args))

That's how I had done it originally (before the use of eval()), but
in this case also, since the functions are still nested,

Uh ??? You probably want to re-read the above code snippet.
Uh...yes, I didn't see the external/parent function was no longer there.
I prefer to nest mine though because I have several parent functions for
different tasks, so each child/nested function has a diff.
implementation, I find that cleaner than having n*4+n top-level
functions (+ n dicts), e.g. I prefer this :

def __task1(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
return resultToXml(locals()[action](*args))

def __task2(self, action, *args):
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
return resultToXml(locals()[action](*args))
over this :
(snip)
>

I could use your callable approach, but like you said it may not be
worth the trouble.
The "trouble" I was talking about was not with using callable objects,
but with trying to hack func.func_code to extract nested functions (if
ever possible).

But anyway... The point of using callable objects is to avoid going thru
the whole "setup" part again and again and again. Now if all your task
functions only differ by the dispatch dict, there's at least another
ways to avoid this runtime repetition - as well as coding repetition
FWIW (warning : untested code):

def _make_task(func):
dispatch = func()
def _task(action, *args):
return resultToXml(dispatch[action](*args))
_task.__name__ = _task.func_name = func.__name__
return _task

@_make_task
def _task1():
def request(params):
pass
def submit(params, values):
pass
def update(params, values):
pass
def delete(params):
pass
return locals()
HTH
Aug 21 '08 #9
On Aug 21, 10:14*am, Bruno Desthuilliers <bruno.
42.desthuilli...@websiteburo.invalidwrote:
Gabriel Rossetti a écrit :
Bruno Desthuilliers wrote:
Gabriel Rossetti a écrit :
Terry Reedy wrote:
(snip)
Unlike the class approach, this requires recreating the constant
functions and dict with each call to _test. *Quick to write but a
bit 'dirty', in my opinion. *Another standard idiom is to set up the
constants outside the function:
>>def request(params):
* * pass
def submit(params, values):
* * pass
def update(params, values):
* * pass
def delete(params):
* * pass
dispatch = {'request':request, 'submit':submit, 'update':update,
'delete':delete}
>>def _test(self, action, *args):
* * return resultToXmo(dispatch[action](*args))
>That's how I had done it originally (before the use of eval()), but
in this case also, since the functions are still nested,
Uh ??? You probably want to re-read the above code snippet.
Uh...yes, I didn't see the external/parent function was no longer there..
I prefer to nest mine though because I have several parent functions for
different tasks, so each child/nested function has a diff.
implementation, I find that cleaner than having n*4+n top-level
functions (+ n dicts), e.g. I prefer this :
* *def __task1(self, action, *args):
* * * *def request(params):
* * * * * *pass
* * * *def submit(params, values):
* * * * * *pass
* * * *def update(params, values):
* * * * * *pass
* * * *def delete(params):
* * * * * *pass
* * * *return resultToXml(locals()[action](*args))
* *def __task2(self, action, *args):
* * * *def request(params):
* * * * * *pass
* * * *def submit(params, values):
* * * * * *pass
* * * *def update(params, values):
* * * * * *pass
* * * *def delete(params):
* * * * * *pass
* * * *return resultToXml(locals()[action](*args))
over this :

(snip)
I could use your callable approach, but like you said it may not be
worth the trouble.

The "trouble" I was talking about was not with using callable objects,
but with trying to hack func.func_code to extract nested functions (if
ever possible).

But anyway... The point of using callable objects is to avoid going thru
the whole "setup" part again and again and again. Now if all your task
functions only differ by the dispatch dict, there's at least another
ways to avoid this runtime repetition - as well as coding repetition
FWIW (warning : untested code):

def _make_task(func):
* * *dispatch = func()
* * *def _task(action, *args):
* * * * *return resultToXml(dispatch[action](*args))
* * *_task.__name__ = _task.func_name = func.__name__
* * return _task

@_make_task
def _task1():
* * *def request(params):
* * * * *pass
* * *def submit(params, values):
* * * * *pass
* * *def update(params, values):
* * * * *pass
* * *def delete(params):
* * * * *pass
* * *return locals()

HTH
Here's more ideas:

Use a wrapper to give the function access to itself as an object:

@auto
def f( self, arg ):
assert self== f

In your original example:

@auto
def toto( toto ):
def titi():
pass
f = getattr(toto, "titi")
print str(f)

Should work, untested. Another is to use a wrapper to participate
functions in a dictionary:

@entry( 'a' )
def a( arg ):
a_stuff( )

@entry( 'b' )
def b( arg ):
b_stuff

You could even make 'entry' a class instance, so you can specialize
and vary it in other cases, untested.

Last one is just use a class, untested:

class __Test:
def __test(self, action, *args):
result = getattr(self, action)(*args)
return resultToXml(result)

def request(self,params):
pass

def submit(self,params, values):
pass

def update(self,params, values):
pass

def delete(self,params):
pass

Keep us posted which one works for you.

Aug 21 '08 #10

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by Brian Roberts | last post: by
6 posts views Thread by Andy Baker | last post: by
7 posts views Thread by block111 | last post: by
4 posts views Thread by Wolfgang Draxinger | last post: by
3 posts views Thread by Rotlaus | last post: by
2 posts views Thread by Johannes Bauer | last post: by
8 posts views Thread by Gregor Horvath | last post: by
reply views Thread by Gabriel Genellina | last post: by
4 posts views Thread by maestro | last post: by
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.