问题
Given the following code, I expect a return value of 'overridden'
not 'value1'
:
class MyMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs.update({'_my_dict': {'key1': 'value1', 'key2': 'value2'}})
return super().__new__(cls, name, bases, attrs)
def __getitem__(cls, value):
return cls._my_dict[str(value)]
class MyBaseClass(metaclass=MyMetaclass):
pass
class MyClass(MyBaseClass):
@classmethod
def __getitem__(cls, value):
return 'overridden'
>>> MyClass['key1']
'value1' # I expect: 'overridden'
What do I need to change?
回答1:
__getitem__
refers to the item-getting behaviors of the instances of the class it is defined on.
So, if you define a __getitem__
on the metaclass, it will work for the classes - if you write a __getitem__
on the class itself, it will only work for instances of that class.
You can however, write the metaclass __getitem__
so that it calls the class' __getitem__
if it exists - and then emulate this behavior:
class MyMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs.update({'_my_dict': {'key1': 'value1', 'key2': 'value2'}})
return super().__new__(cls, name, bases, attrs)
def __getitem__(cls, value):
for supercls in cls.__mro__:
if "__getitem__" in supercls.__dict__:
# getting the value straight from "__dict__" will prevent Python's mechanisms of converting it to a bound instance method:
return supercls.__dict__["__getitem__"](cls, value)
return cls._my_dict[str(value)]
class MyBaseClass(metaclass=MyMetaclass):
pass
class MyClass(MyBaseClass):
def __getitem__(cls, value):
return 'overridden'
Note that in this way, you could even use any other method name for a "class_getitem" in our hierarchy and still leave the usual __getitem__
available to be used by instances.
回答2:
You need to subclass the metaclass, override __getitem__
there, and set that metaclass in a new regular class.
来源:https://stackoverflow.com/questions/60781584/override-python-metaclass-getitem