0

The following code works in Python 2.7 with _x.__dict__['c']=8

class _x:
    def __init__(self):
        self.a = 6
        self.b = 7
        _x.__dict__['c']=8
        print("good!")

y=_x()
print(y.__dict__)
print(_x.__dict__)

Output:

good!
{'a': 6, 'b': 7}
{'c': 8, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x00000000049227B8>}

The above code does not work in Python 3.6 with _x.__dict__['c']=8 and got errors:

TypeError                             Traceback (most recent call last)
<ipython-input-5-b4146e87f5a4> in <module>()
      6         print("good!")
      7 
----> 8 y=_x()
      9 print(y.__dict__)
     10 print(_x.__dict__)

<ipython-input-5-b4146e87f5a4> in __init__(self)
      3         self.a = 6
      4         self.b = 7
----> 5         _x.__dict__['c']=8
      6         print("good!")
      7 

TypeError: 'mappingproxy' object does not support item assignment

Any suggestions?

Zoe
  • 27,060
  • 21
  • 118
  • 148
ozinfo
  • 1
  • 1
  • 3
    Why do you want to go through `__dict__`? Do you just not know about `setattr`? – user2357112 Nov 05 '18 at 19:48
  • 1
    Why are you doing this? It's usually a very bad idea for new construction to just set values on the class (the rare case where it makes sense is when you're numbering instances or the like, but in that case, the class variable should be defined with a base value at definition time). This smells [like an XY problem](https://meta.stackexchange.com/q/66377/322040). – ShadowRanger Nov 05 '18 at 19:58
  • found a solution: `_x.c = 8` works. – ozinfo Nov 05 '18 at 20:01
  • user2357112, ShadowRanger: I am converting a python application (by another author) from 2 to 3. Just want to make it work right now and figure out "why" later. Thanks for your comments. – ozinfo Nov 06 '18 at 21:57

2 Answers2

0

Is there any reason you're trying to use non-public interface? If for some reason you want to set class attribute during instantiation, try

class A:
    def __init__(self):
        self.__class__.k = 1

If you want to set access dynamically, use setattr

Reasoning behind mutability changes described in this answer

Slam
  • 8,112
  • 1
  • 36
  • 44
  • Note: This will differ behaviorally if `A` is subclassed; the OP's approach would always set the attribute on `A`, while this will set the attribute on the subclass if applicable. Plain `A.k = 1` (or as a sneaky approach only valid on Python 3+, and dependent on CPython implementation details, `__class__.k = 1`) would match the OP's design. – ShadowRanger Nov 05 '18 at 19:59
  • Correct, directly setting is an option too, but it's even less viable in proper interfaces, IMO. – Slam Nov 05 '18 at 20:01
  • Thanks a lot for your help, Slam. – ozinfo Nov 06 '18 at 21:44
0

You can set a class variable by specifying the class name before the variable name.

Change:

_x.__dict__['c']=8

to:

_x.c=8
blhsing
  • 91,368
  • 6
  • 71
  • 106