Что отсутствует в следующем коде
Перейти к содержимому

Что отсутствует в следующем коде

  • автор:

Python: Ошибки при работе с переменными

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

print(greeting) greeting = 'Father!' 

Запуск программы выше завершается с ошибкой NameError: name ‘greeting’ is not defined — это ошибка обращения. Это значит, что в коде используется имя (идентификатор), которое пока не определено. Это говорится в самом тексте ошибки: ‘greeting’ is not defined . Кроме неправильного порядка действий, в Python встречаются банальные опечатки в имени переменной. Это происходит и когда переменная используется, и когда ее объявляют.

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

Задание

Найдите в программе необъявленную переменную и объявите ее, присвоив ей значение ‘Dragon’.

После выполнения программы результат на экране должен выглядеть так:

Targaryen and Dragon

Упражнение не проходит проверку — что делать? ��

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

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

В моей среде код работает, а здесь нет ��

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя ��

Это нормально ��, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно ��

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

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

Полезное

Определения

  • Переменная — способ сохранить информацию и дать ей имя для последующего использования в коде.

Найдите ошибки в следующем коде

Обложка поста Найдите ошибки в следующем коде

Первая заключается в том, что используется тип unsigned int , который работает только со значениями, большими или равными нулю. Поэтому условие цикла for всегда будет истинно, и цикл будет выполняться бесконечно.

Корректный код, выводящий значения всех чисел от 100 до 1, должен использовать условие i > 0 . Если нам на самом деле нужно вывести нулевое значение, то следует добавить дополнительный оператор printf после цикла for .

unsigned int i; for (i = 100; i > 0; --i) printf("%d\n", i); printf("%d\n", i); 

Вторая ошибка — вместо %d следует использовать %u , поскольку мы выводим целые значения без знака.

unsigned int i; for (i = 100; i > 0; --i) printf("%u\n", i); 

Теперь этот код правильно выведет список чисел от 100 до 1, в убывающем порядке.

Разбор взят из книги Гейл Л. Макдауэлл «Cracking the Coding Interview» (есть в переводе).

Глючный код на Python: 10 самых распространенных ошибок, которые допускают разработчики

Python — это интерпретируемый, объектно-ориентированный язык программирования высокого уровня с динамической семантикой. Встроенные структуры данных высокого уровня в сочетании с динамической типизацией и динамическим связыванием делают его очень привлекательным для БРПС (быстрой разработки прикладных средств), а также для использования в качестве скриптового и связующего языка для подключения существующих компонентов или сервисов. Python поддерживает модули и пакеты, тем самым поощряя модульность программы и повторное использование кода.

О данной статье

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

Имея это в виду, в этой статье представлен «топ-10» тонких, трудных для обнаружения ошибок, которые могут допустить даже продвинутые разработчики Python.

Ошибка № 1: неправильное использование выражений в качестве значений по умолчанию для аргументов функций

Python позволяет указывать, что у функции могут быть необязательные аргументы, путем задания для них значения по умолчанию. Это, конечно, очень удобная особенность языка, но может привести к неприятным последствиям, если тип такого значения будет изменяемым. Например, рассмотрим следующее определение функции:

>>> def foo(bar=[]): # bar - это необязательный аргумент # и по умолчанию равен пустому списку. . bar.append("baz") # эта строка может стать проблемой. . return bar

Распространенная ошибка в данном случае — это думать, что значение необязательного аргумента будет устанавливаться в значение по умолчанию каждый раз, как функция будет вызываться без значения для этого аргумента. В приведенном выше коде, например, можно предположить, что повторно вызывая функцию foo() (то есть без указания значения для агрумента bar), она всегда будет возвращать «baz», поскольку предполагается, что каждый раз, когда вызывается foo () (без указания аргумента bar), bar устанавливается в [ ] (т. е. новый пустой список).

Но давайте посмотрим что же будет происходить на самом деле:

>>> foo() ["baz"] >>> foo() ["baz", "baz"] >>> foo() ["baz", "baz", "baz"]

А? Почему функция продолжает добавлять значение по умолчанию «baz» к существующему списку каждый раз, когда вызывается foo(), вместо того, чтобы каждый раз создавать новый список?

Ответом на данный вопрос будет более глубокое понимание того, что творится у Python «под капотом». А именно: значение по умолчанию для функции инициализируется только один раз, во время определения функции. Таким образом, аргумент bar инициализируется по умолчанию (т. е. пустым списком) только тогда, когда foo() определен впервые, но последующие вызовы foo() (т. е. без указания аргумента bar) продолжат использовать тот же список, который был создан для аргумента bar в момент первого определения функции.

Для справки, распространенным «обходным путем» для этой ошибки является следующее определение:

>>> def foo(bar=None): . if bar is None: # or if not bar: . bar = [] . bar.append("baz") . return bar . >>> foo() ["baz"] >>> foo() ["baz"] >>> foo() ["baz"]

Ошибка № 2: неправильное использование переменных класса

Рассмотрим следующий пример:

>>> class A(object): . x = 1 . >>> class B(A): . pass . >>> class C(A): . pass . >>> print A.x, B.x, C.x 1 1 1

Вроде все в порядке.

>>> B.x = 2 >>> print A.x, B.x, C.x 1 2 1

Ага, все как и ожидалось.

>>> A.x = 3 >>> print A.x, B.x, C.x 3 2 3

Что за черт?! Мы же только изменили A.x. Почему же C.x тоже изменилось?

В Python переменные класса обрабатываются как словари и следуют тому, что часто называют Порядком разрешения методов (MRO). Таким образом, в приведенном выше коде, поскольку атрибут x не найден в классе C, он будет найден в его базовых классах (только A в приведенном выше примере, хотя Python поддерживает множественное наследование). Другими словами, C не имеет своего собственного свойства x, независимого от A. Таким образом, ссылки на C.x фактически являются ссылками на A.x. Это будет вызывать проблемы, если не обрабатывать такие случаи должным образом. Так что при изучении Python обратите особое внимание на аттрибуты класса и работу с ними.

Ошибка № 3: неправильное указание параметров для блока исключения

Предположим, что у вас есть следующий кусок кода:

>>> try: . l = ["a", "b"] . int(l[2]) . except ValueError, IndexError: # To catch both exceptions, right? . pass . Traceback (most recent call last): File "", line 3, in IndexError: list index out of range

Проблема здесь заключается в том, что выражение except не принимает список исключений, указанных таким образом. Скорее, в Python 2.x выражение «except Exception, e» используется для привязки исключения к необязательному второму заданному второму параметру (в данном случае e), чтобы сделать его доступным для дальнейшей проверки. В результате в приведенном выше коде исключение IndexError не перехватывается выражением except; скорее, вместо этого исключение заканчивается привязкой к параметру с именем IndexError.

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

>>> try: . l = ["a", "b"] . int(l[2]) . except (ValueError, IndexError) as e: . pass . >>>

Ошибка № 4: непонимание правил области видимости Python

Область видимости в Python основана на так называемом правиле LEGB, которое является аббревиатурой Local (имена, назначенные любым способом внутри функции (def или lambda), и не объявленные глобальными в этой функции), Enclosing (имя в локальной области действия любых статически включающих функций (def или lambda), от внутреннего к внешнему), Global (имена, назначенные на верхнем уровне файла модуля, или путем выполнения global инструкции в def внутри файла), Built-in (имена, предварительно назначенные в модуле встроенных имен: open, range, SyntaxError . ). Кажется достаточно просто, верно? Ну, на самом деле, есть некоторые тонкости в том, как это работает в Python, что подводит нас к общей более сложной проблеме программирования на Python ниже. Рассмотрим следующей пример:

>>> x = 10 >>> def foo(): . x += 1 . print x . >>> foo() Traceback (most recent call last): File "", line 1, in File "", line 2, in foo UnboundLocalError: local variable 'x' referenced before assignment

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

Таким образом, многие удивляются, когда получают UnboundLocalError в ранее работающем коде, когда он модифицируется путем добавления оператора присваивания где-нибудь в теле функции.

Эта особенность особенно сбивает разработчиков с толку при использовании списков. Рассмотрим следующий пример:

>>> lst = [1, 2, 3] >>> def foo1(): . lst.append(5) # Это работает нормально. . >>> foo1() >>> lst [1, 2, 3, 5] >>> lst = [1, 2, 3] >>> def foo2(): . lst += [5] # . а вот это падает! . >>> foo2() Traceback (most recent call last): File "", line 1, in File "", line 2, in foo UnboundLocalError: local variable 'lst' referenced before assignment

А? Почему foo2 падает, в то время как foo1 работает нормально?

Ответ такой же, как в предыдущем примере, но, по распространенному мнению, здесь ситуация более тонкая. foo1 не применяет оператор присваивания к lst, тогда как foo2 — да. Помня, что lst + = [5] на самом деле является просто сокращением для lst = lst + [5], мы видим, что мы пытаемся присвоить значение lst (поэтому Python предполагает, что он находится в локальной области видимости). Однако значение, которое мы хотим присвоить lst, основано на самом lst (опять же, теперь предполагается, что он находится в локальной области видимости), который еще не был определен. И мы получаем ошибку.

Ошибка № 5: изменение списка во время итерации по нему

Проблема в следующем куске кода должна быть достаточно очевидной:

>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> for i in range(len(numbers)): . if odd(numbers[i]): . del numbers[i] # BAD: Deleting item from a list while iterating over it . Traceback (most recent call last): File "", line 2, in IndexError: list index out of range

Удаление элемента из списка или массива во время итерации по нему — это проблема Python, которая хорошо известна любому опытному разработчику программного обеспечения. Но, хотя приведенный выше пример может быть достаточно очевидным, даже опытные разработчики могут встать на эти грабли в гораздо более сложном коде.

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

>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all >>> numbers [0, 2, 4, 6, 8]

Ошибка № 6: непонимание того, как Python связывает переменные в замыканиях

Рассмотрим следующий пример:

>>> def create_multipliers(): . return [lambda x : i * x for i in range(5)] >>> for multiplier in create_multipliers(): . print multiplier(2) . 

Вы можете ожидать следующий вывод:

0 2 4 6 8

Но на самом деле вы получите вот что:

8 8 8 8 8 

Это происходит из-за поздней привязки в Python, которое заключается в том, что значения переменных, используемых в замыканиях, ищутся во время вызова внутренней функции. Таким образом, в приведенном выше коде всякий раз, когда вызывается какая-либо из возвращаемых функций, значение i ищется в окружающей области видимости во время ее вызова (а к тому времени цикл уже завершился, поэтому i уже был присвоен конечный результат — значение 4).

Решение этой распространенной проблемы с Python будет таким:

>>> def create_multipliers(): . return [lambda x, i=i : i * x for i in range(5)] . >>> for multiplier in create_multipliers(): . print multiplier(2) . 0 2 4 6 8

Вуаля! Мы используем здесь аргументы по умолчанию для генерации анонимных функций для достижения желаемого поведения. Некоторые назвали бы это решение элегантным. Некоторые —
тонким. Некоторые ненавидят подобные штуки. Но если вы разработчик Python, в любом случае, это важно понимать.

Ошибка № 7: создание циклических зависимостей модуля

Допустим, у вас есть два файла, a.py и b.py, каждый из которых импортирует другой, следующим образом:

import b def f(): return b.x print f()
import a x = 1 def g(): print a.f()

Сначала попробуем импортировать a.py:

>>> import a 1

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

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

Итак, возвращаясь к нашему примеру, когда мы импортировали a.py, у него не было проблем с импортом b.py, поскольку b.py не требует, чтобы что-либо из a.py было определено во время его импорта. Единственная ссылка в b.py на a — это вызов a.f(). Но этот вызов в g() и ничего в a.py или b.py не вызывает g(). Так что все работает прекрасно.

Но что произойдет, если мы попытаемся импортировать b.py (без предварительного импорта a.py, то есть):

>>> import b Traceback (most recent call last): File "", line 1, in File "b.py", line 1, in import a File "a.py", line 6, in print f() File "a.py", line 4, in f return b.x AttributeError: 'module' object has no attribute 'x'

Ой-ой. Это не хорошо! Проблема здесь в том, что в процессе импорта b.py он пытается импортировать a.py, который, в свою очередь, вызывает f(), который пытается получить доступ к b.x. Но b.x еще не было определено. Отсюда исключение AttributeError.

По крайней мере, одно из решений этой проблемы довольно тривиально. Просто измените b.py, чтобы импортировать a.py в g():

x = 1 def g(): import a # This will be evaluated only when g() is called print a.f()

Теперь, когда мы его импортируем, все нормально:

>>> import b >>> b.g() 1 # Printed a first time since module 'a' calls 'print f()' at the end 1 # Printed a second time, this one is our call to 'g' 

Ошибка № 8: пересечение имен с именами модулями стандартной библиотеки Python

Одна из прелестей Python — это множество модулей, которые поставляются «из коробки». Но в результате, если вы сознательно не будете за этим следить, можно столкнуться с тем, что имя вашего модуля может быть с тем же именем, что и модуль в стандартной библиотеке, поставляемой с Python (например, в вашем коде может быть модуль с именем email.py, который будет конфликтовать со модулем стандартной библиотеки с таким же именем).

Это может привести к серьезным проблемам. Например, если какой-нибудь из модулей будет пытаться импортировать версию модуля из стандартной библиотеки Python, а у вас в проекте будет модуль с таким же именем, который и будет по ошибке импортирован вместо модуля из стандартной библиотеки.

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

Ошибка № 9: неспособность учесть различия Python 2 и Python 3

Рассмотрим следующий файл foo.py:

import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def bad(): e = None try: bar(int(sys.argv[1])) except KeyError as e: print('key error') except ValueError as e: print('value error') print(e) bad()

На Python 2 он отработает нормально:

$ python foo.py 1 key error 1 $ python foo.py 2 value error 2

Но теперь давайте посмотрим как он будет работать в Python 3:

$ python3 foo.py 1 key error Traceback (most recent call last): File "foo.py", line 19, in bad() File "foo.py", line 17, in bad print(e) UnboundLocalError: local variable 'e' referenced before assignment

Что здесь только что произошло? «Проблема» в том, что в Python 3 объект в блоке исключения недоступен за его пределами. (Причина этого заключается в том, что в противном случае объекты в этом блоке будут сохраняться в памяти до тех пор, пока сборщик мусора не запустится и не удалит ссылки на них оттуда).

Один из способов избежать этой проблемы — сохранить ссылку на объект блока исключения за пределами этого блока, чтобы он оставался доступным. Вот версия предыдущего примера, которая использует эту технику, тем самым получая код, который подходит как для Python 2, так и для Python 3:

import sys def bar(i): if i == 1: raise KeyError(1) if i == 2: raise ValueError(2) def good(): exception = None try: bar(int(sys.argv[1])) except KeyError as e: exception = e print('key error') except ValueError as e: exception = e print('value error') print(exception) good()

Запустим его в Python 3:

$ python3 foo.py 1 key error 1 $ python3 foo.py 2 value error 2

Ошибка № 10: неправильное использование метода __del__

Допустим, у вас есть вот такой файл mod.py:

import foo class Bar(object): . def __del__(self): foo.cleanup(self.myhandle)

И вы пытаетесь сделать вот такое из другого another_mod.py:

import mod mybar = mod.Bar()

И получите ужасный AttributeError.

Почему? Потому что, как сообщается здесь, когда интерпретатор отключается, глобальные переменные модуля все имеют значение None. В результате в приведенном выше примере, в момент вызова __del__, имя foo уже было установлено в None.

Решением этой «задачи со звездочкой» будет использование atexit.register(). Таким образом, когда ваша программа завершает выполнение (то есть при нормальном выходе из нее), ваши handle’ы удаляются до того, как интерпретатор звершает работу.

С учетом этого, исправление для приведенного выше кода mod.py может выглядеть примерно так:

import foo import atexit def cleanup(handle): foo.cleanup(handle) class Bar(object): def __init__(self): . atexit.register(cleanup, self.myhandle)

Подобная реализация обеспечивает простой и надежный способ вызова любой необходимой очистки после обычного завершения программы. Очевидно, что решение о том, как поступить с объектом, который связан с имненем self.myhandle, остается за foo.cleanup, но, думаю, идею вы поняли.

Заключение

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

Ознакомление с нюансами Python, затронутыми в этой статье, поможет оптимизировать использование языка, избегая при этом некоторых распространенных ошибок.

Обработка ошибок с помощью Python

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

Когда инструмент записывает сообщение об ошибке, ArcPy создает исключение arcpy.ExecuteError . Python позволяет написать модуль, который будет выполняться автоматически при возникновении системной ошибки. С помощью этого модуля для обработки ошибок вы сможете получать сообщения об ошибках от ArcPy и реагировать на них. Если скрипт не имеет модуля для обработки ошибок, он завершает выполнение немедленно, что уменьшает его надежность. Модуль обработки ошибок можно использовать для управления ошибками и повышения надежности скриптов.

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

Выражение try-except

Чтобы охватить всю программу целиком или только отдельные фрагменты кода для обнаружения и определения ошибок могут использоваться выражения try-except . Если в выражении try возникнет ошибка, будет создано исключение, и код будет выполнен в соответствии с выражением except. Использование выражения except является наиболее простой формой обработки ошибок.

В следующем коде Буфер не работает, потому что не был указан обязательный аргумент buffer_distance_or_field . Чтобы найти ошибку, используется выражение except , которое извлекает и выводит сообщение об ошибке, сгенерированное Буфером . Обратите внимание, что блок except выполняется только в случае, если Буфер возвращает ошибку.

import arcpy import sys try: # Execute the Buffer tool arcpy.Buffer_analysis("c:/transport/roads.shp", "c:/transport/roads_buffer.shp") except Exception: e = sys.exc_info()[1] print(e.args[0]) # If using this code within a script tool, AddError can be used to return messages # back to a script tool. If not, AddError will have no effect. arcpy.AddError(e.args[0])

Выражение try содержит необязательное условие finally , которое можно использовать для задач, которые должны выполняться всегда, независимо от того, возникает исключение или нет. В следующем примере ArcGIS 3D Analyst extension регистрируется в соответствии с условием finally , которое гарантирует, что этот дополнительный модуль всегда будет регистрироваться.

class LicenseError(Exception): pass import arcpy try: if arcpy.CheckExtension("3D") == "Available": arcpy.CheckOutExtension("3D") else: # Raise a custom exception raise LicenseError arcpy.env.workspace = "D:/GrosMorne" arcpy.HillShade_3d("WesternBrook", "westbrook_hill", 300) arcpy.Aspect_3d("WesternBrook", "westbrook_aspect") except LicenseError: print "3D Analyst license is unavailable" except arcpy.ExecuteError: print(arcpy.GetMessages(2)) finally: # Check in the 3D Analyst extension arcpy.CheckInExtension("3D")

Выражение raise

Предыдущий пример иллюстрирует ошибку в исключении, которое возникло в коде В некоторых случаях может потребоваться создать пользовательские исключения. Для этой цели может использоваться выражение raise . В следующем коде выражение raise используется, если входной класс объектов определился как не содержащий объектов. Это не обязательно ошибка, но условие, при котором код может быть использован.

class NoFeatures(Exception): pass import arcpy import os import sys arcpy.env.overwriteOutput = True fc = arcpy.GetParameterAsText(0) try: # Check that the input has features result = arcpy.GetCount_management(fc) if int(result[0]) > 0: arcpy.FeatureToPolygon_management( fc, os.path.join(os.path.dirname(fc), 'out_poly.shp')) else: # Raise custom exception raise NoFeatures(result) except NoFeatures: # The input has no features print('<> has no features'.format(fc)) except: # By default any other errors will be caught here e = sys.exc_info()[1] print(e.args[0])

Класс ExecuteError

Когда инструмент геообработки выходит из строя, он создает класс исключений arcpy.ExecuteError , что означает, что вы можете разделить ошибки на различные группы, ошибки геообработки (те, которые создают исключение arcpy.ExecuteError ) и другие типы исключений. Затем можно обрабатывать эти ошибки по разному, как показано в следующем коде:

import arcpy import sys try: result = arcpy.GetCount_management("C:/invalid.shp") # Return geoprocessing specific errors except arcpy.ExecuteError: arcpy.AddError(arcpy.GetMessages(2)) # Return any other type of error except: # By default any other errors will be caught here e = sys.exc_info()[1] print(e.args[0])

traceback

В больших и более сложных скриптах бывает сложно точное определить место возникновения ошибки. Для определения точного местоположения и причины ошибки, а также для более точного определения причины ошибки и экономии ценного времени на отладку можно использовать модули Python , sys и traceback совместно.

# Import the required modules # import arcpy import sys import traceback arcpy.env.workspace = "C:/Data/myData.gdb" try: arcpy.CreateSpatialReference_management() #-------------------------- # Your code goes here # # See the table below for examples #-------------------------- except arcpy.ExecuteError: # Get the tool error messages msgs = arcpy.GetMessages(2) # Return tool error messages for use with a script tool arcpy.AddError(msgs) # Print tool error messages for use in Python print(msgs) except: # Get the traceback object tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] # Concatenate information together concerning the error into a message string pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1]) msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n" # Return Python error messages for use in script tool or Python window arcpy.AddError(pymsg) arcpy.AddError(msgs) # Print Python error messages for use in Python / Python window print(pymsg) print(msgs)

Если был использован приведенный выше код, и произошла ошибка инструмента геообработки, такая как недопустимые входные данные, это вызовет arcpy.ExecuteError , и будет использоваться первое выражение except . Это выражение выведет сообщение об ошибке с помощью функции GetMessages . Если использовался тот же код, но возникла ошибка другого типа, будет использовано второе выражение except . Вместо печати сообщений о геообработке, будет получен объект traceback и выведены соответствующие сообщения о системных ошибках.

В таблице ниже показаны ожидаемые ошибки, являющиеся результатом трех различных строк кода, который мог быть использован вместо вышеуказанного кода. Первый пример – ошибка инструмента геообработки, которая генерирует информацию traceback и сообщения об ошибках геообработки. Второй и третий примеры не обрабатываются, а происходит только генерация данных traceback.

PYTHON ERRORS: Traceback info: File "c:\temp\errortest.py", line 10, in arcpy.GetCount_management("") Error Info: Failed to execute. Parameters are not valid. ERROR 000735: Input Rows: value is required Failed to execute (GetCount). ArcPy ERRORS: Failed to execute. Parameters are not valid. ERROR 000735: Input Rows: value is required Failed to execute (GetCount).
PYTHON ERRORS: Traceback info: File "c:\temp\errortest.py", line 10, in x = "a" + 1 Error Info: cannot concatenate 'str' and 'int' objects

float(«a text string»)

PYTHON ERRORS: Traceback info: File "c:\temp\errortest.py", line 10, in float("a text string") Error Info: invalid literal for float(): a text string

Получение сообщений об ошибках от объекта Result

Несколько слов об объекте Result , который показан ниже:

result = arcpy.GetCount_management("c:/data/rivers.shp")

Если запрос в GetCount_management вызывает исключение, объект Result не создается. Это означает, что вы не можете получать сообщения об ошибках от объекта Result .

import arcpy try: result = arcpy.GetCount_management("c:/data/rivers.shp") # Return Geoprocessing specific errors # (this method is incorrect!) except arcpy.ExecuteError: arcpy.AddError(result.getMessages(2))

Указанный выше код не работает, и появляется сообщение name ‘result’ is not defined . Причина в том, что объект Result невозможно было создать из-за ошибки инструмента. Поскольку объект Result не создан, возникает ошибка Python при попытке использования метода getMessages .

Примечание:

Объект Result , создаваемый путем запроса в сервис геообработки на ArcGIS Server , создается даже при ошибке инструмента. Создание объекта Result не удается только тогда, когда инструмент запускается локально и вызывает ошибку. Более подробную информацию об использовании объекта result смотрите в разделе Использование инструментов в Python .

В этом разделе
  1. Выражение try-except
  2. Выражение raise
  3. Класс ExecuteError
  4. traceback
  5. Получение сообщений об ошибках от объекта Result

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *