Локальні та глобальні області видимості в Python

4 хв. читання

Почнімо зі зразка коду. Збережіть наступний код у файл та запустіть його:

command = "You are a LOVELY person!"

def shout():
    print(command)

shout()
print(command)

Вивід:

You are a LOVELY person!
You are a LOVELY person!

Все працює як очікувалось. Трохи змінимо код й знову запустимо:

command = "You are a LOVELY person!"

def shout():
    command = "HI!"
    print(command)

shout()
print(command)

Вивід:

HI!
You are a LOVELY person!

Все ще працює. Змінимо код ще трохи й запустимо знову:

command = "You are a LOVELY person!"

def shout():
    command = "HI!"
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Вивід:

HI!
You are a LOVELY person!

Вивід тепер не настільки інтуїтивно очікуваний. Зробімо останню зміну, перш ніж його обговорити:

command = "You are a LOVELY person!"

def shout():
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Вивід:

Traceback (most recent call last):
  File "prog.py", line 8, in <module>
    shout()
  File "prog.py", line 4, in shout
    print(command)
UnboundLocalError: local variable 'command' referenced before assignment

Воу! Що це? У нас є змінна command, оголошена й ініціалізована у першому рядку файлу. Це може збити з пантелику багатьох Python програмістів-початківців . Однак, якщо ви знайомі з тим, як Python обробляє області видимості змінних, вас нічого не повинно здивувати.

В останньому прикладі, який працював нормально, велика кількість початківців, можливо, очікували, що вивід буде наступним:

HI!
You are amazing!!

Причина очікування цього виводу проста. Ми змінюємо значення змінної command, присвоюючи їй «You are amazing!!» у функції. Це не працює так, як очікувалось, оскільки ми змінюємо значення command в області видимості функції shout. Зміна залишається в межах цієї функції. Як тільки ми вибираємося з цієї функції у глобальну область видимості, command вказує на своє попереднє глобальне значення.

Коли ми отримуємо доступ до значення змінної в межах функції, і ця змінна не визначена у цій функції, Python вважає, що ми хочемо отримати доступ до значення глобальної змінної з таким ім'ям. Ось чому цей фрагмент коду працює:

command = "You are a LOVELY person!"

def shout():
    print(command)

shout()
print(command)

Однак, якщо ми змінимо значення змінної або її призначення неоднозначним способом, Python видасть нам помилку. Погляньте на минулий код:

command = "You are a LOVELY person!"

def shout():
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Проблема виникає, коли Python шукає command в області видимості shout, а знаходить її оголошеною й ініціалізованою ПІСЛЯ того, як ми намагаємося вивести її значення. У цей момент Python не знає, яке зі значень command ми хочемо вивести.

Ми можемо виправити цю проблему, явно вказавши Python, що ми хочемо вивести значення глобальної command, і хочемо змінити цю глобальну змінну. Відредагуйте код наступним чином:

command = "You are a LOVELY person!"

def shout():
    global command
    print(command)
    command = "You are amazing!!"

shout()
print(command)

Вивід:

You are a LOVELY person!
You are amazing!!

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

Тепер ви можете спитати себе, чому Python «припускає» те, що ми посилаємося на глобальну змінну, замість того, щоб викидати помилку кожного разу, коли змінна невизначена в області видимості функції? Документація Python надає чудове пояснення:

Які правила для локальних та глобальних змінних у Python?

У Python змінні, на які посилаються лише всередині функції, є неявно глобальними. Якщо змінній присвоюється значення будь-де в межах тіла функції, вважається, що вона локальна, якщо вона явно не оголошена як глобальна.

З одного боку, global забезпечує бар'єр проти непередбачених побічних ефектів. З іншого боку, якби global був потрібний для всіх глобальних посилань, ми б використовували його завжди. Ви повинні оголосити глобальними всі посилання на вбудовану функцію або компонент імпортованого модуля. Цей непорядок подолає корисність глобального оголошення для виявлення побічних ефектів.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 209
Приєднався: 1 рік тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід