пространства имен — разделы, внутри которых определенное имя уникально и не связано с такими же именами в других пространствах имен.
Каждая функция определяет собственное пространство имен. Если вы определите переменную, которая называется х в основной программе, и другую переменную х в отдельной функции, они будут ссылаться на разные значения. Но эту стену можно пробить: если нужно, вы можете получить доступ к именам других пространств имен разными способами.
В основной программе определяется глобальное пространство имен, поэтому переменные, находящиеся в этом пространстве имен, являются глобальными.
Вы можете получить значение глобальной переменной внутри функции:
>>> animal = 'fruitbat'
>>> def print_global():
…·····print('inside print_global:', animal)
…
>>> print('at the top level:', animal)
at the top level: fruitbat
>>> print_global()
inside print_global: fruitbat
Но если попробуете получить значение глобальной переменной и изменить его внутри функции, получите ошибку:
>>> def change_and_print_global():
…·····print('inside change_and_print_global:', animal)
…·····animal = 'wombat'
…·····print('after the change:', animal)
…
>>> change_and_print_global()
Traceback (most recent call last):
··File "", line 1, in
··File "", line 2, in change_and_report_it
UnboundLocalError: local variable 'animal' referenced before assignment
Если вы просто измените его, изменится другая переменная, которая также называется animal, но находится внутри функции:
>>> def change_local():
…·····animal = 'wombat'
…·····print('inside change_local:', animal, id(animal))
…
>>> change_local()
inside change_local: wombat 4330406160
>>> animal
'fruitbat'
>>> id(animal)
4330390832
Что здесь произошло? В первой строке мы присвоили строку 'fruitbat' глобальной переменной с именем animal. Функция change_local() также имеет переменную с именем animal, но она находится в ее локальном пространстве имен.
Мы использовали функцию id(), чтобы вывести на экран уникальное значение каждого объекта и доказать, что переменная animal, расположенная внутри функции change_local(), — это не переменная animal, расположенная на основном уровне программы.
Чтобы получить доступ к глобальной переменной вместо локальной переменной внутри функции, вам нужно явно использовать ключевое слово global (вы знали, что я это скажу: явное лучше неявного):
>>> animal = 'fruitbat'
>>> def change_and_print_global():
…·····global animal
…·····animal = 'wombat'
…·····print('inside change_and_print_global:', animal)
…
>>> animal
'fruitbat'
>>> change_and_print_global()
inside change_and_print_global: wombat
>>> animal
'wombat'
Если вы не используете ключевое слово global внутри функции, Python задействует локальное пространство имен и переменная будет локальной. Она пропадет после того, как функция завершит работу.
Python предоставляет две функции для доступа к содержимому ваших пространств имен:
• locals() — возвращает словарь, содержащий имена локального пространства имен;
• globals() — возвращает словарь, содержащий имена глобального пространства имен.
Вот так они используются:
>>> animal = 'fruitbat'
>>> def change_local():
…·····animal = 'wombat'··# локальная переменная
…·····print('locals:', locals())
…
>>> animal
'fruitbat'
>>> change_local()
locals: {'animal': 'wombat'}
>>> print('globals:', globals()) # немного переформатировано для представления
globals: {'animal': 'fruitbat',
'__doc__': None,
'change_local': ,
'__package__': None,
'__name__': '__main__',
'__loader__': ,
'__builtins__': }
>>> animal
'fruitbat'
Локальное пространство имен внутри функции change_local() содержало только локальную переменную animal. Глобальное пространство имен содержало отдельную глобальную переменную animal и многое другое.
Использование _ и __ в именах. Имена, которые начинаются с двух нижних подчеркиваний (__), зарезервированы для использования внутри Python, поэтому вам не следует применять их для своих переменных. Этот шаблон именования был выбран потому, что разработчики, скорее всего, не будут использовать его для создания имен своих переменных.
Например, имя функции находится в системной переменной функция.__name__, а имя ее строки документации — функция.__doc__:
>>> def amazing():
…·····'''This is the amazing function.
…·····Want to see it again?'''
…·····print('This function is named:', amazing.__name__)
…·····print('And its docstring is:', amazing.__doc__)
…
>>> amazing()
This function is named: amazing
And its docstring is: This is the amazing function.
····Want to see it again?
Как вы видели ранее в содержимом globals, основной программе присвоено специальное имя __main__.
Обработка ошибок с помощью try и except
Делай или не делай. Не надо пытаться.
В некоторых языках программирования ошибки отображаются с помощью специальных возвращаемых значений. В Python используются исключения: код, который выполняется, когда происходит связанная с ним ошибка.
Нечто похожее вы уже видели, когда попытались получить доступ к не входящей в список/кортеж позиции или ключу, которого не существует в словаре. Когда вы выполняете код, который при некоторых обстоятельствах может не сработать, вам также понадобятся обработчики исключений, чтобы перехватить любые потенциальные ошибки.
Хорошим тоном является использование обработчиков исключений везде, где может быть сгенерировано исключение, чтобы пользователь знал, что происходит. Вы можете быть неспособны исправить ошибку, но по крайней мере можете узнать, при каких обстоятельствах это произошло, и аккуратно завершить программу. Если исключение сгенерировалось в функции и не было обработано, оно всплывает до тех пор, пока не будет поймано соответствующим обработчиком в одной из вызывающих функций. Если вы не предоставите собственный обработчик исключения, Python выведет сообщение об ошибке и некоторую информацию о том, где произошла ошибка, а затем завершит программу, как показано в следующем фрагменте кода.
>>> short_list = [1, 2, 3]
>>> position = 5
>>> short_list[position]
Traceback (most recent call last):
··File "", line 1, in
IndexError: list index out of range
Вместо того чтобы отпускать события на волю случая, размещайте свой код в блоке try и используйте блок except, чтобы обработать ошибку:
>>> short_list = [1, 2, 3]
>>> position = 5
>>> try:
…·····short_list[position]
… except:
…·····print('Need a position between 0 and', len(short_list)-1, ' but got',