Сожмите это утверждение Python, не разрушая читабельность - PullRequest
2 голосов
/ 09 октября 2009

Я все еще довольно плохо знаком с Python, поэтому пытаюсь понять, как это сделать, и мне нужна помощь.

Я использую коды возврата, чтобы убедиться, что мои внутренние функции возвращаются успешно. Например (из внутренних библиотечных функций):

result = some_function(arg1,arg2)
if result != OK: return result

или (с уровня основного сценария):

result = some_function(arg1,arg2)
if result != OK: abort_on_error("Could not complete 'some_function': %s" % messages(result))

Могу ли я записать это в одну строку, не делая ее нечитаемой?

РЕДАКТИРОВАТЬ: Некоторые люди признают, что исключения могут быть лучшим выбором. Я хотел сохранить исключения только для очень «исключительного» захвата сценария. Можно ожидать, что коды возврата иногда будут давать сбой, и я подумал, что в общем случае было бы неправильно использовать исключения для этого сценария.

Ответы [ 5 ]

10 голосов
/ 09 октября 2009

Не могли бы вы использовать исключения для обозначения сбоя, а не коды возврата? Тогда большинство ваших if result != OK: заявлений просто исчезнет.

3 голосов
/ 09 октября 2009

Звучит так, как будто вы хотите что-то вроде ..

if result = some_function(arg1, arg2):
    return result

Это преднамеренно невозможно в Python. Это слишком распространенная опечатка, чтобы писать if a = b вместо if a == b, и это позволяет смешивать назначение с контролем потока. Если это необходимо, разбейте его на две строки:

x = some_function()
if x:
    print "Function returned True"

Более практический пример этого ..

result = re.match("a", "b")
if result:
   print result.groups()

(точнее, в этом случае вы должны сделать if result is not None:, хотя вышеприведенное работает)

В вашем конкретном случае («чтобы убедиться, что мои внутренние функции возвращаются успешно»), похоже, вы должны использовать исключения. Если все хорошо, просто верни что хочешь. Если что-то пойдет не так, подайте исключение.

Исключения в Python не похожи на многие другие языки - например, они используются для внутреннего управления потоком данных (например, StopIteration исключение)

Я бы посчитал следующее гораздо больше Pythonic, чем при использовании кодов возврата:

#!/usr/bin/env python2.6
def some_function(arg1, arg2):
    if arg1 + arg2 > 5:
        return "some data for you"
    else:
        raise ValueError("Could not complete, arg1+arg2 was too small")

Затем вы можете вызвать функцию в одной строке:

return some_function(3, 2)

Это либо возвращает значение, либо вызывает исключение, которое можно обработать где-то разумным:

def main():
    try:
        result = some_function(3, 5)
    except ValueError, errormsg:
        print errormsg
        sys.exit(1)
    else:
        print "Everything is perfect, the result was {0}".format(result)

Или, если этот случай действительно является ошибкой, просто позвольте остановить приложение с хорошей трассировкой стека.

Да, это намного длиннее, чем одна строка, но идея Python заключается в краткости, но ясности и читабельности.

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

Или в виде стихотворения:

$ python -m this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Наконец, возможно, стоит прочитать более "PEP 8" , руководство по стилю для Python. Он может ответить на некоторые ваши вопросы, такие как «Являются ли однострочные, если утверждения« питоническими »?»

Составные операторы (несколько операторов в одной строке), как правило, не рекомендуется.

Да

if foo == 'blah':
    do_blah_thing()
do_one()
do_two()
do_three()

Скорее нет:

if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()
3 голосов
/ 09 октября 2009

вещий

Идея или фрагмент кода, который близко следует наиболее распространенным идиомам языка Python, а не реализует код с использованием концепций, общих для других языков. [...]

Не подразумевает написания на лайнерах!

1 голос
/ 09 октября 2009

Если вы настаиваете на , не используя исключений, то я бы написал две строки (одна строка здесь будет слишком длинной):

res = some_function(arg1, arg2)
return res if res != OK else ...

Кстати, я рекомендую вам придумать некоторые статические типы значений, которые возвращает ваша функция (несмотря на динамическую типизацию в Python). Например, вы можете вернуть «либо int, либо None». Вы можете поместить такое описание в строку документации.

Если у вас есть int результирующие значения и int коды ошибок, вы можете различить их, введя класс ошибок:

class ErrorCode(int): pass

и затем проверка, если результат isinstance из ErrorCode.

0 голосов
/ 09 октября 2009

Помимо исключений, использование декоратора является хорошим решением этой проблемы:

# Create a function that creates a decorator given a value to fail on...
def fail_unless(ok_val):
   def _fail_unless(f):
       def g(*args, **kwargs):
           val = f(*args, **kwargs)
           if val != ok_val:
               print 'CALLING abort_on_error...'
           else:
               return val
       return g
   return _fail_unless


# Now you can use the decorator on any function you'd like to fail 
@fail_unless('OK')
def no_negatives(n):
    if n < 0:
        return 'UH OH!'
    else:
        return 'OK'

На практике:

>>> no_negatives(9)
'OK'
>>> no_negatives(0)
'OK'
>>> no_negatives(-1)
'CALLING abort_on_error...'

Я знаю, что синтаксис, определяющий fail_unless, немного сложен, если вы не привыкли к декораторам и замыканиям функций, но приложение из fail_unless() довольно хорошо, нет?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...