[Tutor] set locals
spir
denis.spir at gmail.com
Wed Dec 18 11:40:40 CET 2013
On 12/18/2013 10:02 AM, Peter Otten wrote:
> spir wrote:
> [...]
> Like Steven I have no idea how you produced the mappingproxy. Are you trying
> to use a class as a namespace (in Python 3.3)?
>
>>>> class A: pass
> ...
>>>> A.__dict__["foo"] = "bar"
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> TypeError: 'mappingproxy' object does not support item assignment
I have no idea neither, for me it's just a term in an error message. Here is a
minimal reduction of the context, that produces similar outcome (py 3.3):
EDIT: you are right about class dicts, see below.
def set_var(scope, id, value):
scope[id] = value
set_var(locals(), "foo", 'FOO')
assert(foo == 'FOO') # OK
bar = 'bar'
set_var(globals(), "bar", 'BAR')
assert(bar == 'BAR') # OK
class C:
pass
set_var(C.__dict__, "baz", 'BAZ')
# ==> TypeError: 'mappingproxy' object does not support item assignment
assert(C.baz == 'BAZ') # statement never reached
C.baz = "trial to define symbol first"
set_var(C.__dict__, "baz", 'BAZ')
# ==> TypeError: 'mappingproxy' object does not support item assignment
assert(C.baz == 'BAZ') # statement never reached
It is effectively the case that I like to use classes as namespaces (to define
grammars / parsers): they are highly practicle, one can even have computation in
their def! They're kind of sub-modules, in fact; free scopes. So, it was
actually so that the error happened in such a case; and thus "mappingproxy"
seems to be an implementation term for a class's dict, or so.
This does explain why we cannot modify them (as we can do it in plain python
code, but symbol names must be constant). But I have no solution for my issue:
there is no way to write:
c.id = value
with id beeing a variable. Or is there? As fat as I know I really need to do
c.__dict__[id_var] = value
EDIT: works!!!
I tried
C.__setattr__(C, "baz", "BAZ")
which fails, for any reason, with
TypeError: can't apply this __setattr__ to type object
But the direct way works fine, for any reason:
setattr(C, "baz", "BAZ")
Thus we can modify set_var like eg:
def set_var(scope, id, value):
if isinstance(scope, type):
setattr(scope, id, value)
else:
scope[id] = value
Which then enables:
class C:
pass
set_var(C, "baz", 'BAZ')
assert(C.baz == 'BAZ') # OK
=======================
For the record, here in (the code of) my final tool func:
def name (scope): # name all defined pattern in given scope
# Note: if scope is a class, there is a distinction between the scope
# and the actual dict we traverse (c.__dict__): for any reason, we
# cannot set entries in a class's dict directly, but must use setattr.
dic = scope.__dict__ if isinstance(scope, type) else scope
# all patterns in scope (in dic, in fact):
names_pats = ((name, pat) for (name, pat) in dic.items() \
if isinstance(pat, Pattern))
for (name, pat) in names_pats:
# If the original pat is already named, leave it as is and
# instead create a copy with the new name:
if pat.name:
new_pat = copy(pat)
new_pat.name = name # give it its name
if isinstance(scope, type): # case scope is a class
setattr(scope, name, new_pat)
else: # case scope is module or local
scope[name] = new_pat
# Else, this is a new pattern, which just demands a name:
else:
pat.name = name
# Special case of recursive pattern,
# also name its actual matching pattern:
if isinstance(pat, Recurs):
pat.pattern.name = name
Issue solved ;-). Thank you vey much,
Denis
More information about the Tutor
mailing list