[Tutor] Where am I mistaken? (exec not working as I expect)

Peter Otten __peter__ at web.de
Tue Mar 14 05:18:29 EDT 2017


Steven D'Aprano wrote:

> Hello Francesco, and welcome!
> 
> My comments below.
> 
> On Sun, Mar 12, 2017 at 11:48:35PM +0100, Francesco Loffredo via Tutor
> wrote:
> 
>> I did only find a way to access the current document, but that's
>> all. Armed with that, and hoping to find some field names, I wrote a
>> small routine to inspect the types of all elements in that document,
>> and I stumbled in a strange behaviour in the exec() function: it seems
>> that exec() only works if called from the interactive interpreter,
>> while it doesn't if called inside a program.
>> Why?
> 
> That is definitely not the case. You must be misinterpreting what you
> are seeing. Unfortunately, your code is so complex I cannot easily see
> where the problem is. Perhaps later I will have time to study it in more
> detail, or somebody else will.

I think the underlying problem is that Python 3 doesn't give you write 
access to the function's namespace:

>>> def f():
...     x = "a"
...     exec("print(x); x = 'b'; print(x)")
...     print(x)
... 
>>> f()
a
b
a

Here exec()'s namespace is initialized with a copy of the local namespace 
whereas on the module level where global and local namespace are identical 
it operates directly on the module namespace:

>>> x = "a"
>>> exec("print(x); x = 'b'; print(x)")
a
b
>>> x
'b'

While exec() is the wrong choice in most cases (Steven already proposed a 
better way to solve your problem) you can see the rebound names if you pass 
a namespace explicitly:

>>> def f():
...     ns = dict(x="a")
...     exec("print(x); x = 'b'; print(x)", ns)
...     print(ns["x"])
... 
>>> f()
a
b
b

> But you do not need exec here at all. exec is a very powerful command,
> but you should treat it as for experts only. Instead of writing:
> 
>     exec("qqq = inspect.getmembers(xModel.%s)" % x)
> 
> a much safer way is:
> 
>     qqq = inspect.getmembers(getattr(xModel, x))
> 
> which is faster, easier to understand, and easier to debug.
> 
> I also see you have not one, but two bare except clauses:
> 
>     try:
>         ...
>     except:
>         ...
> 
> 
> This is not a good idea! Please read this:
> 
> https://realpython.com/blog/python/the-most-diabolical-python-antipattern/
> 
> 
> I think your code is too complex. Here is a simpler function which does
> what you describe as "correct behaviour":
> 
> def esplora(xModel):
>     i = 0
>     for i, name in enumerate(dir(xModel), 1):
>         what = type(getattr(xModel, name))
>         print(name, what)
>     print("Totale elementi: %s" % i)
> 
> 
> class prova(object):
>     def __init__(self):
>         self.abc = "ABC"
>         self.num = 123
>         self.tup = ("abc", 321)
> 
> lui = prova()
> 
> esplora(lui)
> 
> 
> 
> which gives this result:
> 
> __class__ <class 'type'>
> __delattr__ <class 'method-wrapper'>
> __dict__ <class 'dict'>
> __dir__ <class 'builtin_function_or_method'>
> __doc__ <class 'NoneType'>
> __eq__ <class 'method-wrapper'>
> __format__ <class 'builtin_function_or_method'>
> __ge__ <class 'method-wrapper'>
> __getattribute__ <class 'method-wrapper'>
> __gt__ <class 'method-wrapper'>
> __hash__ <class 'method-wrapper'>
> __init__ <class 'method'>
> __le__ <class 'method-wrapper'>
> __lt__ <class 'method-wrapper'>
> __module__ <class 'str'>
> __ne__ <class 'method-wrapper'>
> __new__ <class 'builtin_function_or_method'>
> __reduce__ <class 'builtin_function_or_method'>
> __reduce_ex__ <class 'builtin_function_or_method'>
> __repr__ <class 'method-wrapper'>
> __setattr__ <class 'method-wrapper'>
> __sizeof__ <class 'builtin_function_or_method'>
> __str__ <class 'method-wrapper'>
> __subclasshook__ <class 'builtin_function_or_method'>
> __weakref__ <class 'NoneType'>
> abc <class 'str'>
> num <class 'int'>
> tup <class 'tuple'>
> Totale elementi: 28
> 
> 
> 
> 
> Hope this helps!
> 
> 
> 




More information about the Tutor mailing list