[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