Когда вы пишете код на других языках, вы иногда создаете область видимости блока, например:
statement
...
statement
{
statement
...
statement
}
statement
...
statement
Одна из целей (из многих) - улучшить читаемость кода: показать, что определенные операторы образуют логическую единицу или что определенные локальные переменные используются только в этом блоке.
Есть ли идиоматический способ сделать то же самое в Python?
One purpose (of many) is to improve code readability
- Код Python, написанный правильно (т.е. следуя дзену Python ), не нуждается в таком украшении, чтобы его можно было читать. Фактически, это одна из (многих) вещей, которые мне нравятся в Python.__exit__
иwith
заявления, изменение ,globals()
но мне не удалось.Ответы:
Нет, нет языковой поддержки для создания области блока.
Следующие конструкции создают область видимости:
источник
Идиоматический способ в Python - делать ваши функции короткими. Если вы думаете, что вам это нужно, реорганизуйте свой код! :)
Python создает новую область видимости для каждого модуля, класса, функции, выражения генератора, понимания dict, понимания множества, а в Python 3.x также для каждого понимания списка. Помимо этого, внутри функций нет вложенных областей видимости.
источник
Вы можете сделать что-то похожее на область видимости блока C ++ в Python, объявив функцию внутри своей функции и затем немедленно вызвав ее. Например:
def my_func(): shared_variable = calculate_thing() def do_first_thing(): ... = shared_variable do_first_thing() def do_second_thing(): foo(shared_variable) ... do_second_thing()
Если вы не уверены, зачем вам это нужно, это видео может вас убедить.
Основной принцип состоит в том, чтобы охватить все как можно более плотно, не вводя какой-либо `` мусор '' (дополнительные типы / функции) в более широкую область, чем это абсолютно необходимо - никто другой не хочет использовать
do_first_thing()
метод, например, поэтому он не должен выходить за вызывающая функция.источник
Я согласен, что блокировка отсутствует. Но одно место в python 3 делает его ВИДОМ, как будто он имеет область видимости блока.
что случилось, что придало этому виду? Это работало правильно в python 2, но чтобы остановить утечку переменной в python 3, они сделали этот трюк, и это изменение заставляет его выглядеть так, как будто здесь есть область действия блока.
Позволь мне объяснить.
Согласно идее области видимости, когда мы вводим переменные с одинаковыми именами внутри одной и той же области, ее значение должно быть изменено.
это то, что происходит в python 2
>>> x = 'OLD' >>> sample = [x for x in 'NEW'] >>> x 'W'
Но в python 3, даже несмотря на то, что переменная с тем же именем введена, она не переопределяет, понимание списка по какой-то причине действует как песочница и похоже на создание в ней новой области.
>>> x = 'OLD' >>> sample = [x for x in 'NEW'] >>> x 'OLD'
и этот ответ противоречит утверждению ответчика @ Thomas . Единственное средство для создания области видимости - это функции, классы или модули, потому что это похоже на еще одно место для создания новой области.
источник
Модули (и пакеты) - отличный способ Pythonic разделить вашу программу на отдельные пространства имен, что, по-видимому, является неявной целью этого вопроса. На самом деле, когда я изучал основы Python, я был разочарован отсутствием функции блочной области видимости. Однако как только я понял модули Python, я смог более элегантно реализовать свои предыдущие цели без необходимости в области видимости блока.
В качестве мотивации и для того, чтобы указывать людям правильное направление, я думаю, полезно привести явные примеры некоторых конструкций области видимости Python. Сначала я объясню свою неудачную попытку использовать классы Python для реализации области видимости блока. Затем я объясню, как я добился чего-то более полезного, используя модули Python. В конце я описываю практическое применение пакетов для загрузки и фильтрации данных.
Попытка блокировки области с классами
На какое-то время мне показалось, что я достиг области видимости блока, вставив код внутри объявления класса:
x = 5 class BlockScopeAttempt: x = 10 print(x) # Output: 10 print(x) # Output: 5
К сожалению, это не работает, когда функция определяется:
x = 5 class BlockScopeAttempt: x = 10 print(x) # Output: 10 def printx2(): print(x) printx2() # Output: 5!!!
Это потому, что функции, определенные в классе, используют глобальную область видимости. Самый простой (но не единственный) способ исправить это - явно указать класс:
x = 5 class BlockScopeAttempt: x = 10 print(x) # Output: 10 def printx2(): print(BlockScopeAttempt.x) # Added class name printx2() # Output: 10
Это не так элегантно, потому что нужно писать функции по-разному в зависимости от того, содержатся они в классе или нет.
Лучшие результаты с модулями Python
Модули очень похожи на статические классы, но, по моему опыту, модули намного чище. Чтобы сделать то же самое с модулями, я создаю файл, вызываемый
my_module.py
в текущем рабочем каталоге, со следующим содержимым:x = 10 print(x) # (A) def printx(): global x print(x) # (B)
Затем в моем основном файле или интерактивном сеансе (например, Jupyter) я делаю
x = 5 import my_module # Output: 10 from (A) my_module.printx() # Output: 10 from (B) print(x) # Output: 5
В качестве объяснения каждый файл Python определяет модуль, который имеет собственное глобальное пространство имен. Импорт модуля позволяет вам получить доступ к переменным в этом пространстве имен с помощью
.
синтаксиса.Если вы работаете с модулями в интерактивном сеансе, вы можете выполнить эти две строки в начале
%load_ext autoreload %autoreload 2
и модули будут автоматически перезагружены при изменении соответствующих файлов.
Пакеты для загрузки и фильтрации данных
Идея пакетов - это небольшое расширение концепции модулей. Пакет - это каталог, содержащий (возможно, пустой)
__init__.py
файл, который выполняется при импорте. Доступ к модулям / пакетам в этом каталоге можно получить с помощью.
синтаксиса.Для анализа данных мне часто нужно прочитать большой файл данных, а затем интерактивно применить различные фильтры. Чтение файла занимает несколько минут, поэтому я хочу сделать это только один раз. Основываясь на том, что я узнал в школе об объектно-ориентированном программировании, я раньше считал, что нужно писать код для фильтрации и загрузки как методы в классе. Основным недостатком этого подхода является то, что если я затем переопределю свои фильтры, определение моего класса изменится, поэтому мне придется перезагрузить весь класс, включая данные.
В настоящее время с Python я определяю пакет с именем,
my_data
который содержит подмодули с именамиload
иfilter
. Внутриfilter.py
я могу сделать относительный импорт:from .load import raw_data
Если я изменю
filter.py
, тоautoreload
обнаружу изменения. Он не перезагружаетсяload.py
, поэтому мне не нужно перезагружать мои данные. Таким образом, я могу создать прототип своего кода фильтрации в блокноте Jupyter, обернуть его как функцию, а затем вырезать и вставить прямо из блокнота вfilter.py
. Осознание этого произвело революцию в моем рабочем процессе и превратило меня из скептика в сторонника «дзен Python».источник