Dan Snider <mr.assume.a...@gmail.com> added the comment:

It's working as intended. locals() and vars() simply returns the current 
frame's f_locals. In functions, modifying this usually accomplishes nothing 
useful because the code object has OPTIMIZED and NEWLOCALS flags set, meaning 
local variables are looked up or set via the LOAD_FAST and STORE_FAST opcodes 
(respectively) which doesn't even look in the f_locals mapping. In this case, 
vars() and locals() will build a new dict[*] and fill it with the frame's 
fastlocals and unpack any closure cells into it.

The code object used for class bodies however is special and actually *does* 
use the mapping in f_locals, which for for classes ultimately built by 
builtins.__build_class__ (aka classes built with a `class` statement) will be 
whatever the metaclass's __prepare__ returns, which in the case of enums is an 
enum._EnumDict instance. 

So that's why metaclasses are so powerful. You don't even need to use a 
dictionary subclass as the class namespace, since the STORE_NAME opcode will 
use PyObject_SetItem; however type.__new__ will make you cast it to a dict, and 
even the dict that is wrapped by a MappingProxy after the class has been 
created will be a copy anyway. 

So anyway, there's nothing actually wrong with the current behavior. 
dict.update never calls `self.__getitem__`, and since `_EnumDict.__setitem__` 
is where all of the magic happens regular dict.update won't trigger it. I agree 
though that adding an update method would be nice though and can be done in 
just a few lines of code.

    import enum
    import sys

    def local_update(it=(), **kws):
        self = sys._getframe(1).f_locals
        d = dict(it, **kws)
        for k, v in d.items():
            self[k] = v
            
    class MyEnum(enum.Enum):
        local_update(a=1, b=2)
        
    assert MyEnum.a.value == 1

[*] it doesn't actually build a new one every time but the only practical 
purpose with the NEWLOCALS code.co_code flag set is for introspection with 
vars(), locals(), and sys._getframe

----------
nosy: +bup

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue34750>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to