2016-05-19 3 views
1

Следующий код питона содержит ошибку:Как предотвратить функцию от преобразовывается к BOOL

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

if location.is_nighttime: 
    close_shades() 

Исправлена ​​ошибка в том, что программист забыл позвонить is_nighttime (или забыли использовать @property декоратор по методу) , поэтому метод отличает bool оценивается как True без вызова.

Есть ли способ предотвратить программист от этого, как в случае выше, так и в случае, когда is_nighttime является автономной функцией вместо метода? Например, что-то в следующем духе?

is_nighttime.__bool__ = TypeError 
+5

Вы забыли '()' для вызова функции. Объекты функций всегда правдивы. – TigerhawkT3

+1

Не должен ли код быть 'if is_nighttime():'? Или вы хотите каким-то образом предотвратить этот непреднамеренный тип? – NikoNyrh

+2

Нет. Если вы хотите поймать это, запустите linter. Точно так же вы не сможете предотвратить случайное включение функции в список или случайно распечатать функцию в stdout. – user2357112

ответ

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! 

Там еще много вещей, вы не можете поймать:

nighttime_list.append(is_nighttime) # No TypeError ._. 

И вы должны помнить, чтобы явно применить это к любой функции, которые вы не хотите рассматриваются как булевы. Вы также не можете многое делать о функциях и методах, которые вы не контролируете; например, вы не можете применить это к str.islower, чтобы поймать такие вещи, как if some_string.islower:.

Если вы хотите поймать такие вещи, я рекомендую вместо этого использовать инструменты статического анализа. Я думаю, что IDE, такие как PyCharm, могут вас предупредить, и там должны быть инструменты для линтинга, которые могут поймать это.


Если вы хотите, чтобы эти вещи работают как методы, вот дополнительная обработка для этого:

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)) 
-2

Короткий ответ: if is_nighttime():, с скобкой назвать.

Более длинный ответ:

is_nighttime указывает на функцию, которая является неконтактного типа Отсутствуют. if ищет условие, которое является логическим, и отбрасывает символ is_nighttime в boolean. Поскольку это не ноль, а не None, это правда.

+0

Сникер. Интересно, как часто может следовать этот цикл «ответа на вопрос -> изменить вопрос -> ответ нижнего уровня»? –

8

Это то, с чем вы можете столкнуться с анализом статического кода .

Например, pylint имеет related warning:

using-constant-test (W0125):

Используя условный оператор с постоянным значением излучаемого, когда условный оператор (Если или тройная, если) использует постоянное значение для его тест. Возможно, это не то, что должен был сделать пользователь .

Демо:

Если 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) 

При вызове:

$ pylint test.py 
************* Module test 
C: 1, 0: Missing module docstring (missing-docstring) 
C: 1, 0: Missing function docstring (missing-docstring) 
Смежные вопросы