Перестаньте писать классы. Язык программирования Python — подробно для начинающих


В данной статье приведены основные моменты, которые могут пригодится при переходе на язык программирования Python с другого языка программирования, либо для самостоятельного изучения Python.

Объекто-ориентированность

Это для начинающих можно пока пропустить, и вернуться после прочтения остального материала!

>>> q = >>> p = >>> len(p) 3 >>> p >>> p 2 >>> p.append(’xtra’) >>> p , 4] >>> q

Определение класса является объектом, как и по сути все в языке.

То есть вы можете присвоить переменной определение класса:

>>> class MyClass: ... i = 12345 ... def f(x): ... print dir(x) ... return x ... >>> c = MyClass() >>> i 123 >>> c.i 12345 >>> c.f > >>> d=MyClass >>> e=MyClass() >>> e <__main__.MyClass instance at 0x000000000239E808> >>> c <__main__.MyClass instance at 0x000000000239E7C8> >>> d >>> d.i 12345 >>> c.i 12345 >>> c.f > >>> e.f > >>> d.f >>> g = d() >>> g.f >

Отступы

Отступы используются в языке Python для записи группирующих инструкций. Например, когда вы определяете функцию или тело цикла, вы пишите все инструкции, которые должны войти в функцию, с одинаковыми отступами:

Def some_func(z): y = z*2 # Тело функции return y # Это - тоже функция # А это - уже нет y = 1 print(some_func(y))

Переменные в Python

Целые числа и числа с плавающей запятой

Присваивая цисло в переменную без точки или с помощью int(), вы получите переменную целого типа. Результат деления двух чисел целого типа также будет целым числом — остаток от деления будет отброшен.

Добавьте к числу точку в конце, чтобы создать переменную типа float:

Строки в Python

Подстановка значений в строку

Python позволяет формировать строку используя шаблон и подставляя в него значения переменных.

Есть два варианта подставить значения в строку: позиционная подстановка и использование именованных параметров.

Позиционная подстановка значений

Output = "Product %s in category %s" % (product, category) output = "You have %s $" % usd_count

В данном случае в строку будут последовательно подставлены значения переменных.

Использование именованных параметров

Output = "Today is %(month)s %(day)s.") % {"month": m, "day": d}

При использовании именованных параметров для подстановки в строку значений, будет выбрано значение для подстановки по его имени из словаря.

Этот способ предпочтителен, если вы планируете переводить ваш проект на несколько языков, поскольку позволит переводчикам менять порядок слов в исходном шаблоне.

Форматирование и вывод строк

Завершающая запятая позволяет после вывода значения вставлять пробел вместо перехода на новую строку:

>>> while b < 10: ... print b, ... b += 1 ... 1 2 3 4 5 6 7 8 9 >>> for x in range(1, 11): ... print str(x).rjust(2), str(x*x).rjust(3), ... # Обратите внимание на запятую в конце предыдущей строки! ... print str(x*x*x).rjust(4) ...

Отформатированный вывод:

1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000

Этот пример демонстрирует использование метода строк rjust(), который выравнивает строку вправо в поле заданной ширины, дополняя ее слева пробелами. Ана-логично действуют методы ljust() и center(). Они не выводят ничего - просто возвращают новую строку. Если исходная строка слишком длинная, она не обрезается, а возвращается в неизменном виде: обычно лучше внести беспорядок в расположение колонок, чем вывести неверное значение. (Если Вы действительно хотите ее обрезать, воспользуйтесь операцией среза: ‘s.ljust(n)’.)

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

>>> import string >>> string.zfill(’12’, 5) ’00012’ >>> string.zfill(’-3.14’, 7) ’-003.14’ >>> string.zfill(’3.14159265359’, 5) ’3.14159265359’

Использование оператора % выглядит примерно так:

>>> import math >>> print ’Значение PI примерно равно %5.3f.’ % \ ... math.pi Значение PI примерно равно 3.142.

% для вывода информации в 3 столбца:

>>> for x in range(1,11): ... print ’%2d %3d %4d’ % (x, x*x, x*x*x) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000

Операции и операнды

Присваивание

Можно присвоить значение сразу нескольким переменным

A = b = c = 1 a, b = 0, 1

Возведение в степень

5 в степени 2 (5 в квадрате):

Print 5**2

Логические условия

Операторы in и not in проверяют, есть указанное значение в последовательности. Операторы is и is not определяют, ссылаются ли две переменные на один и тот же объект. Все эти операторы имеют одинаковый приоритет, который ниже, чем у арифметических операторов.

Логические выражения могут быть сцеплены: например, ‘a < b == c’ проверяет,
меньше ли a чем b и равны ли b и c.

Логические выражения можно группировать с помощью логических операторов
and и or, а также результат можно инвертировать оператором not. Все логические
операторы имеют меньший приоритет, чем операторы сравнения. Среди логических операторов, not имеет наибольший приоритет и or - наименьший.

Встроенные в Python функции

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

Циклы

Цикл While

Цикл while используется для многократного выполнения действий, пока выполняется условие:

While expr: suite1

Инструкция while выполняется в следующем порядке:

1. Вычисляется выражение expr и, если оно дает ложь, переходит к пункту 3.
2. Выполняется блок кода suite1. При этом выполнение в блоке инструкции break
немедленно прерывает выполнение цикла (пункт 3 не выполняется), а выполнение
инструкции continue прерывает выполнение блока кода, после чего выполнение
цикла продолжается с пункта 1. После окончания выполнения блока suite1, вы-
полнение цикла продолжается с пункта 1.
3. Выполняется блок кода suite2 (ветвь else). Инструкции break и continue в
этом блоке считаются относящимися к внешнему циклу.

Цикл For

Цикл for в языке Python перебирает элементы произвольной последовательности (например, списка или строки) в порядке их следования:

A = [’кот’, ’окно’, ’выбросить’] >>> for x in a: ... print x, len(x) ... кот 3 окно 4 выбросить 9

Особенности работы цикла for в Python

Инструкция for используется для перебора элементов последовательности:

For lvalue in sequence: suite1

Выражение sequence вычисляется один раз и должно давать последовательность (объект, для которого определена операция получения элемента по индексу; если индекс выходит за пределы диапазона, должно генерироваться исключение IndexError).

Для каждого элемента последовательности sequence в порядке возрастания индексов, начиная с 0, выполняется присваивание lvalue элемента последовательности и выполняется блок кода suite1.

После того как последовательность исчерпана (определяется по сгенерированному исключению IndexError), если присутствует ветвь else, выполняется блок suite2.

Выполнение инструкции break в блоке suite1 немедленно прерывает выполнение цикла (ветвь else игнорируется). При выполнении инструкции continue в блоке suite1 пропускается остаток блока и выполнение цикла продолжается после присваивания lvalue следующего элемента последовательности sequence или выполняется ветвь else, если в последовательности нет следующего элемента.

Вы можете присваивать переменной или переменным, входящим в lvalue, - это никак не отразится на следующем элементе, который будет присвоен lvalue. Переменные, входящие в lvalue не удаляются после окончания выполнения цикла и сохраняют последние присвоенные им значения. Однако, если последовательность sequence пустая, lvalue не будет присвоено никакое значение (таким образом, используя эти переменные без дополнительной проверки, Вы имеете шанс получить ошибку NameError).

Изменение перебираемой последовательности

Изменяя последовательность, элементы которой вы перебираете, будьте внимательны. Текущий элемент последовательности определяется значением внутреннего счетчика. Конец последовательности определяется по исключению IndexError при попытке получить очередной элемент. Таким образом, если в блоке suite1 Вы удалите текущий или один из пройденных элементов последовательности, следующий элемент будет пропущен.

Аналогично, если вы добавите в последовательность новый элемент перед текущим, тело цикла для текущего элемента будет выполнено еще раз. Такое поведение может привести к неприятным ошибкам, которых обычно можно избежать, если перебирать элементы копии исходной последовательности, например:

For x in a[:]: if x < 0: a.remove(x)

Функции range() и xrange()

Если Вам необходимо перебирать последовательность чисел, то пригодится встроенная
функция range(). Она создает список, содержащий арифметическую прогрессию:
>>> range(10)

Функция xrange работает аналогично, только вместо генерации списка создает объект типа xrange — его значения можно перебрать в цикле, но нельзя изменять

>>> type(range(2)) >>> type(xrange(2))

Инструкции break и continue, ветвь else в циклах

Инструкция break выходит из самого внутреннего вложенного цикла for или while. Инструкция continue продолжает выполнение цикла со следующей итерации.

Циклы могут иметь ветвь else, которая выполняется при “нормальном” выходе (исчерпание последовательности в цикле for, неудовлетворение условия в цикле while), без прерывания инструкцией break. Продемонстрируем ее использование на примере поиска простых чисел:

>>> for n in xrange(2, 10): ... for x in xrange(2, n): ... if n % x == 0: ... print n, ’=’, x, ’*’, n/x ... break ... else: ... print n, ’- простое число’ ... 2 - простое число 3 - простое число 4 = 2 * 2 5 - простое число 6 = 2 * 3 7 - простое число 8 = 2 * 4 9 = 3 * 3

Функции

>>> def fib(n):

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

>>> def fib(n): ... ’’’Выводит числа Фибоначчи в пределах заданного числа’’’ ... a, b = 0, 1 ... while b < n: ... print b, ... a, b = b, a+b

>>> q = range(5) >>> def ch(l): ... l.append("New one!") ... >>> q >>> ch(q) >>> q

Инструкция return выходит из функции и возвращает значение. Без аргументов return используется для выхода из середины процедуры, в этом случае возвращается значение None.

Значения по умолчанию вычисляются в месте определения функции в области
видимости определения, так что

I = 5 def f(arg = i): print arg i = 6 f() выведет 5.

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

Def f(a, l = ): l.append(a) return l print f(1) print f(2) print f(3)

Результат выполнения будет следующий:

Произвольный набор аргументов

Наконец, не так часто используемый вариант - определить функцию таким образом, чтобы ее можно было вызвать с произвольным числом аргументов. В этом случае аргументы будут переданы в виде кортежа. Перед переменным числом аргументов может присутствовать произвольное число обычных аргументов:

Def fprintf(file, format, *args): file.write(format % args)

Именованные аргументы

Функция может быть вызвана с использованием именованных аргументов (keyword
arguments) в виде ‘keyword = value’.

Def example(formal, *arguments, **keywords): print "Обычные аргументы:", formal print ’-’*40 for arg in arguments: print arg print ’-’*40 for kw in keywords.keys(): print kw, ’:’, keywords

Python lambda функции

lambda -функция делает то же самое, что и обычная функция.

В отличие от обычной, lambda использует сокращенный синтаксис: список аргументов записывается без скобок и ключевое слово return отсутствует. Тело функции может содержать только одно выражение. lambda-функция не имеет имени, но может быть вызвана через переменную, которой она присвоена.

>>> g = lambda x: x*2 >>> g(3)

Ввод и вывод данных в Python

Чтение и запись файлов

Встроенная функция open() возвращает объект-файл (file) и обычно используется с двумя аргументами: ‘open(filename, mode)’.

>>> f=open(’/tmp/workfile’, ’wb’) >>> print f

Первый аргумент - строка, содержащая имя файла, второй аргумент - строка, содер-жащая несколько символов, описывающих режим использования файла. Режим может быть ’r’, если файл открывается только для чтения, ’w’ - только для записи (су-ществующий файл будет перезаписан), и ’a’ - для дописывания в конец файла. В режиме ’r+’ файл открывается сразу для чтения и записи. Аргумент mode не является обязательным: если он опущен, подразумевается ’r’.

В Windows (а в некоторых случаях и в Macintosh) файлы по умолчанию открывают-ся в текстовом режиме - для того, чтобы открыть файл в двоичном режиме, необходимо к строке режима добавить ’b’. Следует помнить, что двоичные данные, такие как кар-тинки в формате JPEG и даже текст в UNICODE, при чтении из файла или записи в файл, открытый в текстовом режиме, будут испорчены! Лучший способ оградить себя от неприятностей - всегда открывать файлы в двоичном режиме, даже на тех плат-формах, где двоичный режим используется по умолчанию (возможно у Вас когда-нибудь возникнет желание запустить программу на другой платформе).

Модуль pickle

Если у Вас есть объект x и файловый объект f , открытый для записи, простейший способ сохранить объект потребует всего одну строку кода:

Pickle.dump(x, f)

Так же просто можно восстановить объект (f - файловый объект, открытый для чте-ния):

X = pickle.load(f)

Встроенные функции Python

В язык Python входит множество функций, таких как map() и zip(), заметно упрощающих вычисления.

Структуры данных Python

Списки

Список значений, разделенных запятыми, заключенный в квадратные
скобки. Совсем не обязательно, чтобы элементы списка были одного типа

A = [’spam’, ’eggs’, 100, 1234]

Нумерация элементов списка аналогична строкам — первый элемент идет под номером 0.

Методы для работы со списками

append, pop и insert

Append добавляет в конец списка новый элемент.

Вставить элемент в начало или другую позицию списка позволяет метод insert - Вы указываете индекс элемента, перед которым новый элемент будет добавлен:

>>> a.insert(2, -1)

pop() возвращает последний элемент списка, удаляя его из списка.

index и count

Index позволит найти, в каком положении находится первый элемент с определенным значением.

remove, sort, reverse

Использование списков

append и pop позволяют использовать списки в качестве стека:

>>> stack = >>> stack.append(6) >>> stack.append(7) >>> stack >>> stack.pop() 7 >>> stack

Также легко использовать список в качестве очереди элементов — добавляя с помощью append и извлекая первый в очереди с помощью pop(0):

>>> queue = ["Eric", "John", "Michael"] >>> queue.append("Terry") # Terry добавили в очередь >>> queue.append("Graham") # Graham добавили в очередь >>> queue.pop(0) ’Eric’ >>> queue.pop(0) ’John’ >>> queue [’Michael’, ’Terry’, ’Graham’]

Срезы

Срезы нельзя делать из словарей и множеств или наборов.
Самое распространенное применение срезов в python — создания копии последовательности или ее части.
Рассмотрим срез как часть последовательности. Например, несколько срезов со списка:

>>> s = #простой список >>> s[:] #копия списка, часто очень полезно >>> s # все элементы кроме первого >>> s[-3:] # последние 3 элемента >>>s #откидываем первые и последние 2

Срезы могут быть с тремя параметрами:

S[::2] #парные элементы >>> s #элементы с первого по четвертый с шагом 2

Все эти действия можно проворачивать со строками, кортежами и списками.

>>> "Hello Dolly!" "el ol!"

Как «развернуть» строку (кортеж, список):

>>> "God saw I was dog"[::-1] "god saw I was doG" >>> #отрицательный шаг может оказаться граблями, если не знать особенностей.

Есть несколько действий со срезами, которые можно делать только со списками. Дело в том, что они единственные из базовых последовательностей, которые могут изменяться, и, для которых, имеет значение порядок. Дальше пойдет разговор о срезах, которые изменяют последовательность.
Можно удалять:

>>> s = list(range(10)) #заполняем 0..9 >>> del s #удаляем элементы между третьим и предпоследним с шагом 2 >>> s [ 0, 1, 2, 4, 6, 8, 9]

Ещё можно вставлять элементы:
В варианте замены:

>>> s=list("AF") #список был , мы заменили указанные элементы на [‘A’,’F’] >>> #да, ещё в такой конструкции должны совпадать размеры, это легче понять попробовав >>> s [ 0, 1, "A", 4, "F", 8, 9]

Ну, или вариант вставки попроще:

>>> s = ["4 was here"] # замена последовательного кусочка >>> s [ 0, 1, "A", "4 was here", "F", 8, 9] >>> s = ["after zero"] #или, просто, вставка >>> s [ 0, "after zero", 1, "A", "4 was here", "F", 8, 9]

Можно создать класс, с которого можно будет делать срезы.
Переопределить __getitem__, __setitem__ и __delitem__.
С первого взгляда все кажется предельно простым, но если присмотреться, то __getitem__(self, key) – получает только один параметр, key, а у среза у нас может быть целых 3 числа… Все предельно просто: в случае, когда кто-то пытается срезать кусочек от нашего объекта, значением key функция получит объект типа slice:

>>> class MySliceble(): def __getitem__(self, key): if isinstance(key, slice): return list(range(key.start, key.stop, key.step)) else: raise Exception("Trying to access by index") >>> my = MySliceble() >>> my

Конечно, пример очень символический, но понять можно: у объекта класса slice есть три свойства: start, stop и step, соответствуют числам из скобок среза. Нужно быть внимательным, если число пропущена, то значение будет None, например [::] будет slice(None, None, None) а [:-3] будет slice(None, -3, None).
Замену/вставку и удаление срезов делаем по аналогии.

Кортежи — tuple

Кортеж — последовательность элементов, перечисленных через запятую и заключенная в круглые скобки. Сам кортеж не может быть изменен, но может содержать изменяемые элементы.

>>> t = 1, [’foo’, ’bar’] >>> t (1, [’foo’, ’bar’]) >>> t = Traceback (innermost last): File "", line 1, in ? TypeError: object doesn’t support item assignment >>> t.append(’baz’) >>> t(1, [’foo’, ’bar’, ’baz’])

Создание пустого кортежа

c = ()

Создание кортежа из одного элемента

c = (1,)

Словари — dictionaries

Лучше всего представлять словарь как неупорядоченное множество пар ключ: значение, с требованием уникальности ключей в пределах одного словаря. Пара фигурных скобок {} создает пустой словарь. Помещая список пар key: value, разделенных за-пятыми, в фигурные скобки, Вы задаете начальное содержимое словаря. В таком же виде записывается словарь при выводе.

Чтобы обратиться к элементу словаря, нужно указать его ключ в квадратных скобках.

>>> tel = {"jack": 4098, "sape": 4139} >>> tel["guido"] = 4127 >>> tel {"sape": 4139, "guido": 4127, "jack": 4098} >>> tel["jack"] 4098 >>> del tel["sape"] >>> tel["irv"] = 4127 >>> tel {"guido": 4127, "irv": 4127, "jack": 4098} >>> tel.keys() ["guido", "irv", "jack"] >>> "guido" in tel True

Модули в Python

Модуль - файл, содержащий определения и другие инструкции языка Python. Имя
файла образуется путем добавления к имени модуля суффикса (расширения) ‘.py’. В
пределах модуля, его имя доступно в глобальной переменной __name__.

Модуль может содержать любые инструкции, предназначенные для его инициа-лизации, а не только определения функций. Они выполняются, только когда модуль импортируется первый раз.

Импортирование функций и переменных

Такой вариант инструкции import позволяет импортировать все имена, опре-деленные в модуле, кроме имен, начинающихся с символа подчеркивания (‘_’):
>>> from fibo import *

Начиная с версии Python 2.0, можно произвести подмену импортируемых имен при выполнении инструкции import:

Import string as _string from anydbm import open as dbopen

Функция dir()

Для выяснения имен, определенных в модуле, можно использовать встроенную функцию dir(). Она возвращает отсортированный список строк:

>>> import fibo, sys >>> dir(fibo) [’__name__’, ’fib’, ’fib2’] >>> dir(sys) [’__name__’, ’argv’, ’builtin_module_names’, ’copyright’, ’exit’, ’maxint’, ’modules’, ’path’, ’ps1’, ’ps2’, ’setprofile’, ’settrace’, ’stderr’, ’stdin’, ’stdout’, ’version’]

Без аргументов, dir() возвращает список имен, определенных в текущей области видимости:

Список, возвращаемый функцией dir() не содержит имена встроенных функций и переменных - они определены в стандартном модуле __builtin__:

Файл ‘__init__.py’ необходим для того, чтобы Python распознавал каталог, как со-держащий пакет - таким образом предотвращается маскировка полноценных модулей, расположенных далее в путях поиска, каталогами с распространенными именами (таки-ми как ‘string’). В простейшем случае, ‘__init__.py’ - пустой файл, но может содержать код инициализации пакета и/или устанавливать переменную __all__,

Инструкция import использует следующее соглашение: если в иницилизационном файле ‘__init__.py’ определен список с именем __all__, он исполь-зуется в качестве списка имен модулей, которые должны импортироваться при ис-пользовании ‘from package import *’. Поддержка этого списка в соответствии с текущим составом пакета возлагается на автора. Можно также не определять спи-сок __all__, если авторы не считают уместным импортирование *.

Обработка исключений

Следующий пример демонстрирует пользователю приглашение до тех пор, пока не будет введено целое число или выполнение не будет прервано (обычно Ctrl-C). Во втором случае генерируется исключение KeyboardInterrupt.

While 1: try: x = int(raw_input("Введите целое число: ")) break except ValueError: print "Вы ошиблись, попробуйте еще раз..."

Инструкция try может иметь более одной ветви except, определяя обработчики для разных исключений. Выполняться будет (как максимум) только один из них. Об-рабатываются только исключения, генерированные в соответствующей ветви try, но не в других обработчиках инструкции try. После ключевого слова except может быть указано несколько типов исключений в виде кортежа:

Except (RuntimeError, TypeError, NameError): ... pass

После всех ветвей except, инструкция try может содержать ветвь else, которая будет выполняться в случае, если во время выполнения ветви try исключения не генерируются.

Классы в Python

Наиболее важные особенности классов: механизм наследования допускает несколько базовых классов, производный класс может переопределить любые методы базовых классов, из метода можно вызывать метод с тем же именем базового класса. Объекты могут содержать произвольное количество собственных данных.

Синтаксис определения класса

Простейшая модель определения класса выглядит следующим образом:

Class class_name: some_instruction

Создание объектов — экземпляров класса

Создание экземпляра класса использует запись вызова функций. Просто считайте объект-класс функцией без параметров, возвращающей созданный экземпляр класса.

X = MyClass()

В приведенном примере создается “пустой” объект.

Пример создания класса с атрибутами и методами:

Class MyClass: i = 12345 def f(x): return "Привет всему миру!"

Во многих случаях необходимо создавать объект с определенным начальным состоянием - для этого класс должен содержать специальный метод __init__(),

class MyClass: def __init__(self): self.data =

Если для класса определен метод __init__(), то он автоматически вызывается при создании каждого экземпляра этого класса.

Для большей гибкости метод __init__(), конечно, может иметь аргументы. В этом случае, аргументы, используемые при создании экземпляра класса, передаются методу __init__(). Например:

>>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5)

Методы экземпляров класса

Обычно метод вызывают непосредственно:

В нашем примере он вернет строку ’Привет всему миру!’. При этом совсем не обязательно вызывать метод прямо. x.f является объектом, и его можно сохранить для дальнейшего использования:

Xf = x.f while 1: print xf()

Особенность методов класса состоит в том, что что они получают объект, к которому принадлежат, в качестве первого аргумента. В нашем примере вызов x.f() полностью эквивалентен MyClass.f(x). В общем, вызов метода, привязанного к объекту, со списком из n аргументов полностью эквивалентен вызову соответствующего не привязанного метода-функции со списком аргументов, полученным добавлением объекта перед первым аргументом.

Наследование

Определение производного класса с именем ClassB выглядит следующим образом:

Class ClassB(ClassA): ...

Базовый класс (ClassA) должен быть определен в области видимости, в которой находится определение производного класса ClassB. Вместо имени базового класса можно использовать выражение.

Например, если базовый класс определен в другом модуле:

Class ClassB(ModulA.ClassA):

Производные классы могут переопределить методы базовых классов. Метод базового класса, вызывающего другой определенный для него метод, может, на самом деле,
вызывать метод производного класса, переопределившего этот метод

>>> class ClassA: ... a = "A" ... b = "B" ... def Print_A(self): ... print a ... def Print_B(self): ... print self.b ... def Print_Both(self): ... pring ... def PrintBoth(self): ... print "Printing A" ... self.Print_A() ... print "Printing B" ... self.Print_B() ... >>> a = "aaa" >>> cc = ClassA() >>> cc.Print_A() aaa >>> cc.Print_B() B >>> cc.PrintBoth() Printing A aaa Printing B B >>> class ClassB(ClassA): ... def Print_A(self): ... print self.a ... >>> ccc = ClassB() >>> ccc.PrintBoth() Printing A A Printing B B

Переопределяя метод в производном классе, Вы можете также захотеть вызвать метод базового класса с тем же именем. Это можно сделать: просто вызовите метод, явно указав имя класса:

>>> class ClassC(ClassA): ... def Print_A(self): ... print "Print using old method from ClassA" ... ClassA.Print_A(self) ... >>> c = ClassC() >>> c.PrintBoth() Printing A Print using old method from ClassA aaa Printing B B

Множественное наследование в Python

В Python есть поддержка множественного наследования. Чтобы ваш новый класс стал наследником атрибутов и методов нескольких других классов, просто перечислите их через запятую в определении нового класса:

>>> class ClassD(ClassB, ClassA): ... "Checking inheritance" ... ... >>> d = ClassD() >>> d.PrintBoth() Printing A A Printing B B

Важный нюанс при множественном наследовании — это схема поиска объектов (разрешения имен) — сперва поиск ведется в глубину, затем слева направо.

Это означает, что если имя метода или атрибута есть в обоих классах, от которых вы наследуете, то будет использовано то, которое присутствует в первом или его предках.

Частные атрибуты

>>> class clA: ... __privateA = "aaa" ... def prn(s): ... print s.__privateA ... >>> class clB(clA): ... __privateA = "bbb" ... >>> A = clB() >>> A.prn() aaa >>> A.__privateA Traceback (most recent call last): File "", line 1, in AttributeError: clB instance has no attribute "__privateA" >>> dir(A) ["__doc__", "__module__", "_clA__privateA", "_clB__privateA", "prn"] >>> A._clB__privateA "bbb" >>>

Практические примеры

Как убрать из строки все символы, кроме цифр, в Python?

>>> import re >>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd") "987978098098098"

Мы немного поговорили, теперь поговорим о функциях и методах строк .

Я постарался собрать здесь все строковые методы и функции, но если я что-то забыл - поправляйте.

Базовые операции

    Конкатенация (сложение)

    >>> S1 = "spam" >>> S2 = "eggs" >>> print (S1 + S2 ) "spameggs"
  • Дублирование строки

    >>> print ("spam" * 3 ) spamspamspam
  • Длина строки (функция len)

    >>> len ("spam" ) 4
  • Доступ по индексу

    >>> S = "spam" >>> S [ 0 ] "s" >>> S [ 2 ] "a" >>> S [ - 2 ] "a"

    Как видно из примера, в Python возможен и доступ по отрицательному индексу, при этом отсчет идет от конца строки.

  • Извлечение среза

    Оператор извлечения среза: . X – начало среза, а Y – окончание;

    символ с номером Y в срез не входит. По умолчанию первый индекс равен 0, а второй - длине строки.

    >>> s = "spameggs" >>> s [ 3 : 5 ] "me" >>> s [ 2 : - 2 ] "ameg" >>> s [: 6 ] "spameg" >>> s [ 1 :] "pameggs" >>> s [:] "spameggs"

    Кроме того, можно задать шаг, с которым нужно извлекать срез.

    >>> s [:: - 1 ] "sggemaps" >>> s [ 3 : 5 : - 1 ] "" >>> s [ 2 :: 2 ] "aeg"

Другие функции и методы строк

При вызове методов необходимо помнить, что строки в Python относятся к категории неизменяемых последовательностей, то есть все функции и методы могут лишь создавать новую строку.

>>> s = "spam" >>> s [ 1 ] = "b" Traceback (most recent call last): File "", line 1, in s = "b" TypeError : "str" object does not support item assignment >>> s = s [ 0 ] + "b" + s [ 2 :] >>> s "sbam"

Поэтому все строковые методы возвращают новую строку, которую потом следует присвоить переменной.

Таблица "Функции и методы строк"

Функция или метод Назначение
S = "str"; S = "str"; S = """str"""; S = """str"""
S = "s\np\ta\nbbb" Экранированные последовательности
S = r"C:\temp\new" Неформатированные строки (подавляют экранирование)
S = b"byte" Строка
S1 + S2 Конкатенация (сложение строк)
S1 * 3 Повторение строки
S[i] Обращение по индексу
S Извлечение среза
len (S) Длина строки
S.find (str, ,) Поиск подстроки в строке. Возвращает номер первого вхождения или -1
S.rfind (str, ,) Поиск подстроки в строке. Возвращает номер последнего вхождения или -1
S.index (str, ,) Поиск подстроки в строке. Возвращает номер первого вхождения или вызывает ValueError
S.rindex (str, ,) Поиск подстроки в строке. Возвращает номер последнего вхождения или вызывает ValueError
S.replace (шаблон, замена) Замена шаблона
S.split (символ) Разбиение строки по разделителю
S.isdigit () Состоит ли строка из цифр
S.isalpha () Состоит ли строка из букв
S.isalnum () Состоит ли строка из цифр или букв
S.islower () Состоит ли строка из символов в нижнем регистре
S.isupper () Состоит ли строка из символов в верхнем регистре
S.isspace () Состоит ли строка из неотображаемых символов (пробел, символ перевода страницы ("\f"), "новая строка" ("\n"), "перевод каретки" ("\r"), "горизонтальная табуляция" ("\t") и "вертикальная табуляция" ("\v"))
S.istitle () Начинаются ли слова в строке с заглавной буквы
S.upper () Преобразование строки к верхнему регистру
S.lower () Преобразование строки к нижнему регистру
S.startswith (str) Начинается ли строка S с шаблона str
S.endswith (str) Заканчивается ли строка S шаблоном str
S.join (список) Сборка строки из списка с разделителем S
ord (символ) Символ в его код ASCII
chr (число) Код ASCII в символ
S.capitalize () Переводит первый символ строки в верхний регистр, а все остальные в нижний
S.center (width, ) Возвращает отцентрованную строку, по краям которой стоит символ fill (пробел по умолчанию)
S.count (str, ,) Возвращает количество непересекающихся вхождений подстроки в диапазоне [начало, конец] (0 и длина строки по умолчанию)
S.expandtabs () Возвращает копию строки, в которой все символы табуляции заменяются одним или несколькими пробелами, в зависимости от текущего столбца. Если TabSize не указан, размер табуляции полагается равным 8 пробелам
S.lstrip () Удаление пробельных символов в начале строки
S.rstrip () Удаление пробельных символов в конце строки
S.strip () Удаление пробельных символов в начале и в конце строки
S.partition (шаблон) Возвращает кортеж, содержащий часть перед первым шаблоном, сам шаблон, и часть после шаблона. Если шаблон не найден, возвращается кортеж, содержащий саму строку, а затем две пустых строки
S.rpartition (sep) Возвращает кортеж, содержащий часть перед последним шаблоном, сам шаблон, и часть после шаблона. Если шаблон не найден, возвращается кортеж, содержащий две пустых строки, а затем саму строку
S.swapcase () Переводит символы нижнего регистра в верхний, а верхнего – в нижний
S.title () Первую букву каждого слова переводит в верхний регистр, а все остальные в нижний
S.zfill (width) Делает длину строки не меньшей width, по необходимости заполняя первые символы нулями
S.ljust (width, fillchar=" ") Делает длину строки не меньшей width, по необходимости заполняя последние символы символом fillchar
S.rjust (width, fillchar=" ") Делает длину строки не меньшей width, по необходимости заполняя первые символы символом fillchar
S.format (*args, **kwargs)

Признак того, что объект не должен быть классом - если в нём всего 2 метода, и один из них - инициализация, __init__. Каждый раз видя это, подумайте: «наверное, мне нужна просто одна функция».

Перевод доклада Джэка Дидриха , одного из ключевых разработчиков языка Питон. Доклад прозвучал 9 марта 2012 на конференции PyCon US.

Все из вас читали Дзэн Питона , наверное много раз. Вот несколько пунктов из него:

  • Простое лучше сложного
  • Плоское лучше вложенного
  • Важна читаемость
  • Если программу трудно объяснить, она плохая
  • Если программу легко объяснить, возможно, она хорошá

Написал этот текст Тим Питерс. Он умнее и вас, и меня. Сколько вы знаете людей, в честь которых назвали алгоритм сортировки? Вот такой человек написал Дзэн Питона. И все пункты гласят: «Не делай сложно. Делай просто.» Именно об этом и пойдёт речь.

Итак, в первую очередь, не делайте сложно, там, где можно сделать проще. Классы очень сложны или могут быть очень сложны. Но мы всё равно делаем сложно, даже стараясь делать проще. Поэтому в этом докладе мы прочитаем немного кода и узнаем, как заметить, что идём неверным путём, и как выбраться обратно.

На своей работе я говорю коллегам: «Я ненавижу код, и хочу чтобы его было как можно меньше в нашем продукте.» Мы продаём функционал, не код. Покупатели у нас не из-за кода, а из-за широкого функционала. Каждый раз, когда код удаляется, это хорошо. Нас четверо, и в последний год мы перестали считать количество строк в продукте, но продолжаем вводить новый функционал.

Классы

Из этого доклада вам в первую очередь нужно запомнить вот этот код. Это крупнейшее злоупотребление классами, встречающееся в природе.

Class Greeting(object): def __init__(self, word="Hello"): self.word = word def greet(self, name): return "%s, %s!" % (self.word, name) >>> greeting = Greeting("Hola") >>> greeting.greet("Jorge") Hola, Jorge!

Это не класс, хотя он похож на класс. Имя - существительное, «приветствие». Он принимает аргументы и сохраняет их в __init__. Да, выглядит как класс. У него есть метод, читающий состояние объекта и делающий что-то ещё, как в классах. Внизу написано, как этим классом пользуются: создаём экземпляр Приветствия и затем используем это Приветствие чтобы сделать что-то ещё.

Но это не класс, или он не должен быть классом. Признак этого - в нём всего 2 метода, и один из них - инициализация, __init__. Каждый раз видя это, подумайте: «наверное, мне нужна просто одна функция».

Каждый раз когда из написанного класса вы создаёте всего один экземпляр, используете только раз и тут же выбрасываете, следует думать: «ой, надо бы это отрефакторить! Можно сделать проще, намного проще!»

Def greet(name): ob = Greeting("превед") print ob.greet(name) return

Эта функция состоит из 4 строк кода. А вот как можно сделать то же самое всего за 2 строки:

Def greet(greeting, name): return "%s, %s!" % (greeting, name) import functools greet = functools.partial(greet, "превед") greet("красавчик")

Если вы всё время вызываете функцию с тем же первым аргументом, стандартной библиотеке есть инструмент! functools.partial. Вот посмотрите в код выше: добавляете аргумент, и результат можно вызывать многократно.

Не знаю, у скольких из вас диплом в ИТ, у меня он есть. Я учил такие понятия как

Разделение полномочий
- уменьшение связанности кода
- инкапсуляция
- изоляция реализации

С тех пор как я закончил вуз, 15 лет я этих терминов не употреблял. Слыша эти слова, знайте, вас дурят. Эти термины сами по себе не требуются. Если их используют, люди имеют в виду совершенно разное, что только мешает разговору.

Пример: брюки превращаются...

Многие из вас пользуются в повседневной работе сторонними библиотеками. Каждый раз когда надо пользоваться чужим кодом, первое, что нужно сделать - прочитать его. Ведь неизвестно, что там, какого качества, есть ли у них тесты и так далее. Нужно проверить код прежде чем включать его. Иногда читать код бывает тяжко.

Сторонняя библиотека API, назовём её ShaurMail, включала 1 пакет, 22 модуля, 20 классов и 660 строк кода. Мне пришлось всё это прочитать прежде чем включить в продукт. Но это был их официальный API, поэтому мы пользовались им . Каждый раз когда приходили обновления API, приходилось просматривать диффы, потому что было неизвестно, что они поменяли. Вы посылали патчи - а в обновлении они появились?

660 строк кода, 20 классов - это многовато, если программе нужно только дать список адресов электронной почты, текст письма и узнать, какие письма не доставлены, и кто отписался.

Что такое злоупотребление классами? Часто люди думают, что им понадобится что-то в будущем.… Не понадобится. Напишите всё, когда потребуется. В библиотеке ШаурМаил есть модуль ШаурХэш, в котором 2 строки кода:

Class ShaurHash(dict): pass

Кто-то решил, что позже понадобится надстройка над словарём. Она не понадобилась, но везде в коде остались строки, как первая:

My_hash = ShaurMail.ShaurHash.ShaurHash(id="cat") d = dict(id="cat") d = {"id": "cat"}

Вторая и третья строки кода - никому не нужно объяснять их. Но там везде повторялась эта мантра «ШаурМаил-ШаурХэш-ШаурХэш». Троекратное повторение слова «Шаур» - ещё один признак излишества. От повторений всем только вред. Вы раздражаете пользователя, заставляя его писать «Шаур» три раза. (Это не настоящее имя компании, а вымышленное.)

Потом они уволили этого парня и наняли того, кто знал, что делает. Вот вторая версия API:

Class API: def __init__(self, key): self.header = dict(apikey=key) def call(self, method, params): request = urllib2.Request(self.url + method + "/" + method, urllib.urlencode(params), self.header) try: response = json.loads(urllib2.urlopen(request).read()) return response except urllib2.HTTPError as error: return dict(Error=str(error))

В той было 660 строк, в этой - 15. Всё, что делает этот код - пользуется методами стандартной библиотеки. Он читается целиком, легко, за секунды, и можно сразу понять, что он делает. Кстати, в нём был ещё набор тестов из 20 строк. Вот как надо писать. Когда они обновляли API, я мог прочесть изменения буквально за пару секунд.

Но и здесь можно заметить проблему. В классе два метода, и один из них - __init__. Авторы этого не скрывали. Второй метод - call, «вызвать». Вот как этим API пользоваться:

ShaurMail.API(key="СЕКРЕТНЫЙ КЛЮЧ").call(("mailing", "statistics"), {"id": 1})

Строка длинная, поэтому мы делаем алиас и вызываем его многократно:

ShaurMail.request = ShaurMail.API(key="СЕКРЕТНЫЙ КЛЮЧ").call ShaurMail.request(("mailing", "statistics"), {"id": 1})

Заметьте, мы пользуемся этим классом как функцией. Ею он и должен быть. Если видите подобное, знайте, класс тут не нужен. Поэтому я послал им третью версию API:

ShaurMail_API = url = "https://api.shaurmail.com/%s/%s" ShaurMail_API_KEY = "СЕКРЕТНЫЙ КЛЮЧ" def request(noun, verb, **params): headers = {"apikey": ShaurMail_API_KEY} request = urllib2.Request(ShaurMail_API % (noun, verb), urllib.urlencode(params), headers) return json.loads(urllib2.urlopen(request).read())

Он вообще не создаёт файлов в нашем проекте, потому что я вставил его в тот модуль, где он используется. Он делает всё, что делал 15-строковый API, и всё, что делал 660-строковый API.

Вот с чего мы начали и к чему пришли:

  • 1 пакет + 20 модулей => 1 модуль
  • 20 классов => 1 класс => 0 классов
  • 130 методов => 2 метода => 1 функция
  • 660 строк кода => 15 строк => 5 строк

Легче пользоваться, легче писать, никому не надо выяснять, что происходит.

Стандартная библиотека

Кто пришёл из языка Java, возможно, считает, что пространства имён нужны для таксономии. Это неверно. Они нужны чтобы предотвратить совпадения имён. Если у вас глубокие иерархии пространств, это никому ничего не даёт. ShaurMail.ShaurHash.ShaurHash - всего лишь лишние слова, которые людям надо помнить и писать.

В стандартной библиотеке Питона пространство имён очень неглубокое, потому что вы либо помните, как называется модуль, либо надо смотреть в документации. Ничего хорошего если надо выяснять цепочку, в каком пакете искать, в каком пакете в нём, в каком пакете дальше, и как называется модуль в нём. Нужно просто знать имя модуля.

К нашему стыду, вот пример из нашего же кода, и те же грехи видно и здесь:

Services.crawler.crawlerexceptions.ArticleNotFoundException

Пакет, в котором модуль из 2 строк, класс исключения и «pass». Чтобы использовать это исключение, надо дважды написать «crawler», дважды слово «exception». Имя ArticleNotFoundException само себя повторяет. Так не надо. Если вы называете исключения, пусть это будет EmptyBeer, BeerError, BeerNotFound, но BeerNotFoundError - это уже много.

Можно просто пользоваться исключениями из стандартной библиотеки. Они понятны всем. Если только вам не нужно выловить какое-то специфическое состояние, LookupError вполне подойдёт. Если вы получили отлуп по почте, всё равно придётся его читать, поэтому неважно, как называется исключение.

Кроме того, исключения в коде обычно идут после raise и except, и всем сразу понятно, что это исключения. Поэтому не нужно добавлять «Exception» в название.

В стандартной библиотеке Питона есть и ржавые детали, но она - очень хороший пример организации кода:

  • 200 000 строк кода
  • 200 модулей верхнего уровня
  • в среднем по 10 файлов в пакете
  • 165 исключений

10 файлов в пакете - это много, но только из-за некоторых сторонних проектов, добавленных в библиотеку, где были пакеты из всего 2 файлов. Если вам вздумается создать новое исключение, подумайте лучше, ведь в стандартной библиотеке обошлись 1 исключением на 1200 строк кода.

Я не против классов в принципе. Классы бывают нужны - когда много меняющихся данных и связанных с ними функций. Однако в каждодневной работе такое бывает нечасто. Регулярно приходится работать со стандартной библиотекой, а там уже есть подходящие классы. За вас их уже написали.

Единственное исключение в библиотеке Питона - модуль heapq. Heap queue, «очередь в куче» - это массив, который всегда отсортирован. В модуле heapq десяток методов, и они все работают с той же «кучей». Первый аргумент всегда остаётся тем же, что значит, здесь действительно напрашивается класс.

Heapify(data) pushleft(data, item) popleft(data) pushright(data, item) popright(data)
и т.д.

Каждый раз, когда нужно пользоваться heapq, я беру реализацию этого класса из своего инструментария.

Class Heap(object): def __init__(self, data=None, key=lambda x: None): self.heap = data or heapq.heapify(self.heap) self.key = key def pushleft(self, item): if self.key: item = (self.key(item), item) heapq.pushleft(self.heap, item) def popleft(self): return heapq.popleft(self.heap)

Классы разрастаются как сорняки

Состояние OAuth в Питоне - неважное. Опять же, есть сторонние библиотеки, и прежде чем использовать в своём проекте, их нужно прочесть.

Я пытался использовать сокращатель урлов от Гугла: мне нужно было взять урлы и просто сократить их. У Гугла есть проект, в котором 10 000 строк кода. 115 модулей и 207 классов. Я написал отповедь об этом в Гугле+ , но мало кто её видел, а Гвидо (Ван Россум - прим. пер.) прокомментировал: «Я снимаю с себя ответственность за гугловский код API.» 10 000 строк кода - там же обязательно найдётся какая-нибудь дрянь вроде ШаурМэйла. Вот, например, класс Flow («поток»), от которого наследуют другие.

Class Flow(object): pass class Storage(object): def put(self, data): _abstract() def get(self): _abstract() def _abstract(): raise NotImplementedError

Он пустой. Но у него есть свой модуль, и каждый раз читая наследующий его класс, надо сходить, проверить тот файл и снова убедиться, что тот класс пуст. Кто-то глядел в будущее и решил: «Напишу-ка я 3 строчки кода сейчас, чтобы в будущем эти 3 строчки не менять.» И отнял время у всех, кто читает его библиотеку. Есть ещё класс Хранилище, (Storage) который почти ничего не делает. В нём правильно обрабатываются ошибки, используя стандартные исключения, но им делают алиасы, и опять же нужно ходить читать их код, чтобы выяснить, как это работает.

Чтобы внедрить OAuth2 мне понадобилась неделя. Пару дней заняло чтение десяти тысяч строк кода, после чего я стал искать другие библиотеки. Нашёл python-oauth2. Это вторая версия python-oauth, но она на самом деле не умеет работать с OAuth2, что не сразу удалось выяснить. Впрочем, эта библиотека немного лучше гугловской: только 540 строк и 15 классов.

Я переписал её ещё проще и назвал python-foauth2 . 135 строк кода и 3 класса, и то всё равно много, я не достаточно её отрефакторил. Вот один из этих трёх классов:

Class Error(Exception): pass

Срамота!

Жизнь

Последний пример. Все вы видели игру «Жизнь» Конвэя , даже если не знаете её имени. Есть клетчатое поле, каждый ход вы считаете для каждой клетки соседние, и в зависимости от них она будет либо живой, либо мёртвой. И получаются такие красивые устойчивые узоры, как планер: клетки впереди оживают, а сзади умирают, и планер как будто летит по полю.

Игра «жизнь» очень проста: поле и пара правил. Мы задаём эту задачу на собеседовании, потому что если вы не умеете такого - нам не о чем разговаривать. Многие сразу же говорят «Клетка - существительное. Класс надо.» Какие свойства в этом классе? Место, живая или нет, состояние в следующий ход, всё? Ещё есть соседи. Потом начинают описывать поле. Поле - это множество клеток, поэтому это сетка, у неё метод «подсчитать», который обсчитывает клетки внутри.

Class Cell(object): def __init__(self, x, y, alive=True): self.x = x self.y = y self.alive = alive self.next = None def neigbors(self): for i, j in itertools.product(range(-1, 2), repeat=2): if (i, j) != (0, 0): yield (self.x + i, self.y + j) class Board(object): def __init__(self): self.cells = {} # { (x, y): Cell() } def advance(self): for (x, y), cell in self.cells.items(): alive_neighbors = len(cell.neighbors) cell.next = (alive_neighbors == 3 or (alive_neighbors == 2 and cell.alive))

На этом месте надо сказать «стоп»: у нас есть класс Поле, в котором 2 метода: __init__ и «сделать ход». В нём одно свойство - словарь, значит со словарём и надо работать. Заметьте, что не надо хранить соседей точки, они уже и так есть в словаре. Живая точка или нет - это просто булево значение, поэтому будем хранить координаты только живых клеток. А раз в словаре хранятся только True, нужен не словарь а просто множество (set) координат. Наконец, новое состояние не нужно, можно просто заново создать список живых клеток.

Def neigbors(point): x, y = point for i, j in itertools.product(range(-1, 2), repeat=2): if any((i, j)): yield (x + i, y + j) def advance(board): newstate = set() recalc = board | set(itertools.chain(*map(neighbors, board))) for point in recalc: count = sum((neigh in board) for neigh in neighbors(point)) if count == 3 or (count == 2 and point in board): newstate.add(point) return newstate glider = set([(0, 0), (1, 0), (2, 0), (0, 1), (1, 2)]) for i in range(1000): glider = advance(glider) print glider

Получается очень простая, сжатая реализация игры. Двух классов тут не надо. Внизу - координаты планера, их вставляют в поле, и планер летит. Всё. Это полная реализация игры «жизнь».

Резюме

1. Если вы видите класс с двумя методами, включая __init__, это не класс.
2. Не создавайте новых исключений, если они не нужны (а они не нужны).
3. Упрощайте жёстче.

От переводчика: в комментариях я вижу, что многие восприняли доклад как полное отрицание ООП. Это ошибка. Пункт 1 из итогов чётко говорит, что такое не класс. Классы нужны, но суть доклада - в том, что не нужно ими злоупотреблять.

Оператор Описание Примеры
+ Сложение - Суммирует значения слева и справа от оператора

15 + 5 в результате будет 20
20 + -3 в результате будет 17
13.4 + 7 в результате будет 20.4

- Вычитание - Вычитает правый операнд из левого 15 - 5 в результате будет 10
20 - -3 в результате будет 23
13.4 - 7 в результате будет 6.4
* Умножение - Перемножает операнды 5 * 5 в результате будет 25
7 * 3.2 в результате будет 22.4
-3 * 12 в результате будет -36
/ Деление - Делит левый операнд на правый 15 / 5 в результате будет 3
5 / 2 в результате будет 2 (В Python 2.x версии при делении двух целых чисел результат будет целое число)
5.0 / 2 в результате будет 2.5 (Чтобы получить "правильный" результат хотя бы один операнд должен быть float)
% Деление по модулю - Делит левый операнд на правый и возвращает остаток. 6 % 2 в результате будет 0
7 % 2 в результате будет 1
13.2 % 5 в результате 3.2
** Возведение в степень - возводит левый операнд в степень правого 5 ** 2 в результате будет 25
2 ** 3 в результате будет 8
-3 ** 2 в результате будет -9
// Целочисленное деление - Деление в котором возвращается только целая часть результата. Часть после запятой отбрасывается. 12 // 5 в результате будет 2
4 // 3 в результате будет 1
25 // 6 в результате будет 4

Операторы сравнения в Python:

Оператор Описание Примеры
== Проверяет равны ли оба операнда. Если да, то условие становится истинным. 5 == 5 в результате будет True
True == False в результате будет False
"hello" == "hello" в результате будет True
!= 12 != 5 в результате будет True
False != False в результате будет False
"hi" != "Hi" в результате будет True
<> Проверяет равны ли оба операнда. Если нет, то условие становится истинным.

12 <> 5 в результате будет True. Похоже на оператор!=

> Проверяет больше ли значение левого операнда, чем значение правого. Если да, то условие становится истинным. 5 > 2 в результате будет True.
True > False в результате будет True.
"A" > "B" в результате будет False.
< Проверяет меньше ли значение левого операнда, чем значение правого. Если да, то условие становится истинным. 3 < 5 в результате будет True.
True < False в результате будет False.
"A" < "B" в результате будет True.
>= Проверяет больше или равно значение левого операнда, чем значение правого. Если да, то условие становится истинным. 1 >= 1 в результате будет True.
23 >= 3.2 в результате будет True.
"C" >= "D" в результате будет False.
<= Проверяет меньше или равно значение левого операнда, чем значение правого. Если да, то условие становится истинным. 4 <= 5 в результате будет True.
0 <= 0.0 в результате будет True.
-0.001 <= -36 в результате будет False.

Операторы присваивания в Python:

Оператор Описание Примеры
= Присваивает значение правого операнда левому. c = 23 присвоит переменной с значение 23
+= Прибавит значение правого операнда к левому и присвоит эту сумму левому операнду.

с = 5
а = 2
с += а равносильно: с = с + а. с будет равно 7

-= Отнимает значение правого операнда от левого и присваивает результат левому операнду.

с = 5
а = 2
с -= а равносильно: с = с - а. с будет равно 3

*= Умножает правый операнд с левым и присваивает результат левому операнду.

с = 5
а = 2
с *= а равносильно: с = с * а. c будет равно 10

/= Делит левый операнд на правый и присваивает результат левому операнду. с = 10
а = 2
с /= а равносильно: с = с / а. c будет равно 5
%= Делит по модулю операнды и присваивает результат левому. с = 5
а = 2
с %= а равносильно: с = с % а. c будет равно 1
**= Возводит в левый операнд в степень правого и присваивает результат левому операнду. с = 3
а = 2
с **= а равносильно: с = с ** а. c будет равно 9
//= Производит целочисленное деление левого операнда на правый и присваивает результат левому операнду. с = 11
а = 2
с //= а равносильно: с = с // а. c будет равно 5

Побитовые операторы в Python:

Побитовые операторы предназначены для работы с данными в битовом (двоичном) формате. Предположим, что у нас есть два числа a = 60; и b = 13. В двоичном формате они будут иметь следующий вид:

Оператор Описание Примеры
& Бинарный "И" оператор, копирует бит в результат только если бит присутствует в обоих операндах. (a & b) даст нам 12, которое в двоичном формате выглядит так 0000 1100
| Бинарный "ИЛИ" оператор копирует бит, если тот присутствует в хотя бы в одном операнде. (a | b) даст нам 61, в двоичном формате 0011 1101
^ Бинарный "Исключительное ИЛИ" оператор копирует бит только если бит присутствует в одном из операндов, но не в обоих сразу. (a ^ b) даст нам 49, в двоичном формате 0011 0001
~ Бинарный комплиментарный оператор. Является унарным (то есть ему нужен только один операнд) меняет биты на обратные, там где была единица становиться ноль и наоборот. (~a) даст в результате -61, в двоичном формате выглядит 1100 0011.
<< Побитовый сдвиг влево. Значение левого операнда "сдвигается" влево на количество бит указанных в правом операнде. a << 2 в результате даст 240, в двоичном формате 1111 0000
>> Побитовый сдвиг вправо. Значение левого операнда "сдвигается" вправо на количество бит указанных в правом операнде. a >> 2 даст 15, в двоичном формате 0000 1111

Логические операторы в Python:

Оператор Описание Примеры
and Логический оператор "И". Условие будет истинным если оба операнда истина.

True and True равно True.
True and False равно False.
False and True равно False.
False and False равно False.

or Логический оператор "ИЛИ". Если хотя бы один из операндов истинный, то и все выражение будет истинным. True or True равно True.
True or False равно True.
False or True равно True.
False or False равно False.
not Логический оператор "НЕ". Изменяет логическое значение операнда на противоположное. not True равно False.
not False равно True.

Операторы членства в Python:

В добавок к перечисленным операторам, в Python присутствуют, так называмые, операторы членства, предназначенные для проверки на наличие элемента в составных типах данных, таких, как строки, списки, кортежи или словари :

Операторы тождественности в Python:

Операторы тождественности сравнивают размещение двух объектов в памяти компьютера.

Приоритет операторов в Python

В следующей таблице описан приоритет выполнения операторов в Python от наивысшего (выполняется в первую очередь) до наинизшего.

Оператор Описание
** Возведение в степень
~ + - Комплиментарный оператор
* / % // Умножение, деление, деление по модулю, целочисленное деление.
+ - Сложение и вычитание.
>> << Побитовый сдвиг вправо и побитовый сдвиг влево.
& Бинарный "И".
^ | Бинарный "Исключительное ИЛИ" и бинарный "ИЛИ"
<= < > >= Операторы сравнения
<> == != Операторы равенства
= %= /= //= -= += *= **= Операторы присваивания
is is not Тождественные операторы
in not in Операторы членства
not or and Логические операторы

Обзор различий синтаксиса python2 и python3.

Print - функция

Оператор print был заменён функцией print(), с именованными аргументами для замены большей части синтаксиса старого оператора print. Примеры:

Python2 : print "The answer is" , 2 * 2 Python3 : print ("The answer is" , 2 * 2 ) Python2 : print x , # Запятая в конце подавляет перевод строки Python3 : print (x , end = " " ) # Добавляет пробел вместо перевода строки Python2 : print # Печатает перевод строки Python3 : print () # Нужно вызвать функцию! Python2 : print >> sys . stderr , "fatal error" Python3 : print ("fatal error" , file = sys . stderr ) Python2 : print (x , y ) # Печатает repr((x, y)) Python3 : print ((x , y )) # Не путать с print(x, y)!

Также вы можете настроить разделитель между элементами, например:

>>> print ("There are <" , 2 ** 32 , "> possibilities!" , sep = "" ) There are <4294967296> possibilities!

Функция print() не поддерживает особенность "программный пробел" старого оператора print. Например, в Python 2, print "A\n", "B" напечатает "A\nB\n"; но в Python 3, print("A\n", "B") напечатает "A\n B\n".

Отображения и итераторы вместо списков

Некоторые хорошо известные методы не возвращают в Python 3:

  • Методы словарей dict.keys(), dict.items() и dict.values() возвращают "отображения" вместо списков. Например, больше не работает: k = d.keys(); k.sort(). Используйте k = sorted(d).
  • Соответственно, методы dict.iterkeys(), dict.iteritems() и dict.itervalues() более не поддерживаются.
  • map() и filter() возвращают итераторы. Если вам действительно нужен список, быстрым исправлением станет list(map(...)), но часто лучшим исправлением будет использование генераторов списков (особенно когда оригинальный код использует лямбда-выражения), либо переписать код так, чтобы ему не нужен был список как таковой. Особенно сложно, что map() вызывает побочные эффекты функции; правильное преобразование заключается в использовании цикла (создание списка просто расточительно).
  • range() теперь ведёт себя как xrange(), но работает со значениями любого размера. xrange() больше не существует.
  • zip() возвращает итератор.

Операторы сравнения

Python 3 упростил правила для операторов сравнения:

Операторы сравнения (<, <=, >=, >) поднимают исключение TypeError, когда операнды не упорядочиваемы. Таким образом, выражения типа 1 < "", 0 > None или len <= len более не разрешены, и, например, None < None поднимает TypeError, а не возвращает False. Следствием является то, что сортировка списка с разными типами данных больше не имеет смысла - все элементы должны быть сравнимы друг с другом. Обратите внимание, что это не относится к операторам == и!=: объекты различных несравнимых типов всегда неравны друг другу.

builtin.sorted() и list.sort() больше не принимают аргумент cmp, обеспечивающий функцию сравнения. Вместо этого используйте аргумент key. Аргументы key и reverse теперь "keyword-only".

Функция cmp() должна рассматриваться как устаревшая, и специальный метод __cmp__() в Python 3 не поддерживается. Используйте __lt__() для сортировки, __eq__() с __hash__() для сравнения. (Если вам действительно нужна функциональность cmp(), вы можете использовать выражение (a > b) - (a < b) в качестве эквивалента для cmp(a, b).)

Целые числа

  • PEP 0237: long переименован в int.
  • PEP 0238: Выражение вида 1/2 возвращает float. Используйте 1//2 для отсечения дробной части. (Этот синтаксис существует с Python 2.2)
  • Константа sys.maxint была удалена, с тех пор, как более не существует предела значения целых чисел. Однако, sys.maxsize может быть использован как число, большее любого практического индекса списка или строки. sys.maxsize соответствует "естественному" размеру целого и, как правило, имеет такое же значение, как sys.maxint на той же платформе (при условии одних и те же параметров сборки).
  • repr() от длинного целого числа не включает более завершающий символ L, так что код, который безусловно отрезает этот символ, будет отрезать вместо этого последнюю цифру. (Используйте str() вместо этого.)
  • Восьмеричные литералы более не имеют формы вида 0720; используйте 0o720.

Текст, Unicode и 8-битные строки

Все, что вы знали о бинарных данных и Unicode, изменилось.

Python 3 использует понятия текста и (бинарных) данных вместо строк Unicode и 8-битных строк. Весь текст - Unicode; Однако кодированные Unicode строки представлены ​​в виде двоичных данных. Тип, используемый для хранения текста является , тип, используемый для хранения данных - . Самое большое различие с python 2.x является то, что любая попытка комбинировать текст и данные в Python 3.0 поднимает TypeError, в то время как если бы вы смешивали Unicode и 8-битные строки в Python 2.x, это будет работать, если 8-битная строка содержала только 7-битные (ASCII) символы, но вы получите UnicodeDecodeError, если она содержит не-ASCII символы. Такое поведение вызывало многочисленные скорбные лица на протяжении многих лет.

Как следствие этого изменения в философии, значительная часть кода, который использует Unicode, кодировки или бинарные данные, скорее всего, должна измениться. Это изменения к лучшему, так как в python 2.x были многочисленные ошибки, имеющие отношение к смешиванию закодированного и декодированного текста. Чтобы быть подготовленным к этому, в Python 2.x следует начать использовать Unicode для всего незакодированного текста, и str только для бинарных или закодированных данных. Затем инструмент 2to3 будет делать большую часть работы за вас.

Вы можете больше не использовать литерал u"..." для текста Unicode. Тем не менее, вы должны использовать литерал b"..." для бинарных данных.

Так как str и bytes не могут быть смешаны, вы всегда должны их явно преобразовывать. Используйте str.encode(), чтобы перейти от str к bytes и bytes.decode(), чтобы перейти от bytes к str. Вы также можете использовать bytes(s, encoding=...) и str(b, encoding=...), соответственно.

Как str, тип bytes неизменен. Существует отдельный изменяемый тип для двоичных данных, bytearray. Почти все функции, которые принимают bytes также принимают bytearray.

Все обратные косые черты в "сырых" строковых литералах интерпретируются буквально. Это означает, что "\U" и "\u" в сырых строках не рассматриваются особо. Например, r"\u20ac" это строка из 6 символов в Python 3.0, в то время как в 2.6, ur"\u20ac" был один символ "евро". (Конечно, это изменение влияет только на сырые строковые литералы).

Встроенный абстрактный тип basestring был удален. Используйте str вместо него. str и bytes не имеют достаточно общей функциональности, чтобы оправдать общий базовый класс. Инструмент 2to3 (см. ниже) заменяет каждое вхождение basestring на str.

PEP 3138: repr() для строки больше не экранирует символы, не входящие в набор ASCII. Однако, он по-прежнему экранирует управляющие символы

PEP 3120: Кодировка исходного кода по умолчанию теперь UTF-8.

PEP 3131: не-ASCII символы разрешены в идентификаторах. (Тем не менее, стандартная библиотека остается ASCII, за исключением имен авторов в комментариях.)

Модули StringIO и cStringIO удалены. Вместо этого, импортируйте модуль io и используйте io.StringIO или io.BytesIO для текста и данных соответственно.

Обзор изменений синтаксиса

Этот раздел дает краткий обзор каждого синтаксического изменения Python 3.0.

Новый синтаксис

PEP 3107: аннотации для аргументов функции и возвращаемых значений.

>>> def foo (a : "x" , b : 5 + 6 , c : list ) -> max (2 , 9 ): ... pass >>> foo . __annotations__ {"a": "x", "b": 11, "c": , "return": 9}

PEP 3102: Keyword-only аргументы.

PEP 3104: nonlocal. Переменная во внешней (но не глобальной) области видимости.

>>> def outer (): ... x = 1 ... def inner (): ... x = 2 ... print ("inner:" , x ) ... inner () ... print ("outer:" , x ) ... >>> outer () inner: 2 outer: 1 >>> def outer (): ... x = 1 ... def inner (): ... nonlocal x ... x = 2 ... print ("inner:" , x ) ... inner () ... print ("outer:" , x ) ... >>> outer () inner: 2 outer: 2

PEP 3132: Extended Iterable Unpacking

>>> (a , * rest , b ) = range (5 ) >>> a 0 >>> rest >>> b 4

Генераторы словарей: {k: v for k, v in stuff} (то же самое, что и dict(stuff))

Литералы множеств (например, {1, 2}). Заметьте, что {} - это пустой словарь. Используйте set() для пустых множеств. Генераторы множеств: {x for x in stuff}

Новые восьмеричные литералы, например 0o720, вместо старых (0720).

Новые двоичные литералы, например 0b1010. Новая встроенная функция, bin().

Изменённый синтаксис

PEP 3109 and PEP 3134: новый синтаксис выражения raise: raise ].

"as" и "with" зарезервированные слова.

"True" и "False" и "None" - зарезервированные слова.

Изменено "except exc, var" на "except exc as var".

PEP 3115: Новый синтаксис для метаклассов. Вместо:

class C : __metaclass__ = M ...

Вы должны использовать:

class C (metaclass = M ): ...

Переменная __metaclass__ более не поддерживается.

Генераторы списков больше не поддерживают синтаксическую форму [... for var in item1, item2, ...]. Используйте [... for var in (item1, item2, ...)].

Удаленный синтаксис

PEP 3113: распаковка кортежей в параметрах удалена. Вы больше не можете писать

def foo (a , (b , c )): ... def foo (a , b_c ): b , c = b_c ...

Удалены обратные кавычки (backtick). Используйте repr().

Удалено <>. Используйте!=.

exec - функция. Перестала быть зарезервированным словом.

from module import * запрещено использовать внутри функций.

Встроенные функции

PEP 3135: Новый super(). Теперь вы можете вызывать super() без аргументов и (при условии, что это метод экземпляра, определенный внутри определении класса) класс и экземпляр будут автоматически выбраны. С аргументами, поведение super() остается без изменений.

PEP 3111: raw_input() переименован в input(). Вместо input() в Python 2, вы можете использовать eval(input()).

Добавлена функция next(), вызывающая метод __next__() объекта.

Перемещен intern() в sys.intern().

Удалено: apply(). Вместо apply(f, args) используйте f(*args).

Удалено: callable(). Вместо callable(f) используйте hasattr(f, "__call__"). Функция operator.isCallable() также удалена.

Удалено: coerce().

Удалено: execfile(). Вместо execfile(fn) используйте exec(open(fn).read()).

Удалено: file. Используйте open().

Перемещено: reduce() в functools.reduce()

Перемещено: reload() в imp.reload().

Удалено: dict.has_key(). Используйте оператор in.







2024 © gtavrl.ru.