2

标题几乎解释了这个问题。我不知道是否有实用的解决方案,或者我是否对代码的行为过于挑剔。这篇文章暗示了正确的方向,但我从来没有任何代码可以工作。 https://medium.com/@adamshort/python-gems-5-silent-function-chaining-a6501b3ef07e

这是我想要的功能示例:

class Calc:
    def __init__(self, n=0):
        self.n = n

    def add(self, n):
        self.n += n
        return self

    def might_return_false(self):
        return False

    def print(self):
        print(self.n)
        return self


w = Calc()

# The rest of the chain after might_return_false should be ignored
addedTwice = w.add(5).might_return_false().add(5).print()

w.print() # Should print 5

print(addedTwice) # Should print False
4

2 回答 2

3

我认为这篇文章的意思或多或少类似于下面的内容(但我更喜欢使用异常的另一个答案,因为它更具可读性和更好的可测试性)。创建一个辅助类:

class Empty:
    def __call__(self, *args, **kwargs):
        return self
    def __getattr__(self, *args, **kwargs):
        return self
    def print(self, *args, **kwargs):
        return False

def might_return_false(self):
    return Empty()
于 2020-05-17T20:57:30.667 回答
2

异常是中断链式操作的好方法:

class CalcError(Exception):
    pass


class Calc:
    def __init__(self, n: int = 0):
        self.n = n

    def add(self, n: int) -> 'Calc':
        self.n += n
        return self

    def might_raise(self) -> 'Calc':
        raise CalcError

    def __str__(self) -> str:
        return str(self.n)


w = Calc()

try:
    w.add(5).might_raise().add(5)
    addedTwice = True
except CalcError:
    addedTwice = False

print(w)           # prints 5
print(addedTwice)  # prints False

你也可以像这样做链:

w = Calc()
num_added = 0
try:
    w.add(5)
    num_added += 1
    w.add(5)
    num_added += 1
    w.might_raise()
    w.add(5)
    num_added += 1
    w.add(5)
    num_added += 1
except CalcError:
    print(f"Stopped after {num_added} additions")

如果您尝试使用return而不是执行此操作,则raise需要检查链的每个步骤的状态,以便您可以切换到其他代码分支(可能通过if块)。引发异常具有立即中断执行的非常有用的特性,无论您身在何处,并直接将您带到最近的匹配项except

于 2020-05-17T20:52:15.907 回答