2014-01-24 4 views
4

Предположим, у вас есть функция, которая может вернуть некоторый объект или нет:Не вызывайте функцию, если None Возвращаемое значение

def foobar(arg): 
    if arg == 'foo': 
     return None 
    else: 
     return 'bar' 

Теперь вы вызываете этот метод и вы хотите сделать что-то с объектом, для этого примера Я получаю str, поэтому я могу назвать функцию upper(). Есть теперь два случая, которые могут произойти, когда второй один потерпит неудачу, потому что никто не имеет метода upper()

foobar('sdfsdgf').upper() 
foobar('foo').upper() 

, конечно, это теперь легко исправить:

tmp = foobar('foo') 
if tmp is not None: 
    tmp.upper() 
# or 
try: 
    foobar('foo').upper() 
except ArgumentError: 
    pass 
# or 
caller = lambda x: x.upper() if type(x) is str else None 
caller(foobar('foo')) 

но обработка исключений возможно, не является достаточно точным, и может случиться, что я поймаю исключение, которое может быть важным (= отладка становится сложнее), в то время как первый метод хорош, но может привести к увеличению кода, а третий вариант выглядит довольно неплохо, но вы должны это сделать для всех возможных функций, поэтому метод один, вероятно, лучший.

Интересно, есть ли какой-либо синтаксический сахар, который прекрасно справляется с этой проблемой?

+2

Вы можете вернуть пустую строку вместо «Нет». – Eddie

+0

да, конечно, но предположим, что функция i call - это библиотека, и я не хочу менять API. – reox

+0

У вас может быть только синтаксический aproach, так как должен быть вызов: ret = foobar (arg); ret.upper(), если ret else pass – cox

ответ

13

Вы можете использовать:

(foobar('foo') or '').upper() 

Выражение внутри скобок возвращает строку, даже если foobar() возвращает falsy значение.

Этот делает результат None заменяется пустой строкой. Если ваш код полагается на None, который оставлен на месте, ваш лучший выбор по-прежнему заключается в использовании отдельного оператора if для вызова .upper(), только если возвращаемое значение не равно None.

+0

! я никогда не думаю обо всех языковых возможностях сразу :) – reox

+1

Этот трюк 'или' опрятен, если у вас нет _several_ фальшивых значений в возможных возвратах (' 0', '" ",' None', '[]' , и т.д.). Просто напоминание ... – Alfe

+0

@Alfe: Абсолютно, но так как вы хотите иметь возможность называть '.upper()' здесь, это выглядит как * отличный * результат использования 'или'. :-) –

0

Альтернативный подход - первый/третий варианты могут быть обернуты:

def forward_none(func): 
    def wrapper(arg): 
     return None if arg is None else func(arg) 
    return wrapper 

И имейте в виду, что методы не должны использоваться в качестве методов - они все еще атрибуты класса, и когда ищется в классе, они простые функции:

forward_none(str.upper)(foobar('foo')) 

и мы можем также использовать это в качестве декоратора:

@forward_none 
def do_interesting_things(value): 
    # code that assumes value is not None... 

do_interesting_things(None) # ignores the original code and evaluates to None 
do_interesting_things("something") # as before decoration 

Хотя на практике, если бы я должен был, я бы, вероятно, сделал то, что предлагает Мартийн. И я бы очень старался не делать этого; попадание в эту ситуацию - это запах кода, предполагающий, что мы должны были создать исключение, а не возвращать None. :)

3

Поскольку на этот вопрос был дан ответ, есть несколько новых разработок, которые делают этот шаблон немного проще.

Пакет pymaybe позволяет просто обернуть свои ценности с maybe молча распространяются None значения:

from pymaybe import maybe 
maybe(foobar('foo')).upper() 

Это очень похоже на ответ по Martijn Питерс исключением того, что она сохраняет None значения вместо того, чтобы заменить их пустую строку, и она будет более надежной при наличии нескольких значений falsey.

Кроме того, похоже, что существует проект предложения по стандартным трекам на уровне PEP 505, который выглядит так, чтобы добавить синтаксисы, подобные аксессуарам C# ?., к самому языку. Я не уверен, сколько поддержки у него есть, но это место для поиска возможных дальнейших улучшений.

Смежные вопросы