- Операторы * и ** в Питоне. Что это и как использовать
- Что мы обсуждать не будем
- Тогда про что же мы говорим
- Операторы * и ** при распаковке во время вызова функции
- Операторы * и ** при упаковке аргументов, переданных функции
- Позиционные аргументы, содержащие аргументы только из ключевых слов
- Аргументы, содержащие только ключевые слова и не содержащие позиционные аргументы
- Операторы * и ** при распаковке кортежа
- Операторы * и ** в литерале списка
- Оператор ** в литерале словаря
- Операторы * и ** обладают немалыми возможностями в питоне
- Переменные
- Именование идентификаторов
- Объявление переменных и присвоение значений
- Ссылки на объекты
- Идентификация объекта
- Имена переменных в python
- Множественная инициализация переменных в Python
- Типы переменных Python
- Локальные переменные в Python
- Глобальные переменные в Python
- Удаление переменной в Python
- Максимально возможное значение целого числа в Python
- Вывод одной или нескольких переменных в Python
Операторы * и ** в Питоне. Что это и как использовать
Операторы (operators) * и ** встречаются в питоне очень часто. Иногда они немного непонятны и новичкам, и опытным ребятам, переходящим на питон с ряда других языков программирования (в которых операторы могут использоваться немного иначе). Статья известного питон-коуча Трея Ханнера (Trey Hunner), который помогает девелоперам расширять свои знания. Дата написания статьи: 10.11.2018.
Функционал операторов * и ** развивается уже много лет. Я хочу рассмотреть все способы их использования по состоянию на текущий момент. Буду указывать, что конкретно работает только в современных версиях питона. Поэтому, если вы изучали операторы * и ** еще во времена питона 2 (Python 2), советую хотя бы проглядеть данную статью, потому что в питоне 3 (Python 3) этим операторам добавили много новых возможностей.
Если вы начали изучать питон недавно и еще не освоили аргументы ключевых слов (keyword arguments; также известные как именованные аргументы, named arguments), предлагаю сперва прочитать мою статью про аргументы ключевых слов в питоне.
Что мы обсуждать не будем
В данной статье, говоря про операторы * и **, я имею в виду операторы-префиксы (prefix operators), а не инфиксы (infix). То есть, функции умножения и возведения в степень не входят в тему статьи.
Тогда про что же мы говорим
Мы говорим про операторы-префиксы * и **, которые используются перед переменной (variable). Например:
В данном коде можно увидеть два способа использования оператора *. Оператор ** отсутствует.
В сферу применения рассматриваемых операторов входит:
1. Операторы * и **: передача аргументов в функцию.
2. Операторы * и **: захват аргументов, переданных в функцию.
3. Оператор *: принятие аргументов, содержащих только ключевые слова.
4. Оператор *: захват элементов во время распаковки кортежа (tuple).
5. Оператор *: распаковка итерируемых объектов в списке или кортеже.
6. Оператор **: + распаковка словарей в других словарях.
Даже если вам кажется, что вы освоили все эти способы, позволяющие использовать операторы * и **, рекомендую посмотреть на все нижеприведенные блоки кода, чтобы убедиться, что они все вам знакомы. Последние несколько лет разработчики ядра питона продолжают добавлять этим операторам новые возможности, поэтому какие-то из новых применений можно проглядеть.
Операторы * и ** при распаковке во время вызова функции
При вызове функции оператор * можно задействовать для распаковки итерируемого объекта в аргументах, введенных для вызова:
В строке print(*fruits) производится вызов всех элементов списка fruits в функции print. Они становятся отдельными аргументами. При этом нам даже не надо знать, сколько всего аргументов окажется в списке.
В данном примере оператор * – не просто синтактический выверт (syntactic sugar). Без * отправить все элементы конкретного итерируемого объекта в качестве отдельных аргументов было бы невозможно (это не касается списков с сфиксированной длиной).
Еще один пример:
В данном случае мы принимаем список со списками в качестве элементов и возвращаем «преобразованный» список со списками:
Функционал оператора ** примерно такой же, просто он применяется к аргументам ключевых слов. Он позволяет нам взять словарь, содержащий пары из ключей и значений, и распаковать его в аргументы ключевых слов при вызове функции.
Скажу из своего опыта. Оператор ** не часто используется для распаковки аргументов ключевых слов при вызове функции. Чаще всего я вижу такие примеры при работе с наследованием: вызовы super() часто включают в себя оба оператора.
Операторы * и ** можно использовать неоднократно при вызове функции. Данная возможность появилась в питоне 3.5. Иногда это может оказаться очень уместным:
Неоднократное использование ** выглядит примерно так же:
Однако не нужно терять бдительности при неоднократном использовании операторов * и **. Неоднократное указание одного и того же аргумента ключевых слов не допускается в функциях питона. Поэтому, если использовать ** для словарей, то ключи должны быть уникальными. В противном случае возникнет исключение.
Операторы * и ** при упаковке аргументов, переданных функции
При определении тела функции можно использовать оператор *, чтобы захватывать неограниченное количество позиционных аргументов, переданных этой функции. Они оформляются в кортеж.
Данная функция принимает любое количество аргументов.
Функции питона print и zip принимают любое количество позиционных аргументов. Такое использование оператора * при упаковке аргументов позволяет нам создавать свои функции, которые (аналогично print и zip) принимают любое количество аргументов.
Кроме того, для оператора ** в данном вопросе предусмотрена еще одна возможность: его можно использовать при определении тела функции, позволяющей захватить в словарь любые аргументы ключевых слов, переданные этой функции:
В данном месте ** захватывает в словарь аргументы ключевых слов, которые мы передаем данной функции. Впоследствии аргументы атрибутов (attributes) данной функции смогут на него ссылаться.
Позиционные аргументы, содержащие аргументы только из ключевых слов
питон 3 ввел специальный синтаксис для передачи аргументов, содержащих только ключевые слова, в функцию. Они представляют собой такие аргументы функции, которые можно определить только с помощью синтаксиса для ключевых слов. Это означает, что их нельзя определить позиционно.
Чтобы принимать аргументы, содержащие только ключевые слова, мы можем поместить именованные аргументы после оператора * при определении тела функции:
Данную функцию можно использовать так:
Аргументы dictionary и default поставлены после *keys. То есть, их можно только в качестве аргументов ключевых слов. Если мы попытаемся определить их позиционно, то увидим ошибку:
Данное поведение внедрено в питон с помощью предложения PEP 3102.
Аргументы, содержащие только ключевые слова и не содержащие позиционные аргументы
Аргументы, содержащие только ключевые слова, – неплохое средство. Но что если вы хотите требовать ввода аргументов, содержащих только ключевые слова, не захватывая неограниченное количество позиционных аргументов?
питон позволяет сделать это с помощью немного странного синтаксиса, когда оператор * как бы сам по себе:
Данная функция принимает аргумент, содержащий итерируемый объект (iterable). Его можно определить позиционно (то есть, первым) или с помощью названия и аргумента fillvalue, который входит в число аргументов, допускающих только ключевые слова. Это означает, что мы можем вызвать функцию with_previous вот так:
Данная функция принимает два аргумента. Один из них, fillvalue, обязательно определяется как аргумент, содержащий ключевое слово.
Обычно я использую аргументы, допускающие только ключевые слова, при захвате неопределенного количества позиционных аргументов. Но иногда я использую данную возможность оператора *, чтобы форсировать исключительно позиционное определение аргумента.
На самом деле, данный подход используется встроенной функцией питона sorted. Если посмотреть справку для sorted, можно увидеть следующее:
Пример использования оператора * как самого по себе прямо в документации по аргументам функции sorted.
Операторы * и ** при распаковке кортежа
Дополнительно к вышенаписанному, в питоне 3 добавлен новый способ применения *, который некоторым образом связан с вышеописанными возможностями этого оператора при определении тела функции и при вызове функции.
Оператор * теперь можно использовать при распаковке кортежа:
Если вы задаете себе вопрос: как же мне использовать это в своем коде, посмотрите примеры в моей статье про распаковку кортежей в питоне. В этой статье я показал, каким образом такое использование оператора * может, в некоторых случаях, стать альтернативой для срезания последовательностей (sequence slicing).
Обычно во время своих лекций об операторе * я говорю, что можно использовать только одно выражение с ним в отдельном вызове многократного присвоения (multiple assignment). Технически это некорректно, потому что можно его использовать два раза при вложенной распаковке (nested unpacking). Данный вопрос я рассмотрел подробно в статье про распаковку кортежей.
Правда, я никогда не встречал хорошего примера такого использования. Не думаю, что стал бы его рекомендовать, даже если бы удалось найти. Он выглядит немного непонятно.
Данная возможность добавлена в питон на основе предложения PEP 3132. Следует отметить, что оно не относится к очень длинным.
Операторы * и ** в литерале списка
В питоне 3.5 добавлено очень много возможностей, связанных с оператором *, на основе предложения PEP 448. Одной из самых заметных новых возможностей стало использование * для вывода итерируемого объекта в новый список.
Допустим, у вас есть функция, которая принимает любые последовательности и возвращает список, содержащий каскад из последовательности и ее реверсивного варианта:
Данная функция должна пару раз провести конвертацию в список, чтобы объединить списки и вернуть результат. Начиная с питона 3.5, мы можем, вместо вышеприведенного примера, написать следующее:
В данном коде больше нет нескольких ненужных вызовов списков. Поэтому он стал эффективнее и лучше читается.
Данная функция возвращает новый список, в котором первый элемент переданного списка (или другой последовательности) перенесен в конец нового списка.
Это очень удачная возможность, позволяющая с помощью оператора * объединять итерируемые объекты различных типов. Оператор * работает с любыми итерируемыми объектами, а оператор + работает только с определенными последовательностями, при чем все из объединяемых должны быть одного типа.
Отмечу, что данная возможность не ограничивается только созданием списков. Мы можем выводить итерируемые объекты в новые кортежи или множества (set):
Обратите внимание, что последняя строка принимает список и генератор (generator), а потом выводит их в новое множество. Перед появлением этой возможности для оператора * было непросто сделать это в одну строку кода. Разумеется, способ сделать это существовал, но его было непросто вспомнить или обнаружить:
Оператор ** в литерале словаря
Помимо вышеприведенного на основе предложения PEP 448 в функционал ** добавлен вывод пар ключ/значение (key/value) из словаря в новый словарь:
Про это я написал еще одну статью. Сейчас ее можно найти под новым названием про идиоматический способ сливать словари в питоне. Данную возможность можно использовать не только для сливания двух словарей. Например, можно скопировать словарь, параллельно добавляя в него новые значения:
Еще можно скопировать или слить словари, переписывая определенные значения:
Операторы * и ** обладают немалыми возможностями в питоне
В питоне операторы * и ** – не просто синтактический выверт. Некоторые из их возможностей реализуются и другими средствами, но доступные альтернативы обычно более громоздкие и потребляют больше ресурсов. Кроме того, некоторые элементы в функционале этих операторов попросту не доступны без их использования. Например, без помощи * невозможно передать в функцию неопределенное количество позиционных аргументов.
Прочитав обо всех возможностях * и **, вы, возможно, удивитесь названиям, под которыми используются эти странные операторы. К сожалению, для них нет лаконичных названий. Я слышал, как * называли оператором для упаковки и распаковки. Еще слышал, как его называли «splat» (это из мира Руби) и просто звездой.
Чаще всего я называю их звездой (star) и двойной звездой (double star) (или звездой-звездой (star star)). В данном случае разделения с их функциями как инфиксов не проводится (речь идет про операции умножения и возведения в степень). Но обычно из контекста очевидно, о чем идет речь, про префиксы или инфиксы.
Если вы не понимаете операторы * и ** или боитесь не запомнить все их возможности, не нужно беспокоиться. Способов использования много, и запоминать каждую конкретную возможность для каждого из них не так важно. Лучше будет осознать, в каких случаях к ним можно обратиться. Предлагать использовать данную статью как чек-лист или создать свой чек-лист, который поможет вам использовать операторы * и ** в питоне.
Источник
Переменные
Переменная — это имя, которое используется для ссылки на область памяти. Переменная Python также известна как идентификатор и используется для хранения значения.
В Python нам необязательно указывать тип переменной, поскольку Python является языком с динамической типизацией.
Имена переменных могут состоять как из букв, так и из цифр, но они должны начинаться с буквы или символа подчеркивания.
Рекомендуется использовать строчные буквы для имени переменной. Rahul и rahul — это две разные переменные, т.к. имена переменных регистрозависимы.
Именование идентификаторов
Переменные являются примером идентификаторов. Правила присвоения имени идентификатору приведены ниже.
- Первый символ переменной должен быть буквой или символом подчеркивания ( _ ).
- Все символы, кроме первого, могут быть: строчными (a-z), прописными (A-Z), подчеркиванием или цифрами (0-9).
- Имя идентификатора не должно содержать пробелов или специальных символов (!, @, #, %, ^, &, *).
- Имя идентификатора не должно быть похоже ни на одно ключевое слово, определенное в языке.
- Имена идентификаторов чувствительны к регистру; например, myname и MyName — не одно и то же.
- Примеры допустимых идентификаторов: a123, _n, n_9 и т.д.
- Примеры недопустимых идентификаторов: 1a, n%4, n9 и т.д.
Объявление переменных и присвоение значений
Python не обязывает нас объявлять переменную перед ее использованием в приложении. Он позволяет нам создать переменную в нужный момент.
В Python нам не нужно объявлять переменную в явном виде. Когда мы присваиваем переменной какое-либо значение, эта переменная объявляется автоматически.
Оператор = используется для присвоения значения переменной.
Ссылки на объекты
Необходимо понять, как работает интерпретатор Python, когда мы объявляем переменную. Процесс обращения с переменными несколько отличается от многих других языков программирования.
Python — объектно-ориентированный язык программирования, поэтому каждый элемент данных принадлежит к определенному типу класса. Рассмотрим следующий пример.
В приведенном выше операторе print мы создали строковый объект. Давайте проверим его тип с помощью встроенной в Python функции type() .
В Python переменные — это символическое имя, которое является ссылкой или указателем на объект. Переменные используются для обозначения объектов этим именем.
Давайте разберем следующий пример
На изображении выше переменная a относится к целочисленному объекту.
Предположим, что мы присвоим целочисленное значение 50 новой переменной b .
Переменная b ссылается на тот же объект, на который указывает a , потому что Python не создает другой объект.
Давайте присвоим новое значение b . Теперь обе переменные будут ссылаться на разные объекты.
Python эффективно управляет памятью, если мы присваиваем одной и той же переменной два разных значения.
Идентификация объекта
В Python каждый созданный объект идентифицируется уникально. Python гарантирует, что никакие два объекта не будут иметь одинаковый идентификатор. Для определения идентификатора объекта используется встроенная функция id() . Рассмотрим следующий пример.
140734982691168 140734982691168 2822056960944
Мы присвоили b = a , a и b указывают на один и тот же объект. Когда мы проверили функцией id() , она вернула то же самое число. Мы изменили значение a на 500 ; затем он сослался на новый идентификатор объекта.
Имена переменных в python
Мы уже обсуждали, как объявить допустимую переменную. Имена переменных могут быть любой длины, могут содержать прописные и строчные буквы (от A до Z, от a до z), цифры (0-9) и символ подчеркивания(_). Рассмотрим следующий пример допустимых имен переменных.
Рассмотрим следующие имена допустимых переменных.
В приведенном выше примере мы объявили несколько допустимых имен переменных, таких как name, name , и т.д. Но это не рекомендуется, так как при чтении кода это может привести к путанице. Имя переменной должно быть описательным, чтобы сделать код более читабельным.
Описательные имена переменных, состоящие из нескольких слов могут быть определены следующим способом.
- Camel Case — В верблюжьем регистре каждое слово или аббревиатура в середине начинается с заглавной буквы. Не допускается вмешательство пробелов. Например — nameOfStudent , valueOfVaraible и т.д.
- Pascal Case — То же самое, что и верблюжий регистр, но здесь первое слово также является заглавным. Например — NameOfStudent и т.д.
- Snake Case — В змеином регистре слова разделяются подчеркиванием. Например — name_of_student и т.д.
Множественная инициализация переменных в Python
Python позволяет присваивать значение нескольким переменным в одном операторе, что также известно как множественное присваивание.
Мы можем применять множественные присваивания двумя способами: либо присваивая одно значение нескольким переменным, либо присваивая несколько значений нескольким переменным. Рассмотрим следующий пример.
- Присвоение одного значения нескольким переменным
Значения будут присваиваться в том порядке, в котором появляются переменные.
Типы переменных Python
В Python существует два типа переменных — локальная переменная и глобальная переменная.
Локальные переменные в Python
Локальные переменные — это переменные, объявленные внутри функции и имеющие область видимости в пределах функции. Давайте разберем следующий пример.
В приведенном выше коде мы объявили функцию add() и назначили несколько переменных внутри функции. Эти переменные будут называться локальными переменными, которые имеют область видимости только внутри функции. Если мы попытаемся использовать их вне функции, то получим следующую ошибку.
The sum is: 50 print(a) NameError: name ‘a’ is not defined
Мы попытались использовать локальную переменную вне ее области видимости; это вызвало ошибку NameError .
Глобальные переменные в Python
Глобальные переменные могут использоваться во всей программе, и область их действия распространяется на всю программу. Мы можем использовать глобальные переменные внутри или вне функции.
Переменная, объявленная вне функции, по умолчанию является глобальной переменной. Python предоставляет ключевое слово global для использования глобальной переменной внутри функции. Если мы не используем ключевое слово global , функция рассматривает ее как локальную переменную. Давайте разберем следующий пример.
101 Welcome To Javatpoint Welcome To Javatpoint
В приведенном выше коде мы объявляем глобальную переменную x и присваиваем ей значение. Затем мы определили функцию и обратились к объявленной переменной с помощью ключевого слова global внутри функции. Теперь мы можем изменить ее значение. Затем мы присвоили переменной x новое строковое значение.
Теперь мы вызвали функцию и вывели значение переменной x . Она вывела только что присвоенное значение.
Удаление переменной в Python
Мы можем удалить переменную с помощью ключевого слова del . Синтаксис приведен ниже.
В следующем примере мы создаем переменную x и присваиваем ей значение. Мы удалили переменную x , и при печати получаем ошибку variable x is not defined. Переменная x больше не будет использоваться в будущем.
6 Traceback (most recent call last): File «C:/Users/DEVANSH SHARMA/PycharmProjects/Hello/multiprocessing.py», line 389, in print(x) NameError: name ‘x’ is not defined
Максимально возможное значение целого числа в Python
В отличие от других языков программирования, в Python нет типов данных long int или float. Он рассматривает все целочисленные значения как тип данных int. Здесь возникает вопрос. Какое максимальное значение может хранить переменная в Python? Рассмотрим следующий пример.
Как видно из примера выше, мы присвоили переменной x большое целочисленное значение и проверили его тип. Он вывел class , а не long int . Следовательно, число не ограничено битами, и мы можем расширять его до предела нашей памяти.
В Python нет специального типа данных для хранения больших чисел.
Вывод одной или нескольких переменных в Python
Мы можем печатать несколько переменных в одном операторе print . Ниже приведены примеры печати одного и нескольких значений.
Пример — 1 (печать одной переменной)
Пример — 2 (Печать нескольких переменных)
Источник