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很容易被破坏