Modifying class __dict__ when shadowed by a property

前端 未结 3 1035
眼角桃花
眼角桃花 2021-01-05 05:04

I am attempting to modify a value in a class __dict__ directly using something like X.__dict__[\'x\'] += 1. It is impossible to do the modification

3条回答
  •  情深已故
    2021-01-05 05:16

    This probably counts as an "additional name" you don't want, but I've implemented this using a dictionary in the metaclass where the keys are the classes. The __next__ method on the metaclass makes the class itself iterable, such that you can just do next() to get the next ID. The dunder method also keeps the method from being available through the instances. The dictionary storing the next id has a name starting with a double underscore, so it's not easily discoverable from any of the classes that use it. The incrementing ID functionality is thus entirely contained in the metaclass.

    I tucked the assignment of the id into a __new__ method on a base class, so you don't have to worry about it in __init__. This also allows you to del Meta so all the machinery is a little harder to get to.

    class Meta(type):
        __ids = {}
    
        @property
        def id(cls):
            return __class__.__ids.setdefault(cls, 0)
    
        def __next__(cls):
            id = __class__.__ids.setdefault(cls, 0)
            __class__.__ids[cls] += 1
            return id
    
    class Base(metaclass=Meta):
        def __new__(cls, *args, **kwargs):
            self = object.__new__(cls)
            self.id = next(cls)
            return self
    
    del Meta
    
    class Class(Base):
        pass
    
    class Brass(Base):
        pass
    
    c0 = Class()
    c1 = Class()
    
    b0 = Brass()
    b1 = Brass()
    
    assert (b0.id, b1.id, c0.id, c1.id) == (0, 1, 0, 1)
    assert (Class.id, Brass.id) == (2, 2)
    assert not hasattr(Class, "__ids")
    assert not hasattr(Brass, "__ids")
    

    Note that I've used the same name for the attribute on both the class and the object. That way Class.id is the number of instances you've created, while c1.id is the ID of that specific instance.

提交回复
热议问题