Базовый Python: Возникновение исключений и область видимости / привязка локальной переменной - PullRequest
4 голосов
/ 30 апреля 2010

У меня есть базовый вопрос "Лучшие практики" Python. Я вижу, что уже есть ответы StackOverflow, косвенно связанные с этим вопросом, но они запутались в сложных примерах или включают несколько факторов.

Учитывая этот код:

#!/usr/bin/python

def test_function():
   try:
      a = str(5)
      raise
      b = str(6)
   except:
      print b

test_function()

Каков наилучший способ избежать неизбежного «UnboundLocalError: локальная переменная« b », на которую ссылаются перед присваиванием», которую я собираюсь получить в обработчике исключений?

Есть ли у python элегантный способ справиться с этим? Если нет, то как насчет неумелого пути? В сложной функции я бы предпочел не проверять существование каждой локальной переменной, прежде чем я, например, напечатал отладочную информацию о них.

Ответы [ 4 ]

10 голосов
/ 30 апреля 2010

Есть ли у питона элегантный способ справиться с этим?

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

Если нет, то как насчет не элегантного пути?

try: print 'b is', b
except NameError: print 'b is not bound'

В сложной функции я бы предпочел чтобы избежать проверки существования каждая локальная переменная перед I, для пример, печатная отладочная информация о них

Настоятельно рекомендуется также сохранять простые функции (т. Е. не сложными). Как писал Хоар 30 лет назад (в своей лекции Тьюринга «Старая одежда Императора», например, в этом PDF ):

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

Достижение и поддержание простоты действительно действительно сложно: учитывая, что вам нужно реализовать определенную полную функциональность X, это самый естественный соблазн в мире сделать это через сложное наращивание в несколько сложных классов и функций различных кусочков, «умных» взломов, эпизодов «копировать-и-вставлять-и-редактировать-бит» «кодирования на диске» и т. д. и т. д.

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

6 голосов
/ 30 апреля 2010

Вы можете инициализировать свои переменные вне блока try

a = None
b = None       
try:
    a = str(5)
    raise
    b = str(6)
except:
    print b
2 голосов
/ 30 апреля 2010

Вы можете проверить, определена ли переменная в локальной области, используя встроенный метод locals()

http://docs.python.org/library/functions.html#locals

#!/usr/bin/python

def test_function():
  try:
      a = str(5)
      raise
      b = str(6)
  except:
      if 'b' in locals(): print b

test_function()
1 голос
/ 30 апреля 2010
def test_function():
   try:
      a = str(5)
      raise
      b = str(6)
   except:
      print b

b = str(6) никогда не запускается;программа выходит из блока try сразу после raise.Если вы хотите напечатать некоторую переменную в блоке except, оцените ее, прежде чем вызывать исключение, и поместите их в выбрасываемое вами исключение.

class MyException(Exception):
   def __init__(self, var):
      self.var = var

def test_function():
   try:
      a = str(5)
      b = str(6)
      raise MyException(b)
   except MyException,e:
      print e.var
...