Що нового в Python 2.1

Автор

A.M. Kuchling

вступ

У цій статті пояснюються нові функції Python 2.1. Хоча у версії 2.1 не так багато змін, як у Python 2.0, все ж є деякі приємні сюрпризи. 2.1 є першим випуском, який керується використанням Python Enhancement Proposals або PEP, тому більшість значних змін супроводжуються PEP, які надають більш повну документацію та обґрунтування зміни. Ця стаття не намагається повністю задокументувати нові функції, а просто надає огляд нових функцій для програмістів Python. Зверніться до документації Python 2.1 або до конкретного PEP, щоб дізнатися більше про будь-яку нову функцію, яка вас особливо цікавить.

Одна з нещодавніх цілей команди розробників Python полягала в тому, щоб пришвидшити темп випуску нових випусків, причому новий випуск виходить кожні 6-9 місяців. 2.1 є першим випуском, який вийшов таким швидким темпом, з першою альфа-версією, яка з’явилася в січні, через 3 місяці після виходу остаточної версії 2.0.

Остаточний випуск Python 2.1 був зроблений 17 квітня 2001 року.

PEP 227: Вкладені області

Найбільша зміна в Python 2.1 стосується правил визначення області видимості Python. У Python 2.0 у будь-який момент часу існує щонайбільше три простори імен, які використовуються для пошуку імен змінних: локальний, на рівні модуля та вбудований простір імен. Це часто дивувало людей, оскільки не відповідало їхнім інтуїтивним очікуванням. Наприклад, визначення вкладеної рекурсивної функції не працює:

def f():
    ...
    def g(value):
        ...
        return g(value-1) + 1
    ...

Функція g() завжди викличе виняток NameError, оскільки прив’язка імені g не знаходиться ні в його локальному просторі імен, ні в просторі імен на рівні модуля. Це не є великою проблемою на практиці (як часто ви рекурсивно визначаєте такі внутрішні функції?), але це також робило використання виразу lambda більш незграбним, і це було проблемою на практиці. У коді, який використовує lambda, ви часто можете знайти локальні змінні, які копіюються, передаючи їх як стандартні значення аргументів.

def find(self, name):
    "Return list of any entries equal to 'name'"
    L = filter(lambda x, name=name: x == name,
               self.list_attribute)
    return L

У результаті цього значно погіршується читабельність коду Python, написаного у сильно функціональному стилі.

Найсуттєвіша зміна Python 2.1 полягає в тому, що для вирішення цієї проблеми до мови додано статичне визначення області видимості. Як перший ефект, аргумент за замовчуванням name=name тепер непотрібний у наведеному вище прикладі. Простіше кажучи, коли заданому імені змінної не присвоєно значення у функції (за допомогою призначення або операторів def, class або import), посилання на змінна буде шукатися в локальному просторі імен охоплюючої області. Більш детальне пояснення правил і опис реалізації можна знайти в PEP.

Ця зміна може спричинити деякі проблеми сумісності для коду, де те саме ім’я змінної використовується як на рівні модуля, так і як локальна змінна у функції, яка містить додаткові визначення функцій. Це здається малоймовірним, оскільки такий код було б досить заплутаним для читання.

Одним із побічних ефектів змін є те, що оператори from module import * і exec були зроблені незаконними в межах функції за певних умов. У довідковому посібнику Python весь час говорилося, що from module import * допустимо лише на верхньому рівні модуля, але інтерпретатор CPython ніколи раніше не виконував цього. Як частина реалізації вкладених областей, компілятор, який перетворює джерело Python на байт-коди, має згенерувати інший код для доступу до змінних у місткій області. from module import * і exec не дозволяють компілятору це зрозуміти, оскільки вони додають імена до локального простору імен, які невідомі під час компіляції. Таким чином, якщо функція містить визначення функції або lambda вирази з вільними змінними, компілятор позначить це, викликавши виняток SyntaxError.

Щоб зробити попереднє пояснення трохи зрозумілішим, ось приклад:

x = 1
def f():
    # The next line is a syntax error
    exec 'x=2'
    def g():
        return x

Рядок 4, що містить інструкцію exec, є синтаксичною помилкою, оскільки exec визначатиме нову локальну змінну з назвою x, до значення якої має отримати доступ g().

Це не повинно бути великим обмеженням, оскільки exec рідко використовується в більшості коду Python (і коли він використовується, це часто свідчить про поганий дизайн).

Занепокоєння щодо сумісності призвело до поступового впровадження вкладених областей; у Python 2.1 вони не ввімкнені за замовчуванням, але їх можна ввімкнути в модулі за допомогою оператора future, як описано в PEP 236. (Див. наступний розділ для подальшого обговорення PEP 236.) У Python 2.2 вкладені області стануть типовими, і не буде можливості їх вимкнути, але користувачі матимуть весь час життя 2.1, щоб усунути будь-яку поломку внаслідок їх введення.

Дивись також

PEP 227 - Статично вкладені області

Написаний і реалізований Джеремі Гілтоном.

PEP 236: директиви __future__

Реакцією на вкладені області було широко поширене занепокоєння щодо небезпеки злому коду з випуском 2.1, і воно було досить сильним, щоб змусити Pythoneers застосувати більш консервативний підхід. Цей підхід полягає у введенні угоди про ввімкнення додаткової функціональності у випуску N, який стане обов’язковим у випуску N+1.

Синтаксис використовує оператор from...import із використанням зарезервованої назви модуля __future__. Вкладені області можна активувати наступним оператором:

from __future__ import nested_scopes

Хоча це виглядає як звичайний оператор import, це не так; існують суворі правила щодо того, де можна розмістити таку майбутню заяву. Вони можуть бути лише у верхній частині модуля та повинні передувати будь-якому коду Python або звичайним операторам import. Це тому, що такі оператори можуть впливати на те, як компілятор байт-коду Python аналізує код і генерує байт-код, тому вони повинні передувати будь-якому оператору, який призведе до створення байт-кодів.

Дивись також

PEP 236 - Назад у __future__

Написаний Тімом Пітерсом, а в основному реалізований Джеремі Гілтоном.

PEP 207: багаті порівняння

У попередніх версіях підтримка Python для реалізації порівнянь визначених користувачем класів і типів розширень була досить простою. Класи можуть реалізовувати метод __cmp__(), який отримує два екземпляри класу, і може повертати лише 0, якщо вони рівні, або +1 або -1, якщо вони не були; метод не міг викликати виняток або повертати нічого, окрім логічного значення. Користувачі числового Python часто вважали цю модель занадто слабкою та обмежувальною, тому що в програмах для обробки чисел, для яких використовується числовий Python, було б корисніше мати можливість виконувати поелементне порівняння двох матриць, повертаючи матрицю, що містить результати дане порівняння для кожного елемента. Якщо дві матриці мають різні розміри, тоді порівняння має мати можливість викликати виняток, щоб сигналізувати про помилку.

У Python 2.1 для підтримки цієї потреби було додано розширені порівняння. Класи Python тепер можуть окремо перевантажувати кожну з операцій <, <=, >, >=, == і !=. Назви нових магічних методів:

Операція

Назва методу

<

__lt__()

<=

__le__()

>

__gt__()

>=

__ge__()

==

__eq__()

!=

__ne__()

(Чарівні методи названо на честь відповідних операторів Fortran .LT.. .LE. тощо. Цифрові програмісти майже напевно добре знайомі з цими назвами та легко їх запам’ятають.)

Кожен із цих чарівних методів має форму method(self, other), де self буде об’єктом ліворуч від оператора, а other буде об’єктом з правого боку. Наприклад, вираз A < B призведе до виклику A.__lt__(B).

Кожен із цих магічних методів може повернути будь-що: логічне значення, матрицю, список або будь-який інший об’єкт Python. Крім того, вони можуть викликати виняток, якщо порівняння є неможливим, непослідовним або іншим чином безглуздим.

Вбудована функція cmp(A,B) може використовувати механізм розширеного порівняння та тепер приймає необов’язковий аргумент, який визначає, яку операцію порівняння використовувати; це надається як один із рядків " <", "<=", "> ", ">=", "==" або "!=". Якщо викликати без додаткового третього аргументу, cmp() поверне лише -1, 0 або +1, як у попередніх версіях Python; інакше він викличе відповідний метод і може повернути будь-який об’єкт Python.

Є також відповідні зміни, які цікавлять програмістів на C; є новий слот tp_richcmp в об’єктах типу та API для виконання певного розширеного порівняння. Я не буду тут розповідати про C API, але відсилаю вас до PEP 207 або до документації C API 2.1, щоб отримати повний список пов’язаних функцій.

Дивись також

PEP 207 - багаті порівняння

Написаний Гвідо ван Россумом, значною мірою заснований на попередніх роботах Девіда Ашера та реалізований Гвідо ван Россумом.

PEP 230: Попередження

За 10 років існування Python накопичив певну кількість застарілих модулів і функцій. Важко визначити, коли функцію безпечно видалити, оскільки неможливо дізнатися, скільки коду її використовує — можливо, жодна програма не залежить від функції, або, можливо, багато хто залежить від цієї функції. Щоб уможливити видалення старих функцій у більш структурований спосіб, було додано рамку попереджень. Коли розробники Python хочуть позбутися функції, це спочатку викличе попередження в наступній версії Python. Наступна версія Python може відмовитися від цієї функції, і користувачі матимуть повний цикл випуску, щоб усунути використання старої функції.

Python 2.1 додає структуру попереджень для використання в цій схемі. Він додає модуль warnings, який надає функції для видачі попереджень і для фільтрації попереджень, які ви не бажаєте відображати. Сторонні модулі також можуть використовувати цю структуру, щоб відмовитися від старих функцій, які вони більше не хочуть підтримувати.

Наприклад, у Python 2.1 модуль regex є застарілим, тому його імпортування призводить до друку попередження:

>>> import regex
__main__:1: DeprecationWarning: the regex module
         is deprecated; please use the re module
>>>

Попередження можна видати, викликавши функцію warnings.warn():

warnings.warn("feature X no longer supported")

Перший параметр – це попереджувальне повідомлення; додаткові необов’язкові параметри можуть використовуватися для визначення певної категорії попередження.

Можна додати фільтри, щоб вимкнути певні попередження; шаблон регулярного виразу можна застосувати до повідомлення або до назви модуля, щоб придушити попередження. Наприклад, у вас може бути програма, яка використовує модуль regex, і ви не хочете витрачати час на перетворення її на використання модуля re прямо зараз. Попередження можна придушити викликом

import warnings
warnings.filterwarnings(action = 'ignore',
                        message='.*regex module is deprecated',
                        category=DeprecationWarning,
                        module = '__main__')

Це додає фільтр, який застосовуватиметься лише до попереджень класу DeprecationWarning, ініційованих у модулі __main__, і застосовує регулярний вираз, щоб відповідати лише повідомленню про наявність модуля regex не підтримується, і такі попередження ігноруватимуться. Попередження також можна друкувати лише один раз, друкувати кожного разу, коли виконується код-порушник, або перетворювати на винятки, які призведуть до зупинки програми (звичайно, якщо винятки не перехоплюються звичайним способом).

До API C Python також додано функції для видачі попереджень; подробиці зверніться до PEP 230 або до документації Python API.

Дивись також

PEP 5 - Рекомендації щодо розвитку мови

Написав Пол Прескод, щоб визначити процедури, яких слід дотримуватися під час видалення старих функцій з Python. Політика, описана в цьому PEP, не була офіційно прийнята, але остаточна політика, ймовірно, не надто відрізнятиметься від пропозиції Prescod.

PEP 230 - Рамка попереджень

Написаний і реалізований Гвідо ван Россумом.

PEP 229: Нова система побудови

Під час компіляції Python користувач мав зайти та відредагувати файл Modules/Setup, щоб увімкнути різні додаткові модулі; стандартний набір відносно малий і обмежений модулями, які компілюються на більшості платформ Unix. Це означає, що на платформах Unix із набагато більшою кількістю можливостей, особливо Linux, встановлення Python часто не містять усіх корисних модулів, які могли б.

Python 2.0 додав Distutils, набір модулів для розповсюдження та встановлення розширень. У Python 2.1 Distutils використовуються для компіляції більшої частини стандартної бібліотеки модулів розширення, автоматично визначаючи, які з них підтримуються на поточній машині. Є надія, що це зробить інсталяцію Python простішою та функціональнішою.

Замість того, щоб редагувати файл Modules/Setup, щоб увімкнути модулі, сценарій setup.py у верхньому каталозі дистрибутива вихідного коду Python запускається під час збирання та намагається виявити які модулі можна ввімкнути, перевіривши модулі та файли заголовків у системі. Якщо модуль налаштовано в Modules/Setup, сценарій setup.py не намагатиметься скомпілювати цей модуль і звернеться до вмісту файлу Modules/Setup. Це надає спосіб визначити будь-які дивні прапори командного рядка або бібліотеки, які потрібні для певної платформи.

В іншій далекосяжній зміні механізму збірки Ніл Шеменауер змінив структуру так, що Python тепер використовує єдиний make-файл, який не є рекурсивним, замість make-файлів у верхньому каталозі та в кожному Підкаталоги з Python/, Parser/, Objects/ і Modules/. Це робить створення Python швидшим, а також робить злам Makefiles зрозумілішим і простішим.

Дивись також

PEP 229 - Використання Distutils для створення Python

Написана та реалізована А.М. Кухлінг.

PEP 205: Слабкі посилання

Слабкі посилання, доступні через модуль weakref, є другорядним, але корисним новим типом даних у наборі інструментів програміста Python.

Зберігання посилання на об’єкт (скажімо, у словнику чи списку) має побічним ефектом збереження цього об’єкта назавжди. Є кілька конкретних випадків, коли така поведінка є небажаною, найпоширенішим є кешування об’єктів, а іншим є циклічні посилання в структурах даних, таких як дерева.

Наприклад, розглянемо функцію запам’ятовування, яка кешує результати іншої функції f(x), зберігаючи аргумент функції та її результат у словнику:

_cache = {}
def memoize(x):
    if _cache.has_key(x):
        return _cache[x]

    retval = f(x)

    # Cache the returned object
    _cache[x] = retval

    return retval

Ця версія працює для простих речей, таких як цілі числа, але вона має побічний ефект; словник _cache містить посилання на значення, що повертаються, тому їх ніколи не буде звільнено, доки процес Python не завершить роботу та не очистить. Це не дуже помітно для цілих чисел, але якщо f() повертає об’єкт або структуру даних, яка займає багато пам’яті, це може бути проблемою.

Слабкі посилання забезпечують спосіб реалізації кешу, який не зберігатиме об’єкти живими понад час. Якщо об’єкт доступний лише через слабкі посилання, об’єкт буде звільнено, а слабкі посилання тепер вказуватимуть, що об’єкт, на який він посилався, більше не існує. Слабке посилання на об’єкт obj створюється шляхом виклику wr = weakref.ref(obj). Об’єкт, на який посилається, повертається шляхом виклику слабкого посилання, як якщо б це була функція: wr(). Він поверне об’єкт, на який посилається, або «Немає», якщо об’єкт більше не існує.

Це дає змогу написати функцію memoize(), кеш якої не зберігає живі об’єкти, зберігаючи слабкі посилання в кеші.

_cache = {}
def memoize(x):
    if _cache.has_key(x):
        obj = _cache[x]()
        # If weak reference object still exists,
        # return it
        if obj is not None: return obj

    retval = f(x)

    # Cache a weak reference
    _cache[x] = weakref.ref(retval)

    return retval

Модуль weakref також дозволяє створювати проксі-об’єкти, які поводяться як слабкі посилання — об’єкт, на який посилаються лише проксі-об’єкти, звільняється, але замість того, щоб вимагати явного виклику для отримання об’єкта, проксі прозоро пересилає всі операції до об’єкта, поки об’єкт все ще існує. Якщо об’єкт звільнено, спроба використати проксі призведе до виникнення винятку weakref.ReferenceError.

proxy = weakref.proxy(obj)
proxy.attr   # Equivalent to obj.attr
proxy.meth() # Equivalent to obj.meth()
del obj
proxy.attr   # raises weakref.ReferenceError

Дивись також

PEP 205 - Слабкі посилання

Написаний і реалізований Фредом Л. Дрейком-молодшим.

PEP 232: Атрибути функцій

In Python 2.1, functions can now have arbitrary information attached to them. People were often using docstrings to hold information about functions and methods, because the __doc__ attribute was the only way of attaching any information to a function. For example, in the Zope Web application server, functions are marked as safe for public access by having a docstring, and in John Aycock’s SPARK parsing framework, docstrings hold parts of the BNF grammar to be parsed. This overloading is unfortunate, since docstrings are really intended to hold a function’s documentation; for example, it means you can’t properly document functions intended for private use in Zope.

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

def f(): pass

f.publish = 1
f.secure = 1
f.grammar = "A ::= B (C D)*"

Доступ до словника, що містить атрибути, можна отримати як __dict__ функції. На відміну від атрибута __dict__ екземплярів класу, у функціях ви фактично можете призначити новий словник __dict__, хоча нове значення обмежене звичайним словником Python; Ви не можете бути хитрими і встановити для нього екземпляр UserDict або будь-який інший випадковий об’єкт, який поводиться як відображення.

Дивись також

PEP 232 - Атрибути функції

Написав і реалізував Баррі Варшау.

PEP 235: Імпорт модулів на платформах без урахування регістру

Деякі операційні системи мають файлові системи, які не чутливі до регістру, MacOS і Windows є основними прикладами; у цих системах неможливо розрізнити назви файлів FILE.PY і file.py, навіть якщо вони зберігають назву файлу в оригінальному регістрі (вони також зберігають регістр).

У Python 2.1 оператор import працюватиме для імітації чутливості до регістру на платформах, які не чутливі до регістру. Тепер Python буде шукати перший збіг з урахуванням регістру за замовчуванням, викликаючи ImportError, якщо такий файл не знайдено, тому import file не імпортуватиме модуль з назвою FILE.PY. Зіставлення без урахування регістру можна запитати, встановивши змінну середовища PYTHONCASEOK перед запуском інтерпретатора Python.

PEP 217: інтерактивний дисплей

Під час використання інтерпретатора Python в інтерактивному режимі вихід команд відображається за допомогою вбудованої функції repr(). У Python 2.1 змінна sys.displayhook() може бути встановлена на викликаний об’єкт, який буде викликатися замість repr(). Наприклад, ви можете встановити для нього спеціальну функцію красивого друку:

>>> # Create a recursive data structure
... L = [1,2,3]
>>> L.append(L)
>>> L # Show Python's default output
[1, 2, 3, [...]]
>>> # Use pprint.pprint() as the display function
... import sys, pprint
>>> sys.displayhook = pprint.pprint
>>> L
[1, 2, 3,  <Recursion on list with id=135143996>]
>>>

Дивись також

PEP 217 - Дисплей Хук для інтерактивного використання

Написав і реалізував Моше Задка.

PEP 208: Нова модель примусу

Спосіб виконання числового приведення на рівні C було значно змінено. Це вплине лише на авторів розширень C для Python, надаючи їм більше гнучкості в написанні типів розширень, які підтримують числові операції.

Типи розширень тепер можуть установлювати прапор типу Py_TPFLAGS_CHECKTYPES у своїй структурі PyTypeObject, щоб вказати, що вони підтримують нову модель примусу. У таких типах розширень функції числового слота більше не можуть припускати, що їм будуть передані два аргументи одного типу; натомість їм можуть бути передані два аргументи різних типів, і потім вони можуть виконувати власний внутрішній примус. Якщо функції слота передано тип, який вона не може обробити, вона може вказувати на помилку, повертаючи посилання на одноэлементне значення Py_NotImplemented. Потім буде випробувано числові функції іншого типу, і, можливо, вони зможуть впоратися з операцією; якщо інший тип також повертає Py_NotImplemented, тоді буде викликано TypeError. Числові методи, написані на Python, також можуть повертати Py_NotImplemented, змушуючи інтерпретатор діяти так, ніби метод не існує (можливо, викликаючи TypeError, можливо, намагаючись використовувати числові методи іншого об’єкта).

Дивись також

PEP 208 - Переробка моделі примусу

Написаний і реалізований Нілом Шеменауером, значною мірою заснований на попередніх роботах Марка-Андре Лембурга. Прочитайте це, щоб зрозуміти тонкощі того, як числові операції тепер оброблятимуться на рівні C.

PEP 241: Метадані в пакетах Python

A common complaint from Python users is that there’s no single catalog of all the Python modules in existence. T. Middleton’s Vaults of Parnassus at http://www.vex.net/parnassus/ are the largest catalog of Python modules, but registering software at the Vaults is optional, and many people don’t bother.

Як перший невеликий крок до вирішення проблеми, програмне забезпечення Python, упаковане за допомогою команди Distutils sdist, міститиме файл під назвою PKG-INFO, що містить інформацію про пакунок, як-от його назву, версію та автора. (метадані, в термінології каталогізації). PEP 241 містить повний список полів, які можуть міститися у файлі PKG-INFO. Оскільки люди почали пакувати своє програмне забезпечення за допомогою Python 2.1, все більше і більше пакетів включатимуть метадані, що дає змогу створювати автоматизовані системи каталогізації та експериментувати з ними. З отриманим досвідом, можливо, стане можливим створити справді хороший каталог, а потім створити його підтримку в Python 2.2. Наприклад, команди Distutils sdist і bdist_* можуть підтримувати опцію upload, яка автоматично завантажуватиме ваш пакет на сервер каталогу.

Ви можете почати створювати пакунки, що містять PKG-INFO, навіть якщо ви не використовуєте Python 2.1, оскільки для користувачів попередніх версій Python буде створено новий випуск Distutils. Версія 1.0.2 Distutils містить зміни, описані в PEP 241, а також різні виправлення помилок і вдосконалення. Він буде доступний у Distutils SIG за адресою https://www.python.org/community/sigs/current/distutils-sig/.

Дивись також

PEP 241 - метадані для програмних пакетів Python

Написана та реалізована А.М. Кухлінг.

PEP 243 - Механізм завантаження сховища модулів

Цей проект PEP, написаний Шоном Райфшнайдером, описує запропонований механізм для завантаження пакетів Python на центральний сервер.

Нові та вдосконалені модулі

  • Ka-Ping Yee вніс два нові модулі: inspect.py, модуль для отримання інформації про живий код Python, і pydoc.py, модуль для інтерактивного перетворення рядків документів у HTML або текст. Як бонус, Tools/scripts/pydoc, який тепер автоматично встановлюється, використовує pydoc.py для відображення документації з назвою модуля, пакета чи класу Python. Наприклад, pydoc xml.dom відображає наступне:

    Python Library Documentation: package xml.dom in xml
    
    NAME
        xml.dom - W3C Document Object Model implementation for Python.
    
    FILE
        /usr/local/lib/python2.1/xml/dom/__init__.pyc
    
    DESCRIPTION
        The Python mapping of the Document Object Model is documented in the
        Python Library Reference in the section on the xml.dom package.
    
        This package contains the following modules:
          ...
    

    pydoc також містить інтерактивний довідковий браузер на основі Tk. pydoc швидко викликає звикання; Спробуй!

  • До стандартної бібліотеки додано два різних модулі для модульного тестування. Модуль doctest, наданий Тімом Пітерсом, надає структуру тестування, засновану на виконанні вбудованих прикладів у рядки документів і порівняння результатів із очікуваним результатом. PyUnit, наданий Стівом Перселлом, — це фреймворк модульного тестування, натхненний JUnit, який, у свою чергу, був адаптацією фреймворку тестування Smalltalk Кента Бека. Перегляньте http://pyunit.sourceforge.net/ для отримання додаткової інформації про PyUnit.

  • Модуль difflib містить клас SequenceMatcher, який порівнює дві послідовності та обчислює зміни, необхідні для перетворення однієї послідовності в іншу. Наприклад, цей модуль можна використовувати для написання інструменту, подібного до програми Unix diff, і фактично приклад програми Tools/scripts/ndiff.py демонструє, як написати такий сценарій.

  • curses.panel, оболонку для бібліотеки панелей, частину ncurses і проклять SYSV, надав Томас Геллекум. Бібліотека панелей надає вікна з додатковою функцією глибини. Вікна можна переміщувати вище або нижче в порядку глибини, а бібліотека панелей визначає, де панелі перекриваються та які розділи видно.

  • Пакет PyXML пройшов кілька випусків, починаючи з Python 2.0, і Python 2.1 містить оновлену версію пакета xml. Деякі з важливих змін включають підтримку Expat 1.2 і пізніших версій, здатність синтаксичних аналізаторів Expat обробляти файли в будь-якому кодуванні, що підтримується Python, а також різні виправлення помилок для SAX, DOM і модуля minidom.

  • Ping також вніс ще один хук для обробки неперехоплених винятків. sys.excepthook() можна встановити на об’єкт, що викликається. Якщо виняток не перехоплюється жодним блоком tryexcept, виняток буде передано до sys.excepthook(), який потім може робити все, що забажає. На Дев’ятій конференції Python Ping продемонстрував застосування для цього хука: друк розширеного трасування, яке не лише містить перелік фреймів стека, але також перераховує аргументи функції та локальні змінні для кожного фрейму.

  • Різні функції в модулі time, такі як asctime() і localtime(), вимагають аргументу з плаваючою комою, що містить час у секундах від епохи. Найпоширенішим використанням цих функцій є робота з поточним часом, тому аргумент із плаваючою комою став необов’язковим; якщо значення не вказано, буде використано поточний час. Наприклад, записи у файлі журналу зазвичай потребують рядка, що містить поточний час; у Python 2.1 можна використовувати time.asctime() замість довшого time.asctime(time.localtime(time.time())), який був необхідний раніше.

    Цю зміну запропонував і впровадив Томас Воутерс.

  • Модуль ftplib тепер за замовчуванням отримує файли в пасивному режимі, оскільки пасивний режим, швидше за все, працюватиме за брандмауером. Цей запит надійшов від системи відстеження помилок Debian, оскільки інші пакунки Debian використовують ftplib для отримання файлів, а потім не працюють через брандмауер. Вважається малоймовірним, що це спричинить комусь проблеми, оскільки Netscape за замовчуванням використовує пасивний режим, і мало хто скаржиться, але якщо пасивний режим не підходить для вашої програми чи налаштувань мережі, викличте set_pasv(0) для об’єктів FTP, щоб вимкнути пасивний режим.

  • До модуля socket, наданого Грантом Едвардсом, додано підтримку необробленого доступу до сокетів.

  • Модуль pstats тепер містить простий інтерактивний браузер статистики для відображення профілів часу для програм Python, викликаних, коли модуль запускається як сценарій. Надав Ерік С. Реймонд.

  • Додано нову залежну від реалізації функцію sys._getframe([depth]) для повернення заданого об’єкта кадру з поточного стеку викликів. sys._getframe() повертає кадр у верхній частині стека викликів; якщо вказано додатковий цілочисельний аргумент depth, функція повертає кадр, який depth викликає нижче верхньої частини стека. Наприклад, sys._getframe(1) повертає об’єкт кадру викликаючого.

    Ця функція присутня лише в CPython, а не в Jython або реалізації .NET. Використовуйте його для налагодження та втримайтеся від спокуси вставити його у робочий код.

Інші зміни та виправлення

У Python 2.1 було внесено відносно небагато менших змін через коротший цикл випуску. Пошук у журналах змін CVS виявив 117 застосованих виправлень і 136 виправлених помилок; обидві цифри, ймовірно, занижені. Деякі з найбільш помітних змін:

  • Тепер опціонально доступний спеціалізований розподільник об’єктів, який має бути швидшим за системний malloc() і мати менше витрат пам’яті. Розподільник використовує функцію C malloc(), щоб отримати великі пули пам’яті, а потім виконує менші запити пам’яті з цих пулів. Його можна ввімкнути, надавши параметр --with-pymalloc сценарію configure; див. Objects/obmalloc.c для деталей реалізації.

    Автори модулів розширення C повинні протестувати свій код із увімкненим розподільником об’єктів, тому що деякий неправильний код може зламатися, спричиняючи дамп ядра під час виконання. В API C Python є купа функцій розподілу пам’яті, які раніше були лише псевдонімами malloc() і free() бібліотеки C, тобто якщо ви випадково викликаєте невідповідні функції, помилка не буде бути помітним. Коли розподільник об’єктів увімкнено, ці функції більше не є псевдонімами malloc() і free(), і виклик неправильної функції для звільнення пам’яті призведе до створення дампа ядра. Наприклад, якщо пам’ять було виділено за допомогою PyMem_New(), її потрібно звільнити за допомогою PyMem_Del(), а не free(). Кілька модулів, що входять до складу Python, вийшли з ладу, і їх потрібно було виправити; безсумнівно, є інші сторонні модулі, які матимуть таку саму проблему.

    Розподільник об’єктів надав Володимир Марангозов.

  • Швидкість рядково-орієнтованого файлового вводу-виводу покращено, оскільки люди часто скаржаться на низьку швидкість, а також тому, що його часто використовують як наївний еталон. Тому метод readline() файлових об’єктів було переписано, щоб він був набагато швидшим. Точна величина прискорення буде відрізнятися від платформи до платформи залежно від того, наскільки повільною була бібліотека C getc(), але вона становить близько 66% і потенційно набагато швидше в деяких конкретних операційних системах. Тім Пітерс виконав більшу частину порівняльного аналізу та кодування для цієї зміни, мотивуючи це обговоренням у comp.lang.python.

    Також було додано новий модуль і метод для файлових об’єктів, наданий Джеффом Еплером. Новий метод, xreadlines(), подібний до наявного вбудованого xrange(). xreadlines() повертає непрозорий об’єкт послідовності, який підтримує лише повторення, читання рядка на кожній ітерації, але не зчитування всього файлу в пам’ять, як це робить існуючий метод readlines(). Ви б використали це так:

    for line in sys.stdin.xreadlines():
        # ... do something for each line ...
        ...
    

    Для детальнішого обговорення змін лінії вводу-виводу дивіться резюме python-dev за 1–15 січня 2001 року на https://mail.python.org/pipermail/python-dev/2001-January/.

  • Новий метод, popitem(), було додано до словників, щоб уможливити деструктивне повторення вмісту словника; це може бути швидше для великих словників, оскільки немає потреби створювати список, що містить усі ключі чи значення. D.popitem() видаляє випадкову пару (ключ, значення) зі словника D і повертає її як 2-кортеж. Це було реалізовано переважно Тімом Пітерсом і Гвідо ван Россумом за пропозицією та попереднім виправленням Моше Цадка.

  • Модулі тепер можуть контролювати, які імена імпортуються, коли використовується from module import *, визначаючи атрибут __all__, що містить список імен, які будуть імпортовані. Однією з поширених скарг є те, що якщо модуль імпортує інші модулі, такі як sys або string, from module import * додасть їх до простору імен модуля імпорту. Щоб виправити це, просто перелічіть загальнодоступні імена в __all__:

    # List public names
    __all__ = ['Database', 'open']
    

    Більш сувору версію цього патча вперше запропонував і реалізував Бен Вольфсон, але після деякого обговорення розробників python була перевірена слабша остаточна версія.

  • Застосування repr() до рядків, які раніше використовували вісімкові символи для недрукованих символів; наприклад, новий рядок був ''\012'. Це був рудиментарний слід походження Python C, але сьогодні вісімкова система має дуже мало практичного використання. Ka-Ping Yee запропонував використовувати шістнадцяткові символи замість вісімкових, а також використовувати символи \n, \t, \r для відповідних символів, і реалізував це нове форматування.

  • Синтаксичні помилки, виявлені під час компіляції, тепер можуть викликати винятки, що містять назву файлу та номер рядка помилки, приємний побічний ефект реорганізації компілятора, виконаної Джеремі Гілтоном.

  • Розширення C, які імпортують інші модулі, було змінено на використання PyImport_ImportModule(), що означає, що вони використовуватимуть усі встановлені хуки імпорту. Це також рекомендується для сторонніх розширень, яким потрібно імпортувати якийсь інший модуль із коду C.

  • Завдяки Фредріку Лунду розмір бази даних символів Unicode було зменшено ще на 340 КБ.

  • Додано кілька нових портів: MacOS X (від Стівена Маєвського), Cygwin (від Джейсона Тішлера); RISCOS (автор Дітмар Швертбергер); Unixware 7 (автор Billy G. Allie).

І є звичайний список незначних виправлень помилок, незначних витоків пам’яті, редагування рядків документів та інших налаштувань, надто довгий, щоб його варто було б перерахувати; перегляньте журнали CVS, щоб отримати повну інформацію, якщо ви її бажаєте.

Подяки

Автор хотів би подякувати наступним людям за пропозиції щодо різних чернеток цієї статті: Грем Кросс, Девід Гуджер, Джей Грейвс, Майкл Хадсон, Марк-Андре Лембург, Фредрік Лунд, Ніл Шеменауер, Томас Воутерс.