簡體   English   中英

TypeError: super(type, obj): obj 必須是類型的實例或子類型。 創建元類后調用 super 時出錯

[英]TypeError: super(type, obj): obj must be an instance or subtype of type. Error when calling super after metaclass creation

假設我使用了一個庫,他們的源代碼是按照這個形狀編寫的:

class SuperLibraryDemo:
    def __init__(self, test) -> None:
        self.test = test

    def demo(self) -> str:
        return "Returning from demo method with name: %s" % self.test


class LibraryDemo(SuperLibraryDemo):
    def __init__(self, test: str = "something") -> None:
        super(LibraryDemo, self).__init__(test)
        print("At LibraryDemo __init__ method: This should have been skipped")

    def demo(self) -> None:
        super().demo()

請記住,這是一個圖書館。 我不應該根據我的需要調整它的源代碼。 但是,出於此問題的LibraryDemo之外的原因,我需要在 LibraryDemo 中切換__init__方法調用的內部代碼。

考慮到這個目標,我決定在元類的幫助下編寫一個CustomLibraryDemo ,如下所示:

class MetaDemo(type):
    def __new__(mcs, class_name: str, bases: Tuple[Type, ...], class_dict: Dict[str, Any]):
        basis = bases[0]
        c_attrs = dict(basis.__dict__)
        prior_c_process_bases = basis.__base__
        c_attrs["__init__"] = lambda self, settings: prior_c_process_bases.__init__(self, settings)
        new_bases = types.new_class(basis.__qualname__, basis.__bases__,
                                    exec_body=lambda np: MetaDemo.populate_class_dict(np, c_attrs))
        return super(MetaDemo, mcs).__new__(mcs, class_name, (new_bases,), class_dict)

    @staticmethod
    def populate_class_dict(namespace: Dict[str, Any], attr: Dict[str, Any]) -> None:
        for key, value in attr.items():
            namespace[key] = value

class CustomLibraryDemo(LibraryDemo, metaclass=MetaDemo):
    def __init__(self, test: Optional[str] = None) -> None:
        super(CustomLibraryDemo, self).__init__(test)
        print("At CustomDemo __init__ method: This message should appear")

    def test(self) -> None:
        print("In test method at CustomLibraryDemo class: %s" % self.test)

雖然乍一看這種方法似乎對我有用,但當我調用CustomLibraryDemo().demo()時出現錯誤:

TypeError: super(type, obj): obj must be an instance or subtype of type

為什么?

您可能不需要自定義元類; 相反,只需將 arguments 調整為super

class CustomLibraryDemo(LibraryDemo):
    def __init__(self, test: Optional[str] = None) -> None:
        super(LibraryDemo, self).__init__(test)
        print("At CustomDemo __init__ method: This message should appear")

    def test(self) -> None:
        print("In test method at CustomLibraryDemo class: %s" % self.test)

在決定下一步使用哪個 class 時,使用LibraryDemo而不是CustomerLibraryDemo會導致super沿着 MRO 進一步啟動。

% python3 tmp.py
At CustomDemo __init__ method: This message should appear

這個問題解決了我的問題。 就我而言,在bases方法簽名上__new__ basis.__bases__參數可以解決問題。 這樣, new_bases變量的語法變成:

new_bases = types.new_class(basis.__qualname__, bases,
                                    exec_body=lambda np: MetaDemo.populate_class_dict(np, c_attrs))

順便說一句,這段代碼可以簡化為:

new_bases = type(basis.__qualname__, bases, c_attrs)

刪除populate_class_dict元類方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM