Особенности ЯП Python3
Содержание
-
Особенности ЯП Python3
-
Базовые особенности
- Python2 и Python3
- Интерпретатор
- Связывание
- Групповое связывание
- «Математические» сравнения
- «Списки»
- Словари
- Цикл с итерируемым объектом
- Выражения как суперпозиция методов
- Неявная динамическая типизация (duck typing)
- Универсальные логические выражения
- Пространства имён
- Строки документации
- Циклические конструкторы
- Наличие современных программных конструкций
- Динамическая объектная модель
- Сравнение с другими языками
- Подробности реализации
-
Базовые особенности
Базовые особенности
Python2 и Python3
Имеется два похожих языка программирования с разным синтаксисом — Pythoh2 и Python3. Python3 — более новый язык, из которого выброшено то, что показалось неудачным в Python2.
Примеры и описание далее относятся к Python3, если не оговорено иное.
Интерпретатор
Python — интерпретируемый, а не компилируемый язык, поэтому многие механизмы контроля (и возникающие благодаря им ошибки) перенесены со стадии лексического/синтаксического анализа на стадию выполнения программы. Например, наличие или отсутствие имени в пространстве видимости проверяется в момент использования этого имени:
1 Python 2.7.8 (default, Nov 20 2014, 14:29:22)
2 [GCC 4.9.2 20141101 (ALT Linux 4.9.2-alt1)] on linux2
3 Type "help", "copyright", "credits" or "license" for more information.
4 >>> a*2
5 Traceback (most recent call last):
6 File "<stdin>", line 1, in <module>
7 NameError: name 'a' is not defined
8 >>> a=2
9 >>> a*2
10 4
Вместо операторных скобок (составных операторов) используется одинаковый отступ записи всех операторов в блоке (это называется «блок с отступом», в грамматике — "suite").
Достоинство: практически любую программу можно прочесть. Недостаток: надо избегать использования символов табуляции.
Связывание
Значение любого питоновского выражения — это объект. Объект можно связать с помощью имени или в качестве элемента составного объекта. Основная операция связывания — это «=». В примере создаётся два объекта: один с одной связью (именем), другой — с четырьмя (три имени и участие в списке).
Удалить объект в Питоне нельзя. Операция del удаляет одну связь. Если эта связь — последняя, объект становится недоступен. В удобный для Питона момент придёт сборщик мусора gc и очистит занимаемую объектом память (с предварительным вызовом у объекта определенного метода-"деструктора").
Все связи равноправны. Если объект модифицируемый, то его можно изменить, обращаясь по любой связи.
Групповое связывание
Связывание может быть групповым, когда слева и справа от «=» стоят последовательности (причём «слева» может быть не одно):
Более того, эти последовательности автоматически распаковываются:
«Математические» сравнения
Конструкции вида «a < b < c» в Питоне могут быть произвольной длины и обозначают многоместные сравнения в «математическом стиле» (в большинстве языков указанный пример читался бы как сравнение результата a<b с c.
«Списки»
Тип данных «list» в питоне — это динамический массив связей. Тип объекта может быть любым, но поскольку любая связь имеет одинаковое внутреннее представление, сложность индексации в объекте типа list — O(1), зато сложность вставки/удаления зависит от расстояния до конца списка, наибольшая для начала (O(n), где n — длина списка), наименьшая — O(1) — для конца. Именно поэтому стек имитировать естественно с помощью list, а вот очередь — лучше с помощью collections.deque. Динамическая реогранизация массива при его значительном увеличении/уменьшении происходит прозрачно для программиста.
Словари
На первый взгляд словари выглядят как массивы, у которых вместо индекса можно писать любой константный питоновсткий объект. На самом деле это — хеш-таблицы, использующие целочисленное значение функции hash(объект) для связывания объекта. Словари не упорядочены.
Множество внутренних структур самого Питона (например, пространства имён), реализованы с помощью словарей.
Цикл с итерируемым объектом
Цикл for переменная in последовательность в Питоне — не просто цикл по последовательности, и тем более — не просто цикл со счётчиком. Роль последовательности может играть любой итерируемый объект (т. е. имеющий метод .__iter__()). Помимо списков итерируемыми являются, например, словарь и файл:
В примере с файлом обратите внимание на удвоение переводов строк: итерация по файлу эквивалентна последовательному вызову метода .readline() (прочесть строку), который возвращает очередную строку целиком, вместе с концевым символом перевода строк, а функция print() при печати добавляет ещё один.
Выражения как суперпозиция методов
Все выражения с объектами можно воспринимать как «синтаксический сахар», удобную форму записи вызова соответствующий методов (они называются «специальными»). Например, a+b превращается в a.__add__(b), причём если при вычислении возникает исключение, то попытка продолжается с помощью b.__radd__(a).
Неявная динамическая типизация (duck typing)
Тип объекта в Питоне всегда строго определён — это класс, экземпляром которого объект является (этот класс возвращает, например, type(объект)). Но в пространстве имён нет никаких привязок к типам
Это означает, например, что при вызове функции или метода (и при вычислении выражения, так как операции — это вызовы методов) никакой проверки типов не производится. Ошибка возникнет только если у объекта не окажется соответствующего операции метода или какая-то из функций/методов всё-таки проверит тип параметра.
1 >>> def su(a,b):
2 ... return a+b
3 ...
4 >>> def di(a,b):
5 ... return a-b
6 ...
7 >>> su(1,2)
8 3
9 >>> su([5,6],["QQ",9.0])
10 [5, 6, 'QQ', 9.0]
11 >>> di(1,2)
12 -1
13 >>> di([5,6],["QQ",9.0])
14 Traceback (most recent call last):
15 File "<stdin>", line 1, in <module>
16 File "<stdin>", line 2, in di
17 TypeError: unsupported operand type(s) for -: 'list' and 'list'
Универсальные логические выражения
В Питоне любой объект может быть параметром операторов if и while, а также булевских операций and, or и not. Обычно одно значение объекта любого класса может считаться «ложью» (такой объект называется нулевым), остальные — «истиной».
Нулевыми являются численные нули, пустые последовательности и словари и т. п., а также все объекты, имеющие метод .__bool__(), у которых он возвращает False.
Частичное вычисление. Операция not объект возвращает True или False, в зависимости от того, является ли объект нулевым, или нет. Операции оббъект1 and объкет2 и объект1 or объект2 возвращают объект1 или объект2 по следующим правилам:
A or B |
B нулевой |
B ненулевой |
А нулевой |
B |
B |
А ненулевой |
A |
A |
То есть «если A ненулевой, результат A, иначе B»
A and B |
B нулевой |
B ненулевой |
А нулевой |
A |
A |
А ненулевой |
B |
B |
То есть «если A нулевой, результат A, иначе B»
В обоих случаях есть ситуация, при которой B не вычисляется.
Пространства имён
Исполняющая система Python с точки зрения программиста выглядит как множество вложенных пространств имён. Каждое пространство имён — это объект. Свойства объекта определяются набором методов и полей (неявная динамическая типизация).
Что важно, состав объекта доступен в процессе работы программы:
1 >>> a = "STRing"
2 >>> dir(a)
3 ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
4 >>> hasattr(a,"lower")
5 True
6 >>> hasattr(a,"hower")
7 False
8 >>> getattr(a,"lower")
9 <built-in method lower of str object at 0x7f84e7270a08>
10 >>> meth = getattr(a,"lower")
11 >>> callable(meth)
12 True
13 >>> meth()
14 'string'
15 >>> a.lower()
16 'string'
Функция dir(<объект>) возвращает содержимое пространства имён объекта — список строк (т. е. список его полей). Проверить наличие поля с заданным имененм у объекта можно с помощью hasattr(объект,"имя поля"), а получить само поле — getattr(объект,"имя поля"). В примере поле оказывается методом (то есть вызываемым объектом), поэтому его можно вызвать. Результат работы такого вызова и обычного a.lower() один и тот же.
Такого рода инстроспекция весьма полезна с учётом неявной динамической типизации. Так как предварительный контроль типов при передаче параметров не предполагается, его можно реализовать внутри любого вызываемого объекта (например, функции или метода):
- Просто ничего не делая. При невозможности воспроизвести алгоритм с фактическими параметрами, например, если вызывается неподдерживаемая операция, возникнет исключение
- Обрабатывая возникающее исключение.
Предварительно проверив, есть ли нужный метод у фактического параметра, либо проверив тип объекта с помощью type(объект)
Функция dir() без параметров возвращает содержимое текущего пространства имён (т. е. ключи словаря, возвращаемого locals()).
Строки документации
Все объекты Python самодокументированы
Циклические конструкторы
Наличие современных программных конструкций
Исключения как средство управления вычислениями. Исключения в Python — это не «действия в чрезвычайных ситуациях», а нормальный инструмент управления потоком вычислений. TODO пример и почему трудно иначе
Повторно-входимые функции
Декораторы
Контексты
Элементы функционального программирования
Динамическая объектная модель
…
Сравнение с другими языками
Паскаль и Си
- (Паскаль) Питон различает большие и маленькие буквы.
- У имён объектов нет типов, потому что они — не переменные, а просто именованные связи. Считается плохим тоном программирования использовать одно и то же имя для объектов разного типа.
- Действительное отличие подхода «имя == связь» от подхода «имя == переменная» заметно только на изменяемых объектах, для константных же (чисел, строк) именованные связи ведут себя совершенно так же, как переменные без типа.
(Паскаль) Нет разделения на функции и процедуры, функция без return возвращает None, возвращаемое значение любой функции можно не использовать.
(Паскаль) Как и в Си, в Питоне «==» — это сравнение, а «=» — присваивание
(Си) Хотя в Питоне есть конструкция вида «a=b=c», операция «=» не является, как в Си, арифметической, и её нельзя использовать в выражениях.
(Паскаль) Операции and, or и not имеют более низкий приоритет, чем арифметические и операции сравнения, поэтому выражение вида a>0 and b+c<0 не требует скобок. Побитовые операции в Питоне обозначаются так же, как в Си: «&», «|» и «~».
(Си) В питоне, как в Си, есть операции изменения объекта (например, «+=» — прибавление). Разумеется, изменяться может только неконстантный объект (например, список), для константного объекта (число, строка) результат такой операции — новый объект, результат вычисления выражения. В приведённом примере в результате прибавления списочный объект остаётся тем же, а целочисленный меняется на другой.
(Си) В Питоне есть тернарная операция вида «результат_истина if условие else результат_ложь», соответствующая «У ? Р_И : Р_Л» в Си. Сверх того имеются и другие операции, замещающие операторы (лямбда-функции, циклические конструкторы)
- Передача параметров в функции происходит строго по соиспользованию. Это значит, что фактическими параметрами функции являются объекты (возможно, только что вычисленные), для них создаются имена в локальном пространстве имён функции, а при выходе из функции эти имена уничтожаются. Копирования данных не происходит. В Си передача данных строго по значению (передача данных по ссылке имитируется передачей указателя на объект). В паскале передача данных либо по значению, либо по ссылке (указывается явно).
Частичное вычисление AND и OR (см. выше) как в Си, но значение — не булевское
- Структуры (записи) как отдельные конструкции в Питоне не выделены. Логически — это просто объекты, у которых нет методов.
Структуры (записи) как последовательности байтов, в которые упакованы объекты разного типа, в синтаксис не встроены, поддерживаются модулем strcut
Массивы как последовательности байтов, представляющие собой последовательности данных одного типа, встречаются и используются в Питоне редко. Есть встроенные типы bytearray/bytes, выделенный модуль array. Самые мощные массивы реализованы в стороннем пакете NumPy.
В Питоне больше, чем с Си и Паскале, конструкций языка и встроенных типов, некоторые из них нужны не сразу (например, assert или with)
Подробности реализации
Некоторые свойства Питона, поясняющие его структуру, но без знания которых можно спокойно жить
Именование как «синтаксический сахар»
То, что мы видим как «именование», — это просто заполнение соответствующего пространства имён парами «имя → объект». Чем, собственно, и обеспечивается референция объекта. Кстати, все пространства имён доступны из самого Питона и имеют стандартный питоновский тип «словарь» (dict). Так что вообще никакой новой сущности не вводится, только «синтаксический сахар».
Пример: функция locals() возвращает словарь имён, локальных в текущем контексте:
1 >>> locals()
2 {'__name__': '__main__', '__builtins__': …}
3 >>> A=123
4 >>> locals()
5 {'A': 123, '__name__': '__main__', '__builtins__': …}
6 >>> locals()["A"]='OK'
7 >>> locals()
8 {'A': 'OK', '__name__': '__main__', '__builtins__': …}
9 >>> QQ
10 Traceback (most recent call last):
11 File "<stdin>", line 1, in <module>
12 NameError: name 'QQ' is not defined
13 >>> locals()["QQ"]='Yes, QQ!'
14 >>> QQ
15 'Yes, QQ!'
16 >>> locals()
17 {'A': 'OK', '__name__': '__main__', 'QQ': 'Yes, QQ!', '__builtins__': …}
Обратите внимание, что ключи в словаре не упорядочены, и в данном примере 'QQ' появляется где-то в середине (а в другй раз может и в другом месте появиться).