我遇到了一种情况,需要从另一个实现者那里得到要求,请遵循我的基类设计:
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
分成两个方法—一个抽象方法和另一个调用抽象方法并验证其返回值的方法:我终于想出了解决办法。你知道吗
其思想是在主类中实现
__getattribute__
,因此必须修改子类调用的方法。你知道吗考虑两个简单的类:由模块定义的
Foo
基类和由API用户定义的Bar
子类。Bar
类覆盖method
方法,但您希望它返回类型为int
的对象,以便保持与Foo.method
相同的行为。你知道吗当然,这没关系。 但是这里有一个使用
__getattribute__
方法的技巧。你知道吗我首先检查请求的属性是否命名为
"method"
。 如果是的话,我就创建一个自定义函数,它不是返回实际的method
,而是断言实际的method
的返回值是一个int
。你知道吗现在,
__getattribute__
方法的定义是这样的:instance.whatever
将导致对instance.__getattribute__("whatever")
的调用,而不管whatever
是否可以作为继承族中任何类的属性找到。你知道吗因此,如果
bar = Bar()
,那么bar.method
将被我在Foo.__getattribute__
中定义的内部_f
替换。你知道吗现在,
bar.method()
将产生一个AssertionError
,但是如果我按如下方式修改它:那么死刑就可以了。你知道吗
关于
__getattribute__
的定义,可能有点棘手,因为您不能调用self.something
,因为它会导致对__getattribute__
的递归调用。 解决方案是直接引用type(self).method
,它引用了这里由Bar
定义的类方法。 在这种情况下,此方法将instance
作为第一个参数,因此必须传递self
,因此行:当然,如果子类本身实现
__getattribute__
,所有这些都将失败。 但无论如何,不要忘记pythonapi很容易被破坏。 更具体地说,AssertError
很容易被捕获。 好吧,你可以用sys.exit(1)
代替assert
,但这可能有点太强制性了。。。你知道吗我有个主意。 这或多或少是一种反模式,Python方面的,因为它禁止用户自由地做他们想做的事情。 另一方面,人们可以用一个简单的
print
来代替assert
/raise
,以便教育用户,而不是惩罚他们。你知道吗相关问题 更多 >
编程相关推荐