Python 需要特定的返回类型

Python 需要特定的返回类型,python,Python,我有一种情况,我需要从另一个实现者那里获得,遵循我的基类设计: class ExemplaryClass: pass class Base(ABC): @abstractmethod def process(self): # should return specific type, for instance ExemplaryClass 和派生类,将由其他程序员创建: class Derived(Base): def process(self)

我有一种情况,我需要从另一个实现者那里获得,遵循我的基类设计:

class ExemplaryClass:
    pass

class Base(ABC):
    @abstractmethod
    def process(self):
        # should return specific type, for instance ExemplaryClass
和派生类,将由其他程序员创建:

class Derived(Base):
    def process(self):
        # if return sth different from ExemplaryClass, should throw exception
我怎样才能通过代码迫使程序员遵循我的设计? 在C++和其他带有静态类型控制的语言中,这个问题很简单:

class ExemplaryClass {}

class Base{
public:
    virtual ExemplaryClass proccess() =0;
}

class Derived :public Base {
public:
    // ERROR
    void proccess() ovveride { }
}

但是在像python这样带有动态类型控制的语言中,这种情况非常复杂,我不知道如何解决这个问题

正如其他人在评论中指出的那样,进行此类类型检查是不好的做法。但是如果您确实想这样做,可以将
process
分为两个方法-一个抽象方法和另一个调用抽象方法并验证其返回值的方法:

class Base(ABC):
    def process(self):
        result = self._process()
        assert isinstance(result, ExemplaryClass)
        return result

    @abstractmethod
    def _process(self):
        raise NotImplementedError

正如其他人在评论中指出的那样,进行此类类型检查是不好的做法。但是如果您确实想这样做,可以将
process
分为两个方法-一个抽象方法和另一个调用抽象方法并验证其返回值的方法:

class Base(ABC):
    def process(self):
        result = self._process()
        assert isinstance(result, ExemplaryClass)
        return result

    @abstractmethod
    def _process(self):
        raise NotImplementedError

我终于想出了一个解决办法

其思想是在主类中实现
\uuuu getattribute\uuu
,因此必须修改子类调用的方法

考虑两个简单的类:由模块定义的
Foo
基类和由API用户定义的
Bar
子类。
Bar
类覆盖
方法
方法,但您希望它返回类型为
int
的对象,以便保持与
Foo.method
相同的行为

class Foo:
    def method(self):
        return 1

class Bar(Foo):
    def method(self):
        return "a"
当然,这没关系。 但是这里有一个使用
\uuu getattribute\uu
方法的技巧

我首先检查请求的属性是否命名为
“method”
。 然后,如果是,我创建一个自定义函数,而不是返回实际的
方法
,该additionnal断言实际的
方法
的返回值是一个
int

def __getattribute__(self, attribute):
    if attribute == "method":

        def _f(*args, **kwargs):
           result = type(self).method(self, *args, **kwargs)
           assert isinstance(result, int)
           return result

        return _f
现在,
\uuuuu getattribute\uuuuu
方法的定义使得
instance.which
将导致调用
instance

因此,如果
bar=bar()

现在,
bar.method()
将产生一个
AssertionError
,但如果我按如下方式修改它:

class Bar(Foo):
    def method(self):
        return 1
那么死刑就可以了


关于
\uuuuu getattribute\uuuu
的定义,这可能有点棘手,因为您不能调用
self.something
,因为它会导致对
\uuuuu getattribute\uuuu
的递归调用。 解决方案是直接引用
type(self).method
,它引用
Bar
在此定义的类方法。 在这种情况下,此方法将
实例
作为第一个参数,因此必须传递
self
,因此行:

result = type(self).method(self, *args, **kwargs)
当然,如果子类本身实现了
\uuu getattribute\uuu
,所有这些都将失败。 但无论如何,不要忘记Python API很容易被破坏。 更具体地说,
AssertError
很容易被捕获。 好的,您可以用
sys.exit(1)
替换
assert
,但这可能有点太强制了


我刚有个主意。 这或多或少是一种反模式,在Python方面,因为它禁止用户自由地做他们想做的事情。
另一方面,人们可以用一张印刷品来代替断言,以教育用户而不是惩罚他们。

我终于想出了一个解决办法

其思想是在主类中实现
\uuuu getattribute\uuu
,因此必须修改子类调用的方法

考虑两个简单的类:由模块定义的
Foo
基类和由API用户定义的
Bar
子类。
Bar
类覆盖
方法
方法,但您希望它返回类型为
int
的对象,以便保持与
Foo.method
相同的行为

class Foo:
    def method(self):
        return 1

class Bar(Foo):
    def method(self):
        return "a"
当然,这没关系。 但是这里有一个使用
\uuu getattribute\uu
方法的技巧

我首先检查请求的属性是否命名为
“method”
。 然后,如果是,我创建一个自定义函数,而不是返回实际的
方法
,该additionnal断言实际的
方法
的返回值是一个
int

def __getattribute__(self, attribute):
    if attribute == "method":

        def _f(*args, **kwargs):
           result = type(self).method(self, *args, **kwargs)
           assert isinstance(result, int)
           return result

        return _f
现在,
\uuuuu getattribute\uuuuu
方法的定义使得
instance.which
将导致调用
instance

因此,如果
bar=bar()

现在,
bar.method()
将产生一个
AssertionError
,但如果我按如下方式修改它:

class Bar(Foo):
    def method(self):
        return 1
那么死刑就可以了


关于
\uuuuu getattribute\uuuu
的定义,这可能有点棘手,因为您不能调用
self.something
,因为它会导致对
\uuuuu getattribute\uuuu
的递归调用。 解决方案是直接引用
type(self).method
,它引用
Bar
在此定义的类方法。 在这种情况下,此方法将
实例
作为第一个参数,因此必须传递
self
,因此行:

result = type(self).method(self, *args, **kwargs)
当然,如果子类本身实现了
\uuu getattribute\uuu
,所有这些都将失败。 但无论如何,不要忘记Python API很容易被破坏