Python OOP,对方法/类中的参数进行类型验证

ipe*_*tta 2 python oop types python-3.x

我试图理解Python中的OOP,并且我有这种"非pythonic思维方式"问题.我想要一个我的类的方法来验证参数的类型,如果它不是正确的类型(例如ValueError),则引发异常.我得到的最接近我的愿望是:

class Tee(object):
    def __init__(self):
        self.x = 0
    def copy(self, Q : '__main__.Tee'):
        self.x = Q.x
    def __str__(self):
        return str(self.x)

a = Tee()
b = Tee()
print(type(a))  # <class '__main__.Tee'>
print(isinstance(a, Tee))  # True
b.x = 255
a.copy(b)
print(a)        # 255
a.copy('abc')   # Traceback (most recent call last): [...]
                # AttributeError: 'str' object has no attribute 'x'
Run Code Online (Sandbox Code Playgroud)

所以,即使我试图确保Q我的copy方法中的参数类型属于同一个类,解释器只是通过它并AttributeError在尝试x从字符串中获取成员时引发它.

我明白我可以这样做:

[...]
    def copy(self, Q):
        if isinstance(Q, Tee):
            self.x = Q.x
        else:
            raise ValueError("Trying to copy from a non-Tee object")
[...]
a = Tee()
a.copy('abc')   # Traceback (most recent call last): [...]
                # ValueError: Trying to copy from a non-Tee object
Run Code Online (Sandbox Code Playgroud)

但是,即使我创建了一个专用的函数,方法或装饰器,在类的各个地方实现它仍然需要做很多工作.所以,我的问题是:对此有更多的"pythonic"方法吗?

顺便说一下,我正在使用Python 3.6.5.

dec*_*eze 5

类型注释不会在运行时强制执行.期.它们目前仅供IDE或静态分析器(如mypy)使用,或者由您自己编写的任何代码使用,以反映这些注释.但由于Python主要基于duck typing,因此运行时不会也不会实际执行类型.

如果在开发期间使用静态类型检查器来捕获此类错误,这通常就足够了.如果要进行实际的运行时检查,可以使用断言:

assert isinstance(Q, Tee), f'Expected instance of Tee, got {type(Q)}'
Run Code Online (Sandbox Code Playgroud)

但它们也主要用于调试,因为可以关闭断言.要拥有强类型断言,您需要明确:

if not isinstance(Q, Tee):
    raise TypeError(f'Expected instance of Tee, got {type(Q)}')
Run Code Online (Sandbox Code Playgroud)

但同样,这可以防止鸭子打字,这并不总是令人满意的.

顺便说一句,你的类型注释应该只是def copy(self, Q: 'Tee'),不包括'__main__'; 另见https://docs.python.org/3/whatsnew/3.7.html#whatsnew37-pep563.