Python中的空模式未被充分利用?

Tom*_*ora 18 python error-handling null

我偶尔遇到这样的代码:

foo = Foo()
...
if foo.bar is not None and foo.bar.baz == 42:
   shiny_happy(...)
Run Code Online (Sandbox Code Playgroud)

对我来说,这似乎是非语言的.

在Objective-C中,您可以将消息发送到nil并获得nil作为答案.我一直认为这很方便.当然可以在Python中实现Null模式,但是从Google给出的结果来看,似乎没有广泛使用.为什么?

或者甚至更好 - 让None.whatever返回None而不是提出例外是不是一个坏主意?

moz*_*ves 19

PEP 336 - Make None Callable提出了类似的功能:

None应该是一个可调用的对象,当使用任何参数调用时没有副作用并返回None.

它被拒绝的原因只是"它被认为是一种功能,在调用时会引发错误."

  • 一般的python哲学是通过`import this`找到的.具体来说:"面对模棱两可,拒绝猜测的诱惑." 如果没有找到显式的return语句,Python也会确保返回None.实现可以很容易地返回堆栈上的最后一个东西,比如lisp,或者是callable的第一个参数,比如smalltalk. (2认同)

Elo*_*off 14

对不起,但那个代码是pythonic.我认为大多数人会同意Python中的"显式优于隐式".与大多数人相比,Python是一种易于阅读的语言,人们不应该通过编写神秘的代码来打败它.使意义非常清楚.

foo = Foo()
...
if foo.bar is not None and foo.bar.baz == 42:
    shiny_happy(...)
Run Code Online (Sandbox Code Playgroud)

在这个代码示例中,很明显foo.bar在这个代码路径上有时是None,并且我们只运行shiny_happy()如果​​它不是None,并且.baz == 42.很清楚任何人这里发生了什么为什么 对于null模式或try ...,除了此处发布的答案中的代码之外,不能说同样的情况.如果您的语言(如Objective-C或javascript强制执行空模式)是一回事,但在一种根本不使用它的语言中,它只会产生难以阅读的混淆和代码.在python中编程时,就像pythonistas那样.


Ski*_*ick 13

你能不能试试除外?Pythonic方式表示要求宽恕比允许更容易.

所以:

try:
    if foo.bar.baz == 42:
        shiny_happy(...)
except AttributeError:
    pass #or whatever
Run Code Online (Sandbox Code Playgroud)

或者做到这一点,而不是可能使更多的异常沉默:

try:
    baz = foo.bar.baz
except AttributeError:
    pass # handle error as desired
else:
    if baz == 42:
        shiny_happy(...)
Run Code Online (Sandbox Code Playgroud)

  • @Skilldrick:你想念我的观点.如果foo根本没有属性栏怎么办?如果它有一个栏,但该栏没有.baz属性怎么办?更糟糕的是如果shiny_happy()引发了一个AttributeError?您无意中捕获(并忽略)多个可能的错误.那只是BAD编程.不好,因为您没有向读者说明您实际意味着忽略了多少这些错误条件,并且因为您确实忽略了它们,这可能是也可能不是正确的事情.这段代码是站不住脚的,让我感到非常难过,因为它得到了很多赞成. (5认同)
  • 像这样的静态`AttributeError`是一个*可怕的想法.这比原始代码要糟糕得多.如果`shiny_happy`或从中调用的代码有错误怎么办? (2认同)
  • 叹.这仍然可以掩盖错误.假设.bar或.baz有一个吸气剂. (2认同)

Jas*_*rff 11

便利性是以尽可能不及时检测到的愚蠢错误为代价的,尽可能接近有缺陷的代码行.

我认为这个特殊功能的便利性最多只是偶尔出现,而愚蠢的错误一直在发生.


当然,类似SQL的NULL对于测试来说是不好的,这确实会使命题无论是真还是假.从unittest.py考虑这段代码:

class TestCase:
    ...
    def failUnless(self, expr, msg=None):
        """Fail the test unless the expression is true."""
        if not expr: raise self.failureException, msg
Run Code Online (Sandbox Code Playgroud)

现在假设我有一个测试来执行此操作:

conn = connect(addr)
self.failUnless(conn.isOpen())
Run Code Online (Sandbox Code Playgroud)

假设connect错误地返回null.如果我正在使用"null模式",或者语言已经内置,并且conn为null,conn.isOpen()则为null,并且也not conn.isOpen()为null,因此断言通过,即使连接明显未打开.

我倾向于认为这NULL是SQL最差的功能之一.而null在其他语言中静默传递任何类型的对象的事实并没有好多少.(托尼霍尔称空参考"我十亿美元的错误".)我们需要更少的东西,而不是更多.