简体   繁体   English

如何测试 python class 不是协议的子类

[英]How to test that a python class does not subclass a protocol

I need to make sure that developers on my team are not directly subclassing a typing.Protocol instance.我需要确保我团队中的开发人员没有直接typing.Protocol实例。 That is, although their classes should implement the interface of the Protocol, we don't want:也就是说,虽然它们的类应该实现协议的接口,但我们不希望:

class MyClass(MyProtocol):
    # inherits MyProtocol

which would coerce the class to be a subclass of the Protocol and, therefore, necessarily pass isinstance(MyClass(), MyProtocol) even if it does not implement any logic in the attributes and methods of the class.这将强制 class 成为协议的子类,因此即使它没有在 class 的属性和方法中实现任何逻辑,也必须传递isinstance(MyClass(), MyProtocol)

Example of the problem:问题示例:

class MyProtocol(Protocol):
    def foo(self):
        raise NotImplementedError("Don't subclass MyProtocol!")

class MyClass(MyProtocol):
    pass

# MyClass now has foo since it inherits the Protocol...
assert hasattr(MyClass(), 'foo')

In other words, I would like a test of the form:换句话说,我想要一个表格测试:

def does_not_subclass_protocol(obj, protocol):
    # returns True if and only if obj does not have
    # MyClass(MyProtocol)...
    # syntax in class definition.

You can prohibit subclassing in the Protocol and use typing.runtime_checkable :您可以在协议中禁止子类化并使用typing.runtime_checkable

from typing import Protocol, runtime_checkable


@runtime_checkable
class MyProtocol(Protocol):
    def foo(self): ...
    
    def __init_subclass__(cls, *args, **kwargs):
        raise TypeError

I don't know whether the type checker will ignore the magic method __init_subclass__ because I can only test on my mobile phone now.我不知道类型检查器是否会忽略魔术方法__init_subclass__因为我现在只能在手机上测试。

Direct implementation Protocol:直接实现协议:

>>> class MyClass:
...     def foo(self):
...         print('hello')
...
>>> isinstance(MyClass(), MyProtocol)
True

Inheritance agreement: Inheritance 协议:

>>> class MyClass(MyProtocol): pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/data/user/0/ru.iiec.pydroid3/files/aarch64-linux-android/lib/python3.9/abc.py", line 106, in __new__
    cls = super().__new__(mcls, name, bases, namespace, **kwargs)
  File "<stdin>", line 6, in __init_subclass__
TypeError

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM