如何防止函数被强制转换为bool

Jia*_*ian 2 python

以下python代码有一个bug:

class Location(object):
    def is_nighttime():
        return ...

if location.is_nighttime:
    close_shades()
Run Code Online (Sandbox Code Playgroud)

错误是程序员忘记调用is_nighttime(或忘记@property在方法上使用装饰器),因此该方法通过bool评估True而不被调用来进行转换.

有没有办法阻止程序员这样做,在上面的情况下,以及在is_nighttime一个独立的函数而不是方法的情况下?例如,具有以下精神的东西?

is_nighttime.__bool__ = TypeError
Run Code Online (Sandbox Code Playgroud)

use*_*ica 10

从理论上讲,您可以将函数包装在类似函数的对象中__call__,并将该函数委托给函数,并__bool__引发TypeError.它真的很笨拙,并且可能导致更多的错误交互而不是它会捕获 - 例如,除非你为此添加更多特殊处理,否则这些对象将无法用作方法 - 但你可以这样做:

class NonBooleanFunction(object):
    """A function wrapper that prevents a function from being interpreted as a boolean."""
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)
    def __bool__(self):
        raise TypeError
    __nonzero__ = __bool__

@NonBooleanFunction
def is_nighttime():
    return True  # We're at the Sun-Earth L2 point or something.

if is_nighttime:
    # TypeError!
Run Code Online (Sandbox Code Playgroud)

还有很多你无法捕捉到的东西:

nighttime_list.append(is_nighttime)  # No TypeError ._.
Run Code Online (Sandbox Code Playgroud)

而且你必须记住明确地将它应用于你不希望被视为布尔值的任何函数.你也无法做很多关于你无法控制的功能和方法; 例如,你不能用它str.islower来捕捉像这样的东西if some_string.islower:.

如果你想抓住这样的东西,我推荐使用静态分析工具.我认为像PyCharm这样的IDE可能会警告你,并且应该有可以捕获它的linting工具.


如果你希望这些东西作为方法工作,这里是额外的处理:

import functools

class NonBooleanFunction(object):
    ...  # other methods omitted for brevity
    def __get__(self, instance, owner):
        if instance is None:
            return self
        return NonBooleanFunction(functools.partial(self.func, instance))
Run Code Online (Sandbox Code Playgroud)


ale*_*cxe 8

这是您可以使用静态代码分析的方法.

例如,pylint有一个相关的警告:

using-constant-test (W0125):

使用具有常量值的条件语句当条件语句(If或三元if)使用常量值进行测试时发出.这可能不是用户想要做的.

演示:

如果is_nightmare没有被调用:

$ pylint test.py
************* Module test
C:  1, 0: Missing module docstring (missing-docstring)
C:  1, 0: Missing function docstring (missing-docstring)
W:  4, 0: Using a conditional statement with a constant value (using-constant-test)
Run Code Online (Sandbox Code Playgroud)

如果被叫:

$ pylint test.py
************* Module test
C:  1, 0: Missing module docstring (missing-docstring)
C:  1, 0: Missing function docstring (missing-docstring)
Run Code Online (Sandbox Code Playgroud)