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

Francesco Loffredo fal at libero.it
Wed Mar 15 08:24:56 EDT 2017


On 14/03/2017, Steven D'Aprano wrote:
> 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)

and Peter Otten wrote:
> 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
>

First of all, many thanks to both of you, Steven and Peter!

Steven taught me how to use getattr() instead of directly inspecting the 
results of dir(), thus leading me unlock the inner structure of the 
document I'm exploring; Peter solved the puzzle I stumbled on while 
searching, and taught me something about function namespace.

As to the use of exec() and bare except, Steven, I read the post you 
linked some time ago, and I thoroughly understand those are very 
dangerous and complex commands. But I think I used them with all due 
caution.

Due to my ignorance about  getattr(), I tried first using type(name) and 
later with inspect.getmembers(name), but both of them only applied to 
the string I gave them, instead of its meaning. That's why I felt forced 
to use exec. And it worked, while in the interpreter. I'm happy I did, 
because this made me learn something  from you!  (well, after a full 
weekend spent in failing efforts... ;-) )

As to the two bare excepts, I just don't care what the exception is, I'm 
only interested in knowing if there has been one, and I properly 
signalled it. So I think this is a proper use case for a bare except.

The output of dir(XSCRIPTCONTEXT.getDocument()), my real problem, is 290 
items long, and some of them (e.g. the first one, "AllVersions") cannot 
be accessed at all. So I always get at least one exception, but I just 
don't care of them.

After your help, I modified my routine, still using a bare except:

# 
---------------------------------------------------------------------------

# this only works as a Python macro called from LibreOffice
xModel = XSCRIPTCONTEXT.getDocument()
i = 0
questi = []
for i, name in enumerate(dir(xModel), 1):
     try:
         qqq = inspect.getmembers(getattr(xModel, name))
     except:
         qqq = "-NO AVAIL-"
     questi.append(str((name, qqq))+"\n")
questi.append(str(("Totale elementi:", " %s" % i)))
resultstring = "\n\n".join(questi)

# 
---------------------------------------------------------------------------

and the first lines of its much awaited output:

=============================================================

('AllVersions', '-NO AVAIL-')

...

('Args', [('__add__', <method-wrapper '__add__' of tuple object at 
0x7f2d18934048>), ('__class__', <class 'tuple'>), ('__contains__', 
<method-wrapper '__contains__' of tuple object at 0x7f2d18934048>), 
('__delattr__', <method-wrapper '__delattr__' of tuple object at 
0x7f2d18934048>), ('__dir__', <built-in method __dir__ of tuple object 
at 0x7f2d18934048>), ('__doc__', "tuple() -> empty 
tuple\ntuple(iterable) -> tuple initialized from iterable's items\n\nIf 
the argument is a tuple, the return value is the same object."), 
('__eq__', <method-wrapper '__eq__' of tuple object at 0x7f2d18934048>), 
('__format__', <built-in method __format__ of tuple object at 
0x7f2d18934048>), ('__ge__', <method-wrapper '__ge__' of tuple object at 
0x7f2d18934048>), ('__getattribute__', <method-wrapper 
'__getattribute__' of tuple object at 0x7f2d18934048>), ('__getitem__', 
<method-wrapper '__getitem__' of tuple object at 0x7f2d18934048>), 
('__getnewargs__', <built-in method __getnewargs__ of tuple object at 
0x7f2d18934048>), ('__gt__', <method-wrapper '__gt__' of tuple object at 
0x7f2d18934048>), ('__hash__', <method-wrapper '__hash__' of tuple 
object at 0x7f2d18934048>), ('__init__', <method-wrapper '__init__' of 
tuple object at 0x7f2d18934048>), ('__iter__', <method-wrapper 
'__iter__' of tuple object at 0x7f2d18934048>), ('__le__', 
<method-wrapper '__le__' of tuple object at 0x7f2d18934048>), 
('__len__', <method-wrapper '__len__' of tuple object at 
0x7f2d18934048>), ('__lt__', <method-wrapper '__lt__' of tuple object at 
0x7f2d18934048>), ('__mul__', <method-wrapper '__mul__' of tuple object 
at 0x7f2d18934048>), ('__ne__', <method-wrapper '__ne__' of tuple object 
at 0x7f2d18934048>), ('__new__', <built-in method __new__ of type object 
at 0x7f2d191dcc50>), ('__reduce__', <built-in method __reduce__ of tuple 
object at 0x7f2d18934048>), ('__reduce_ex__', <built-in method 
__reduce_ex__ of tuple object at 0x7f2d18934048>), ('__repr__', 
<method-wrapper '__repr__' of tuple object at 0x7f2d18934048>), 
('__rmul__', <method-wrapper '__rmul__' of tuple object at 
0x7f2d18934048>), ('__setattr__', <method-wrapper '__setattr__' of tuple 
object at 0x7f2d18934048>), ('__sizeof__', <built-in method __sizeof__ 
of tuple object at 0x7f2d18934048>), ('__str__', <method-wrapper 
'__str__' of tuple object at 0x7f2d18934048>), ('__subclasshook__', 
<built-in method __subclasshook__ of type object at 0x7f2d191dcc50>), 
('count', <built-in method count of tuple object at 0x7f2d18934048>), 
('index', <built-in method index of tuple object at 0x7f2d18934048>)])


('AutoStyles', [('CharacterStyles', pyuno object 
(com.sun.star.style.XAutoStyleFamily)0x7f2d30765c00{, 
supportedInterfaces={com.sun.star.style.XAutoStyleFamily,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak}}), 
('Count', 3), ('ElementNames', ('CharacterStyles', 'RubyStyles', 
'ParagraphStyles')), ('ElementType', <Type instance 
com.sun.star.style.XAutoStyleFamily (<Enum instance 
com.sun.star.uno.TypeClass ('INTERFACE')>)>), ('ImplementationId', 
<ByteSequence instance 'b'''>), ('ParagraphStyles', pyuno object 
(com.sun.star.style.XAutoStyleFamily)0x7f2d30765b20{, 
supportedInterfaces={com.sun.star.style.XAutoStyleFamily,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak}}), 
('RubyStyles', pyuno object 
(com.sun.star.style.XAutoStyleFamily)0x7f2cf6ad3f20{, 
supportedInterfaces={com.sun.star.style.XAutoStyleFamily,com.sun.star.lang.XTypeProvider,com.sun.star.uno.XWeak}}), 
('Types', (<Type instance com.sun.star.style.XAutoStyles (<Enum instance 
com.sun.star.uno.TypeClass ('INTERFACE')>)>, <Type instance 
com.sun.star.lang.XTypeProvider (<Enum instance 
com.sun.star.uno.TypeClass ('INTERFACE')>)>, <Type instance 
com.sun.star.uno.XWeak (<Enum instance com.sun.star.uno.TypeClass 
('INTERFACE')>)>)), ('getByIndex', <PyUNO_callable object at 
0x7f2d18a727b0>), ('getByName', <PyUNO_callable object at 
0x7f2d18a727c8>), ('getCount', <PyUNO_callable object at 
0x7f2d18a727e0>), ('getElementNames', <PyUNO_callable object at 
0x7f2d18a727f8>), ('getElementType', <PyUNO_callable object at 
0x7f2d18a72810>), ('getImplementationId', <PyUNO_callable object at 
0x7f2d18a72828>), ('getTypes', <PyUNO_callable object at 
0x7f2d18a72840>), ('hasByName', <PyUNO_callable object at 
0x7f2d18a72858>), ('hasElements', <PyUNO_callable object at 
0x7f2d18a72870>), ('queryAdapter', <PyUNO_callable object at 
0x7f2d18a72888>), ('queryInterface', <PyUNO_callable object at 
0x7f2d18a728a0>)])

...

('Totale elementi:', ' 290')

======================================================

Now I just have to search these 290 haystacks to find the fields I 
created in this form... but at least I have a magnifying glass.

THANKS !

Francesco


More information about the Tutor mailing list