Особенности ЯП Python3

Базовые особенности

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").

   1 for i in range(10):
   2     n = 3*i**2 + 2*i + 7
   3     print (i,n)
   4 print "Done"

Достоинство: практически любую программу можно прочесть. Недостаток: надо избегать использования символов табуляции.

Связывание

Значение любого питоновского выражения — это объект. Объект можно связать с помощью имени или в качестве элемента составного объекта. Основная операция связывания — это «=». В примере создаётся два объекта: один с одной связью (именем), другой — с четырьмя (три имени и участие в списке).

   1 >>> a=b=[1,"QQ",2]
   2 >>> c=b
   3 >>> e=[234,678,b]
   4 >>> d=[1,"QQ",2]
   5 >>> id(a), id(b), id(c), id(d), id(e[2])
   6 (139945032097664, 139945032097664, 139945032097664, 139945032132440, 139945032097664)

Удалить объект в Питоне нельзя. Операция del удаляет одну связь. Если эта связь — последняя, объект становится недоступен. В удобный для Питона момент придёт сборщик мусора gc и очистит занимаемую объектом память (с предварительным вызовом у объекта определенного метода-"деструктора").

   1 >>> del a
   2 >>> a
   3 Traceback (most recent call last):
   4   File "<stdin>", line 1, in <module>
   5 NameError: name 'a' is not defined
   6 >>> c
   7 [1, 'QQ', 2]

Все связи равноправны. Если объект модифицируемый, то его можно изменить, обращаясь по любой связи.

   1 >>> c[1]="ZZZZZ"
   2 >>> e[2]
   3 [1, 'ZZZZZ', 2]
   4 >>> b
   5 [1, 'ZZZZZ', 2]

Групповое связывание

Связывание может быть групповым, когда слева и справа от «=» стоят последовательности (причём «слева» может быть не одно):

   1 >>> a=x,y=3,5
   2 >>> a
   3 (3, 5)
   4 >>> x
   5 3
   6 >>> y
   7 5

Более того, эти последовательности автоматически распаковываются:

   1 >>> c=["QQ",3,[12,34],(1,5,6)]
   2 >>> (s,t),n,(x,y),l=c
   3 >>> s
   4 'Q'
   5 >>> t
   6 'Q'
   7 >>> x
   8 12
   9 >>> y
  10 34
  11 >>> l
  12 (1, 5, 6)

«Математические» сравнения

Конструкции вида «a < b < c» в Питоне могут быть произвольной длины и обозначают многоместные сравнения в «математическом стиле» (в большинстве языков указанный пример читался бы как сравнение результата a<b с c.

«Списки»

Тип данных «list» в питоне — это динамический массив связей. Тип объекта может быть любым, но поскольку любая связь имеет одинаковое внутреннее представление, сложность индексации в объекте типа listO(1), зато сложность вставки/удаления зависит от расстояния до конца списка, наибольшая для начала (O(n), где n — длина списка), наименьшая — O(1) — для конца. Именно поэтому стек имитировать естественно с помощью list, а вот очередь — лучше с помощью collections.deque. Динамическая реогранизация массива при его значительном увеличении/уменьшении происходит прозрачно для программиста.

Словари

На первый взгляд словари выглядят как массивы, у которых вместо индекса можно писать любой константный питоновсткий объект. На самом деле это — хеш-таблицы, использующие целочисленное значение функции hash(объект) для связывания объекта. Словари не упорядочены.

Множество внутренних структур самого Питона (например, пространства имён), реализованы с помощью словарей.

Цикл с итерируемым объектом

Цикл for переменная in последовательность в Питоне — не просто цикл по последовательности, и тем более — не просто цикл со счётчиком. Роль последовательности может играть любой итерируемый объект (т. е. имеющий метод .__iter__()). Помимо списков итерируемыми являются, например, словарь и файл:

   1 >>> d={1:"QQ", 222:"abc", (1,"TTT"): 2}
   2 >>> for k in d:
   3 ...   print(k)
   4 ... 
   5 1
   6 222
   7 (1, 'TTT')

В примере с файлом обратите внимание на удвоение переводов строк: итерация по файлу эквивалентна последовательному вызову метода .readline() (прочесть строку), который возвращает очередную строку целиком, вместе с концевым символом перевода строк, а функция print() при печати добавляет ещё один.

   1 >>> for line in open("file.txt"):
   2 ...   print(line)
   3 ... 
   4 First line
   5 
   6 Second line
   7 
   8 Third line

Выражения как суперпозиция методов

Все выражения с объектами можно воспринимать как «синтаксический сахар», удобную форму записи вызова соответствующий методов (они называются «специальными»). Например, 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() один и тот же.

Такого рода инстроспекция весьма полезна с учётом неявной динамической типизации. Так как предварительный контроль типов при передаче параметров не предполагается, его можно реализовать внутри любого вызываемого объекта (например, функции или метода):

  1. Просто ничего не делая. При невозможности воспроизвести алгоритм с фактическими параметрами, например, если вызывается неподдерживаемая операция, возникнет исключение
  2. Обрабатывая возникающее исключение.
  3. Предварительно проверив, есть ли нужный метод у фактического параметра, либо проверив тип объекта с помощью type(объект)

Функция dir() без параметров возвращает содержимое текущего пространства имён (т. е. ключи словаря, возвращаемого locals()).

Строки документации

Все объекты Python самодокументированы /!\

Циклические конструкторы

/!\

Наличие современных программных конструкций

Динамическая объектная модель

Сравнение с другими языками

Паскаль и Си

Подробности реализации

Некоторые свойства Питона, поясняющие его структуру, но без знания которых можно спокойно жить

Именование как «синтаксический сахар»

То, что мы видим как «именование», — это просто заполнение соответствующего пространства имён парами «имя → объект». Чем, собственно, и обеспечивается референция объекта. Кстати, все пространства имён доступны из самого Питона и имеют стандартный питоновский тип «словарь» (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' появляется где-то в середине (а в другй раз может и в другом месте появиться).

Python/Features (last edited 2016-11-02 19:28:07 by FrBrGeorge)