Python — один из самых популярных языков для начинающих. Его очень просто читать, поскольку синтаксис очень прямой. Пока вы знакомы с основами, нет никаких сомнений в том, что язык делает в любой момент времени.
Однако, как и любой другой язык, который вы можете изучать, в Python есть некоторые причуды по этому поводу. Эта статья познакомит вас с некоторыми особенностями Python, рассказав, что происходит под капотом.
Примечание: для этой статьи , мы будем иметь в виду только причуды, относящиеся к Python 3, поскольку Python 2 устарел в январе 2020 года.
Мы рассмотрим:
- Переменные, пространство имен и область действия
- Удаление элемента списка во время итерации
- Изменение словаря при итерации по нему
- Разрешение имени без учета области класса
- Остерегайтесь изменяемых аргументов по умолчанию
- Те же операнды, другая история
- Что не так с логическими значениями?
- Атрибуты класса и атрибуты экземпляра
-
метод split ()
- Дикий импорт
- Что узнать дальше
- Улучшите свой код с лучшими приемами Python
- Переменные, пространство имен и область действия
- Пространство имен
- Область действия
- Удаление элемента списка при итерации
- del keyword
- remove () метод
- pop (idx) метод
- Итак, что делает работа?
- Изменение словаря во время итерации по нему
- Продолжайте обучение.
- Разрешение имен без учета области класса
- Остерегайтесь изменяемых аргументов по умолчанию
- Те же операнды, другая история
- Что не так с логическими значениями?
- Атрибуты класса и атрибуты экземпляра
- метод split ()
- Импорт с подстановочными знаками
- Чему научиться дальше
- Продолжить чтение о Python
Улучшите свой код с лучшими приемами Python
Этот курс проливает свет на некоторые из интересных частей Python, которые вы, возможно, не знали вл. Изучите приемы, которые должен знать каждый программист Python.
Python FTW: Under the Hood
Переменные, пространство имен и область действия
Есть две вещи, о которых нам нужно поговорить, когда дело доходит до изучения Python изнутри: пространство имен и scope .
Пространство имен
В Python, поскольку это объектно-ориентированный язык программирования, все считается объектом. Пространство имен — это просто контейнер для сопоставления имени переменной объекта с этим объектом.
function_namespace = {name_of_obj_a: obj_1, name_of_obj_b: obj_2} for_loop_namespace = {name_of_obj_a: obj_3, name_of_obj_b: obj_4}
Мы можем рассматривать пространства имен как просто словари Python, где имя переменной для объекта является ключом, а значение — самим объектом. Мы создаем новое независимое пространство имен каждый раз, когда определяем цикл, функцию или класс. Каждое пространство имен имеет свою собственную иерархию, называемую областью действия.
Область действия
Область действия на очень высоком уровне — это иерархия, в которой интерпретатор Python может «Видеть» определенный объект. Интерпретатор начинает с наименьшей области видимости, локальной, и смотрит наружу, если он не может найти объявленную переменную для вложенной области. Если интерпретатор не может найти его в закрытой области видимости, он смотрит в глобальную область видимости.
Рассмотрим следующий пример:
i = 1 def foo (): i = 5 print (i, 'in foo () ') print ("локальное пространство имен foo ()", locals ()) return i print ("глобальное пространство имен", globals ()) foo ()
Здесь у нас есть пространство имен global
и у нас есть foo ()
пространство имен. Вы можете взглянуть на отдельные пространства имен, напечатав globals ()
и напечатав locals ()
в заданных местах кода.
Локальное пространство имен довольно простое. Вы можете ясно видеть i
и его значение. Глобальное пространство имен немного отличается тем, что оно также включает в себя некоторые посторонние вещи из Python.
Здесь функция foo отображается как место в памяти, а не как фактическое значение функции, а также значение для i
в пространстве имен global
.
При этом вы можете изменить переменную в глобальном пространстве имен. Просто используйте ключевое слово global
перед именем переменной перед вашей логикой:
i = 1 def foo (): global ii = 5 print (i, 'in foo ()') print (" local namespace ", locals ()) return i print (" global i before func invocation ", globals () [" i "]) foo () print (" global i after func invocation ", globals () [" i "] )
Удаление элемента списка при итерации
При работе со списками в Python нам нужно посмотреть, что происходит, когда мы удаляем элементы из списка когда мы его перебираем. Как правило, повторять и удалять элементы из списка не рекомендуется из-за непредвиденных последствий. Возьмите эти примеры:
del
keyword
Ключевое слово del
удаляет только экземпляр этого элемента в локальном пространстве имен, но не сам фактический элемент в глобальном пространстве имен. Таким образом, глобально определенный list_1
не затронут.
list_1 = ["яблоки", "апельсины", "бананы", "клубника"] для элемента в списке_1: del item print ("список_1:", список_1); # ['яблоки', 'апельсины', 'бананы', 'клубника']
remove ()
метод
В методе remove ()
как только Python удалит элемент из списка, все остальные элементы сдвинутся влево один раз, но итерация не произойдет до тех пор, пока все не будет перемещено.
list_2 = ["яблоки", "апельсины", "бананы", " клубника "] для элемента в списке_2: список_2.remove (элемент) print (" список_2: ", список_2) # ['апельсины', 'клубника']
Вот пошаговое изложение того, как это происходит:
- Первая итерация: удалить
яблоки
.апельсины
перемещается влево и теперь является текущим индексом.bananas
перемещается влево и становится следующим индексом.клубника
слева, и цикл переходит к следующему индексу. - Вторая итерация:
бананы
находится в текущем индексе, поэтому метод удаляетбананы
.клубника
перемещается влево и теперь является текущим индексом. Значений индекса больше нет, поэтому итерация выполнена. - Результат: остались
апельсины
иклубника
в списке.
pop (idx)
метод
Для По той же причине, что мы не используем метод remove при просмотре списка, мы не используем метод pop (idx)
. Если индекс не передается в качестве аргумента, Python удаляет последний индекс в списке.
list_3 = ["яблоки", "апельсины", "бананы", "клубника"] для элемента в списке_3: list_3. pop () print ("list_3:", list_3) # ['яблоки', 'апельсины']
- Первая итерация: удалите
клубнику
, чтобы длина списка теперь равнялась трем. Перейдите к следующей итерации. - Вторая итерация: удалите
бананы
, чтобы длина списка теперь равнялась двум. Больше нет значений индекса, и итерация выполнена. - Результат: остались
яблоки
иапельсины
в списке.
Примечание. Если индекс передается в
pop ( )
, а его не существует, он вызовет ошибкуIndexError
.
Итак, что делает работа?
Секрет перебора и манипулирования списком в Python заключается в нарезке или создании копии списка. Это так же просто, как использовать [:ght:
.
list_4 = ["яблоки", "апельсины", "бананы", "клубника"] для элемента в списке_4 [:]: list_4.remove () #pop () здесь также будет работать. print ("list_4:", list_4) # []
list_4 [:]
Этот оператор делает копию списка в памяти. Исходный список не изменяется, когда мы просматриваем его, но влияет на исходный, когда все готово.
Нравится статья? Прокрутите вниз, чтобы подписаться на нашу бесплатную новостную рассылку, выходящую два раза в месяц.
Изменение словаря во время итерации по нему
словари Python могут быть сложными объектами для работы. Однако совершенно точно можно сказать, что эти словари вообще не могут быть изменены , когда они зацикливаются.
В зависимости от версии Python вы есть, вы либо получите ошибку времени выполнения, либо цикл будет выполняться определенное количество раз (от 4 до 8), пока не потребуется изменить размер словаря.
Вы можете найти обходной путь, используя перечислить понимание, но обычно это не лучший вариант.
для я в x: del x [i] x [i + 1] = i + 1 print (i) print (x)
Продолжайте обучение.
Изучите интересные части Python, не просматривая видео или документацию. Текстовые курсы Educative просты в использовании и содержат среду программирования в реальном времени, что делает обучение быстрым и эффективным.
Python FTW: Under the Hood
Разрешение имен без учета области класса
По словам создателя Python Гвидо ван Россума, Python 2 имел несколько «грязных маленьких секретов», которые допускали определенные утечки. Одна из этих утечек позволила переменной управления циклом изменить значение a в понимании списка.
Это было исправлено в Python 3, предоставив компонентам списка их собственную охватывающую область. Когда составление списка не находит определения для a
во включающей области видимости, оно обращается к глобальной области, чтобы найти значение. Вот почему Python 3 игнорирует a = 17
в области класса.
a = 5class Пример: # global aa = 17 b = [a for i in range (20)] print (Example.y [ 0])
Остерегайтесь изменяемых аргументов по умолчанию
Аргументы по умолчанию в Python — это резервные значения, которые устанавливаются как параметры, если функция вызывается без аргументов . Они могут быть полезны, но если вы вызовете функцию несколько раз подряд, могут возникнуть непредвиденные последствия.
def num_list (nums = []): num = 1 nums.append (num) return nums print (num_list ()) print (num_list ()) print (num_list ([])) print (num_list ()) print (num_list ([4]))
Первые два раза вызывается num_list ()
, к нему будет добавлен 1
в nums
перечислить оба раза. Результат: [1, 1]
. Чтобы сбросить список, вы должны передать пустой список следующему вызову..
Уловка! Чтобы предотвратить ошибки, когда вы используете аргументы по умолчанию, используйте
None
в качестве исходного значения по умолчанию.
Те же операнды, другая история
Переназначения в Python могут быть сложными, если вы не уверены, как они работают. Операторы =
и + =
имеют в Python два разных значения при использовании в сочетании со списками.
# reassignmenta = [1, 2, 3, 4] b = aa = a + [5, 6, 7, 8] print (a) print (b) # extendsa = [1, 2, 3, 4] b = aa + = [5, 6, 7, 8] print ( а) печать (б)
При работе со списками Оператор =
просто означает переназначение. Когда b
назначен как a
, он создает копию a
, как это было в то время. Когда a
переназначается на a + [5, 6, 7, 8]
, он объединяет исходный a
с [5, 6, 7, 8]
для создания [1, 2, 3, 4, 5, 6, 7, 8]
. Список b
не изменился по сравнению с исходным назначением.
С оператором + =
, когда он относится к спискам, ярлык для метода extends ()
. В результате список меняется на месте, давая нам [1, 2, 3, 4, 5, 6, 7, 8]
как для
, так и для b
.
Что не так с логическими значениями?
Когда они доходит до логических значений, это кажется довольно простым. Сколько у нас логических значений и сколько целых значений в этом смешанном массиве?
mixed_type_list = [False, 4.55, "education.io", 3, True, [], False, dict ()] integers_count = 0booleans_count = 0 для элемента в списке mixed_type_list: if isinstance (item, int): inteers_count + = 1 elif isinstance (item, bool): booleans_count + = 1 print (inteers_count) print (booleans_count)
Почему на выходе 4-0
? Короче говоря, логическое значение в Python является подклассом целых чисел. True в Python соответствует 1
, а False равно 0
.
Атрибуты класса и атрибуты экземпляра
В объектно-ориентированном Python класс — это шаблон, а instance — это новый объект, основанный на этом шаблоне. Что бы произошло, если бы мы попытались изменить или смешать назначения переменных класса и переменных экземпляра?
class Animal: x = "tiger" class Vertebrate (Животное): передать класс Cat (Животное): передать print (Animal.x, Vertebrate .x, Cat.x) Vertebrate.x = печать "обезьяны" (Animal.x, Vertebrate.x, Cat.x) Animal.x = печать "лев" (Animal.x, Vertebrate.x, Cat.x) a = Animal () print (ax, Animal.x) ax + = "ess" print (ax, Animal.x)
Здесь у нас есть три класса: Animal
, Vertebrate
и Cat.
. Когда мы назначаем переменную в классе Animal, а другие классы являются расширениями класса Animal, эти другие классы имеют доступ к переменной, созданной в классе Animal.
Будьте уверены в своем переназначении, когда работа с классами и экземплярами. Если вы хотите изменить шаблон , используйте имя класса, а когда вы хотите изменить экземпляр, используйте переменную, которую вы присвоили новому экземпляру имени класса.
метод split ()
split ()
имеет некоторые уникальные свойства в Python. Взгляните на этот пример:
print ('foo' .split ("")) # ['', '', '', '', '', '', '', '', '', 'foo' , ''] print ('foo bar' .split ()) # ['foo', 'bar'] print (''. split ('')) # ['']
Когда мы даем методу разделения разделитель, в этом случае ( ""
) и используйте его для строки любой длины, он разделится на пробелы. Независимо от того, сколько пробелов в строке, она будет разделена на каждый.
Если разделитель не указан, интерпретатор Python будет сжимать все повторяющиеся пробельные символы в один и разделены на этот символ, оставляя только группы непробельных символов разделенными.
Пустая строка, разделенная на пробельный символ, вернет список с пустой строкой в качестве первого индекса.
Импорт с подстановочными знаками
Импорт с подстановочными знаками может быть полезен, если вы знаете, как их использовать. У них есть некоторые особенности, которые могут сбивать их с толку чаще, чем нет. Возьмем этот пример:
def hello_world (str): return str; def _hello_world (str): return str
from helpers import * hello_world ("hello_world - РАБОТАЕТ!") _ hello_world ("_ hello_world - РАБОТАЕТ!")
div>
Если бы мы попытались запустить это в каталоге, в котором находились эти файлы, первый вызов функции hello_world
будет работать нормально. Второе, не очень. При использовании импорта с подстановочными знаками функции, начинающиеся с подчеркивания, не импортируются.
Для этих методов вам придется либо напрямую импортировать функцию, либо использовать __ all __
list для использования импорта с подстановочными знаками.
__ all__ = [hello_world, _private_hello_world] def hello_world (str): return str; def _private_hello_world (str): return str
Примечание: Переменная
__ all__
окружена двумя символами подчеркивания с обеих сторон.
Чему научиться дальше
Поздравляю! Вы узнали о десяти распространенных причудах в Python, которые могут улучшить ваш код. Чтобы максимально использовать возможности языка, важно понимать, что происходит под капотом Python. Но еще многое предстоит узнать, чтобы по-настоящему овладеть Python.
Далее вы должны узнать о:
-
del
операции - Уловки со строками
- Отношения подкласса
- Раздутие экземпляра dicts
- Нерефлексивный метод класса
- и многое другое
Чтобы начать работу с этими и другими причудами, ознакомьтесь с учебным курсом Python FTW: Under the Hood Инструктор Сатвик Кансал больше рассказывает о том, как работает Python, и о причинах некоторых ошибок или ответов в интерпретаторе. Вы можете думать о курсе как о руководстве «Python hacks». Умопомрачительные и веселые!
Удачного обучения!
Продолжить чтение о Python
- Обновления Python 3.9: топографическая сортировка и манипуляции со строками
- Учебник по динамическому программированию: создание эффективных программ на Python
- Часто задаваемые вопросы о Python: быстрые ответы к общим вопросам Python