В основном для забавы, чтобы помочь с эргономикой парсера, который я пишу, я бы очень хотел переопределить класс '__getattr__
, не делая того же для его подклассов. Для объяснения приведем код:
class AttrMeta(type):
def __getattr__(self, name):
if name == "A":
return "hi there."
class Main(metaclass=AttrMeta):
pass
class Subclass(Main):
pass
print(Main.A) # => hi there.
print(Subclass.A) # => hi there.
print(Main().A) # => AttributeError: 'Main' object has no attribute 'A'
print(Subclass().A) # => AttributeError: 'Subclass' object has no attribute 'A'
Это все нормально, но я бы хотел, чтобы Subclass
не наследовал __getattr__
. Для этого первым делом я попытался переопределить __new__
в AttrMeta
следующим образом:
# in AttrMeta...
def __new__(mcs, name, bases, namespace, **kwargs):
if bases:
return type.__new__(type, name, bases, namespace, **kwargs)
return type.__new__(mcs, name, bases, namespace, **kwargs)
Идея состояла в том, чтобы убрать метакласс из подклассов Main
, которые обнаруживаются глядя на bases
. Это привело к бесконечным рекурсиям при создании class Subclass(Main)
, что имеет смысл - как вы могли иметь такую разорванную цепочку наследования?
Моя следующая идея состояла в том, чтобы удалить __getattr__
вручную:
# in AttrMeta...
def __new__(mcs, name, bases, namespace, **kwargs):
new_cls = type.__new__(mcs, name, bases, namespace, **kwargs)
if bases:
del new_cls.__getattr__
return new_cls
Что ж, в ретроспективе очевидно, что вы не можете этого сделать: вы получаете AttributeError: __getattr__
. Это потому, что Subclass.__getattr__
связан с AttrMeta
- на самом деле, "__getattr__" not in dir(Subclass)
имеет место.
В этот момент я сказал себе: эй. Тим Питерс сказал, что люди, которым нужны метаклассы, знают это на самом деле, и я просто не из этих людей. На самом деле мне совсем не нужно писать этот парсер, я просто пытаюсь, вы знаете, немного отвлечься во время карантина. Возможно, я просто сделаю это, назначив __getattr__
в классе и посмотрим, что произойдет. Итак, я попробовал:
class Main:
pass
class Subclass(Main):
pass
def __getattr__(self, name):
if name == "A":
return "hi there."
Main.__getattr__ = __getattr__
Main.A # raises AttributeError: type object 'Main' has no attribute 'A'
На данный момент у меня закончились идеи. Я, вероятно, просто сдамся и позволю Subclass
иметь атрибут getter. Я не хочу переопределять __getattr__
на каждом Subclass
, поскольку их много, но мне было любопытно, есть ли какие-нибудь идеи там. Спасибо за чтение этого длинного поста.