[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