Python - typechecking确定何时不会抛出错误?

时间:2013-05-10 06:48:40

标签: python oop

我有一些Python类,如果简化,看起来像:

class base:
    def __init__(self, v):
        self.value = v

    def doThings(self):
        print "Doing things."

    def doMoreThings(self):
        print "Doing more things."

    def combine(self, b):
        self.value += b.value

class foo(base):
    def showValue(self):
        print "foo value is %d." % self.value

class bar(base):
    def showValue(self):
        print "bar value is %d." % self.value

base类包含方法(由doThingsdoMoreThings表示),它们实现foobar子类共有的功能。 foobar子类的不同之处主要在于它们如何解释value字段。 (上图,它们只是在打印时显示的不同,但在我的实际应用中,它们会做其他一些更复杂的事情。)base可以被认为是“抽象的”:用户只能使用foobarbase仅作为其子类共有的代码的主页存在。

我想问的方法是combine,它可以让你拿走其中两个对象并制作第三个。由于foobarvalue的解释不同,因此对combine两个不同类型的子类没有意义:您可以combine两个{{1}获取foo或两个foo来获取bar但不是barfoo。即便如此,bar的过程对于所有子类来说都是相同的,因此将其分解并在一个地方定义是有意义的。

如果用户试图combine两个不兼容的对象,我可能会发出错误信号,但是我没有看到一种方法可以在不引入丑陋的类型检查的情况下执行此操作。这样做是好的做法吗?或者我应该做通常的事情,而不是检查,记录问题,并假设用户不会尝试以一种非预期的方式使用combine,即使这样的使用似乎“成功”并返回一个垃圾对象而不是引发错误?

感谢您的帮助。

4 个答案:

答案 0 :(得分:3)

我在这里看到了几种方法:

  1. 不要检查任何内容并信任用户做正确的事情。根据具体情况,可能是适当的或危险的。

  2. 检查类型。你是对的,它看起来很难看,但却是最简单的事情。

  3. 没有value,但是按照他们想要的方式命名(pressuretemperature)并让他们自己组合。

  4. 与3相同,但另外还有子类有property,它将对.value的访问映射到它们各自的“实际”值变量。这样,您可以保留。__init__(),但.combine()必须由每个子类完成。

  5. 与4相同,但不要使用property,而是使用自制的descriptor。在this answer中,我展示了如何做到这一点。

答案 1 :(得分:2)

更改合并方法

def combine(self, b):
    if (not(self.__class__.__name__ == b.__class__.__name__)):
        raise TypeError("%s cannot combine with %s" % ( self.__class__.__name__, b.__class__.__name__))
    else:        
        self.value += b.value

或者,将base的类定义更改为

class base(object):

然后可以使用更简单,更好,更快乐的组合方法(谢谢glglgl)

def combine(self, b):
    if (not(type(self) == type(b))):
        raise TypeError("%s cannot combine with %s" %
                        ( type(self), type(b) ))
    else:        
        self.value += b.value

答案 2 :(得分:0)

当我处理不会失败的生产代码时,我使用了一个装饰器,确保风险函数不会爆炸,变成火球并炸毁我的整个系统。

def bulltproof(func):
    def _bulletproof(*args, **kwargs):
        try:
            result = func(*args, **kwargs)
        except Exception as exc:
            raise BulletproofError(exc)
        return result
    return _bulletproof

使用它:

@bulletproof
def some_risky_function():
    #....

只捕获一个错误:

try:
    some_risky_function()
except Bulletproof:
...

您可以返回None而不是引发错误,记录错误或将其关闭以进行测试。当然,当你想确保你的程序能够从错误中恢复时,这种方法很有用,但有时最好还是死而不是继续出错

答案 3 :(得分:0)

由于.combine()在概念上完全不同,取决于对象是foo还是bar,因此我认为不要在抽象父级中使用该函数,而是将它保存在派生类中。即使它是相同的代码,组合foo的两个实例将与组合bar的两个实例不同。如果.combine()的代码实际上非常冗长,您可以在基类中创建一个私有方法来完成工作,但只能从派生类中定义的函数中调用它。