| ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
Глава 10. Недавние добавления в версии 1.1 Python - развивающийся язык. С тех пор, как этот семинар в последний раз был тщательно пересмотрен, несколько новых особенностей было добавлено к языку. Несмотря на то, что в идеале мне следовало бы переработать семинар, с тем, чтобы включить их в основной текст, нехватка времени в данный момент требует от меня воспользоваться более скромным подходом. В данной главе я кратко перечислю наиболее важные улучшения в языке, и, как Вам ими воспользоваться. 10.1 Последнее напечатанное выражение В интерактивном режиме, последнее напечатанное выражение присваивается переменной _ . Это значит, что когда Вы используете Python как настольный калькулятор, стало проще продолжать вычисления, например: >>> tax = 17.5 / 100 >>> price = 3.50 >>> price * tax 0.6125 >>> price + _ 4.1125 >>> round (_, 2) 4.11 >>> По причинам, которые слишком трудно объяснить, эта переменная реализована как встроенная (находится в модуле 10.2 Строковые литералы 10.2.1 Двойные кавычки Python может теперь использовать также и двойные кавычки для выделения строковых литералов, например: 10.2.2 Продолжение строковых литералов Строковые литералы могут охватывать несколько строк, путем записи символа новой строки и обратного слеша, например, hello = "Это довольно длинная строка, содержащая\n\ несколько строк текста, точно также, как Вы сделали бы в С.\n\ Пробелы в начале строки имеют значение.\n" print helloвыведет следующее: Это довольно длинная строка, содержащая несколько строк текста, точно также, как Вы сделали бы в С. Пробелы в начале строки имеют значение. 10.2.3 Строки в тройных кавычках В некоторых случаях, когда Вам нужно включить действительно длинную строку (например, содержащую несколько параграфов информативного текста), раздражает необходимость завершения каждой строки символами hello = """ Эта строка (стринг) ограничена тремя двойными кавычками (3 раза "). Новые строчки можно записывать без символов новой строки, хотя, \ все еще можно\n пользоваться всеми нормальными escape-последовательностями. Пробелы в начале строчки имеют значение. Если нужно включить три открывающие кавычки, Вам следует записать хотя бы один из них в виде escape-символа, например \""" . Эта строка (стринг) заканчивается на новой строке. """ Так же можно воспользоваться тремя одинарными кавычками, без всякой семантической разницы. 10.2.4 Сопоставление строковых литералов Один последний изворот: Вы можете сопоставить многочисленные строковые литералы. Два или более смежных строковых литерала (но не произвольные выражения!) разделенные только пробелом будут конкатенированы (без промежуточного пробела) в один строковый объект во время компилирования. Это делает возможным продолжение длинной строки (string) со следующей строки (line), без жертвования абзацным отступом или эффективностью, в отличие от использования оператора конкатенации строк 10.3 Оператор форматирования 10.3.1 Основное употребление Глава о форматировании вывода, в действительности, устарела: сейчас существует почти полный интерфейс форматирования в стиле С. Это сделано перегрузкой оператора взятия остатка (%) для левого операнда, являющегося строкой: >>> import math >>> print 'Значение PI приблизительно равно %5.3f.' % math.pi Значение PI приблизительно равно 3.142. >>> Если имеется более одного форматирования в строке, то передавайте тьюпл в качестве правого операнда: >>> table = {'Sjoerd':4127, 'Jack':4098, 'Dcab':8637678} >>> for name, phone in table.items(): ... print '%-10s ==> %10d' % (name, phone) ... Jack ==> 4098 Dcab ==> 8637678 Sjoerd ==> 4127 >>> Большая часть форматирования работает точно как в С и требует чтобы Вы передавали подходящий тип (иначе Вы получите исключение). Форматирование с помощью 10.3.2 Ссылка на переменные по именам Если у Вас действительно длинная форматируемая строка, которую не хочется разбивать на части, было бы хорошо если мы могли сослаться на форматируемые переменные по имени, а не по позиции. Это можно сделать используя расширение форматов С в следующем виде: >>> table = {'Sjoerd':4127, 'Jack':4098, 'Dcab':8637678} >>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table Jack: 4098; Sjoerd: 4127; Dcab: 8637678 >>> Это особенно полезно в комбинации с новой встроенной функцией 10.4 Необязательные аргументы функций Теперь возможно определение функций с переменным числом аргументов. Существует две формы, которые можно комбинировать. 10.4.1 Значение аргумента по умолчанию Самая полезная форма - определение значения по умолчанию для одного или более аргументов. Это создает функцию, которую можно вызывать с меньшим числом аргументов, чем определено, например: def ask_ok (prompt, retries=4, complaint=’Да или нет, пожалуйста!’): while 1: ok = raw_input (prompt) if ok in ( ‘д’, ‘да’ ) : return 1 if ok in ( ‘н’, ‘не’, ‘нет’ ) : return 0 retries = retries - 1 if retries < 0 : raise IOError, 'пользователь-отказник' print compliant Эту функцию можно вызвать либо так: ask_ok ( ‘Вы действительно хотите выйти ?’ ) либо вот так: ask_ok ( ‘Переписать файл ?’, 2 ) Значения по умолчанию оцениваются в точке определения функции, в области определения, так что, i = 5 def f ( arg=i ) : print arg i = 6 f() выведет 5 . 10.4.2 Списки произвольных аргументов Также возможно уточнить, что функцию можно будет вызывать с произвольным количеством аргументов. Эти аргументы будут "завернуты" в тьюпл. Переде переменным набором аргументов может встретиться ноль, или более нормальных аргументов: def fprintf ( file, format, *args ) : file.write ( format % args ) Эта особенность может быть использована с предыдущей: def but_is_it_useful ( required, optional=None, *remains ) : print "I don’t know" 10.5 Лямбда и инструменты функционального программирования 10.5.1 Лямбда формы По народному требованию, несколько особенностей, обычно находимых в языках функционального программирования и Lisp, были добавлены в Python. С помощью ключевого слова def make_incrementor (n) : return lambda x, incr = n : x + incr 10.5.2 Map, Reduce и Filter Три новые встроенные функции для последовательностей являются хорошими кандидатами для того, чтобы передать им лямбда формы. Map.map ( function, sequence ) вызывает функцию function (item) для каждого элемента (item) последовательности (sequence) и возвращает список полученных значений. Например, для вычисления нескольких кубов:
>>> map ( lambda x: x*x*x, range(1,11) ) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] >>> Можно передать более одной последовательности, тогда функция должна иметь столько же аргументов, сколько последовательностей, и она будет вызываться с соответствующим элементом из каждой последовательности (или Комбинируя два этих особых случая, мы видим, что >>> seq = range (8) >>> map ( None, seq, map ( lambda x : x*x , seq ) ) [(0,0), (1,1), (2,4), (3,9), (4,16), (5,25), (6,36), (7,49)] >>> Filter.filter ( function, sequence ) возвращает последовательность (такого же типа, если возможно), содержащую те элементы item последовательности sequence , для которых функция function (item) - истина. Например, для вычисления некоторых простых чисел:
>>> filter ( lambda x: x%2 != 0 and x%3 != 0 , range (2, 25) ) [5, 7, 11, 13, 17, 19, 23] >>> Reduce.reduce (function, sequence) возвращает простое значение, составленное путем вызова функции function сначала с первыми двумя элементами последовательности sequence , с результатом и следующим элементом, и так далее. Например, для вычисления суммы чисел от 1 до 10:
>>> reduce (lambda x, y: x+y, range(1,11)) 55 >>> Если в последовательности только один элемент, возвращается это значение; если последовательность пуста, возникает исключение. Можно передать и третий аргумент, для установки начального значения. В этом случае, начальное значение возвращается для пустой последовательности, и функция сначала применяется к стартовому значению и первому элементу последовательности, а затем к результату и следующему элементу, и так далее. Например: >>> def sum (seq): ... return reduce (lambda x, y: x+y, seq, 0) ... >>> sum (range (1, 11)) 55 >>> sum ([]) 0 >>> 10.6 Продолжение строк без обратного слеша Хотя основным механизмом продолжения строки источника в следующей физической строке остается помещение обратного слеша в конце строки, выражения внутри парных скобок, ( или квадратных скобок или фигурных скобок) теперь могут быть продолжены так же без использования слеша. Это особенно полезно для вызовов функций со многими аргументами и для инициализации больших таблиц. Например: month_names = [‘Январь’, ‘Февраль’, ‘Март’, ‘Апрель’, ‘Май’, ‘Июнь’, ‘Июль’, ‘Август’, ‘Сентябрь’, ‘Октябрь’, ‘Ноябрь’, ‘Декабрь’] и CopyInternalHyperLinks (self.context.hyperlinks, copy.context.hyperlinks, uidremap) 10.7 Регулярные выражения Хотя printf-стиль С форматирования вывода, встроенный в Python, достаточен для большинства случаев форматирования вывода, scanf-стиль С форматированного ввода не очень полезен. Вместо scanf-стиля ввода, Python предлагает Emacs-стиль регулярных выражений, как мощный механизм ввода и сканирования. Для полного описания читайте соответствующую секцию в "Справочнике библиотеки Python". 10.8 Обобщенные словари Ключи словарей больше не ограничены строками - они могут быть любым немутируемым базовым типом, включая строки, числа, тьюплы, и экземпляры классов. (Списки и словари не приемлемы в качестве ключей словаря, во избежание проблем, когда объект, используемый как ключ, модифицируется.) Словари теперь имею два новых метода: >>> d = { 100:’сто’, 1000:’тысяча’, 10:’десять’ } >>> d.keys() {100, 10, 1000] >>> d.values() [‘сто’, ‘десять’, ‘тысяча’] >>> d.items() [(100, ‘сто’), (10, ‘десять’), (1000, ‘тысяча’)] >>> 10.9 Разнообразные новые встроенные функции Функция Функция Функция Функция Функция Примечание: 10.10 Пункт else для оператора try Оператор for arg in sys.argv: try: f = open (arg, ‘r’) except IOError: print ‘Не могу открыть’, arg else: print arg, ‘содержит’, len ( f.readlines() ), ‘строк’ f.close() 10.11 Новые особенности классов в версии 1.1 С классами произошли некоторые изменения: механизм перегрузки операторов стал более гибким, предоставляющим улучшенную поддержку для нечислового использования операторов (включая вызов объекта, как будто бы это функция), и можно запереть доступ к атрибутам. 10.11.1 Новая перегрузка операторов Больше нет необходимости принуждать обе стороны оператора быть одного и того же класса или типа. Класс может еще предоставить метод В порядке создания возможности реализации двоичных операторов у которых правая часть - экземпляр класса, а левая часть - нет, без использования принуждения, версии правых частей двоичных операторов могут быть определены. При этом В качестве примера здесь приводится очень простой класс, представляющий время ( import time class Time: def __init__ (self, seconds): self.seconds = seconds def __repr__ (self): return time.ctime (self.seconds) def __add__ (self, x): return Time(self.seconds + x) __radd__ = __add__ # поддержка для x + t def __sub__ (self, x): if hasattr (x, ‘seconds’): # проверка того, что x - это Time return self.seconds - x.seconds else: return self.seconds - x now = Time (time.time()) tomorrow = 24*3600 + now yesterday = now - today print tomorrow - yesterday # выведет 172800 10.11.2 Доступ к закрытому атрибуту Теперь Вы можете определить три новых "волшебных" метода: Метод Методы Для примера здесь приводится близкий к универсальному класс "Wrapper", который передает доступ ко всем своим атрибутам другому объекту. Обратите внимание на то, как метод class Wrapper: def __init__(self, wrapper): self.__dict__[‘wrapper’] = wrapped def __getattr__(self, name): return getattr(self.wrapped, name) def __setattr__(self, name, value): setattr(self.wrapped, name, value) def __delattr__(self, name): delattr(self.wrapped, name) import sys f = Wrapper (sys.stdout) f.write (‘hello world\n’) # выводит ‘hello world’ А вот простой пример для from math import pi class Circle: def __init__(self, radius): self.radius = radius def __getattr__(self, name): if name==’circumference’: return 2*pi*self.radius if name==’diameter’: return 2*self.radius if name==’area’: return pi*pow(self.radius, 2) raise AttributeError, name 10.11.3 Вызов экземпляра класса Если класс определяет метод class PresetSomeArguments: def __init__(self, func, *args): self.func, self.args = func, args def __call__(self, *args): return apply(self.func, self.args + args) f = PresetSomeArguments (pow, 2) # f(i) подсчитывает степени числа z for i in range(10): print f(i), # печатает 1 2 4 8 16 32 64 128 256 512 print # переход на новую строку [Назад][Содержание][Вперед] |
|
| ||||||||||||||||
|