[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