Вышла первая альфа Python 3.0
decoratorОпубликовано 1.09.2007 в Новости
Итак, свершилось. В доказательство тому, что Python 3 не превратится в безнадежный долгострой на манер Perl 6 вышла первая альфа. Вместо разработки новой версии с нуля (и как следствие неизбежного попадания в ловушку «эффекта второй системы»), было решено прежде всего очистить язык от накопившихся за долгие годы разнообразных компромисов, обусловленных необходимостью нести бремя обратной совместимости, и ограничиться относительно небольшим колличеством нововеденний.
Рассмотрим основные изменения.
Строки
- Полностью переделана работа со строками. Теперь есть два типа данных – строки (str) и байты (bytes). Строки подобны типу данных unicode из Python 2.x (т.е. все строки теперь юникодные!). Байты хранят двоичные данные (текст в какой-либо кодировке, который обрабатывается как двоичные данные, пока вы не решите декодировать его). Строки и байты нельзя смешивать, вы всегда должны явно преобразовывать их, используя методы .encode() (str -> bytes) или .decode() (bytes -> str).
- Вместо оператора % у строк появился метод format:
"The story of {0}, {1}, and {c}".format(a, b, c=d)
Каждый аргуммент функции format получает порядковый номер начиная с нуля, так в данном примере – ‘a’ это аргумент 0, ‘b’ – агрумент 1. Именные аргументы идентифицируются по имени. Функция включает в себя возможности выравнивания текста, работу с различными типами данных и проч.Несколько примеров использования:
"My name is {0.name}".format(file('out.txt'))
"My name is {0[name]}".format(dict(name='Fred'))"
"Today is: {0:a b d H:M:S Y}".format(datetime.now())
Предствлен класс Formatter, который позволяет легко создавать свои версии функции format. Например, можно сделать вариант format, котрый получает доступ непсоредственно к переменным из заданной области видимости:
fmt = NamespaceFormatter(globals())
greeting = "hello"
print(fmt("{greeting}, world!")) - Кодировка исходного кода по-умолчанию теперь UTF-8.
- Модули StringIO и cStringIO удалены. Вместо них следуют использовать StringIO или BytesIO из модуля io.
Исключения
- Исключения должны наследоваться от BaseException. StandardException удален.
- Вместо except E, e: теперь следует использовать except E as e:, а вместо raise Exception, args – raise Exception(args)
Классы
- Наконец-то в языке остался лишь один вид классов. «Классические» классы удалены.
- Новый синтаксис для метаклассов. Теперь метакласс указывается через аргумент в списке базовых классов: class Foo(base1, base2, metaclass=mymeta): вместо прежнего указания в теле класса __metaclass__ = mymeta
- Появились декораторы для классов.
Различные изменения
- Добавлены аннотации функций.
- Новые возможности распаковки последовательностей. Теперь можно делать так: a, b, *rest = some_sequence и даже так *rest, a = stuff. rest всегда список; правая часть выражения обязательно должна быть итерабельна.
- При делении целых теперь получается вещественное число. Для получения целого используйте 3//2.
- Удален оператор <>. Используйте вместо него !=.
- long переименован в int. Теперь есть только один встроеный тип для целых – int.
- Добавлено ключевое слово nonlocal для доступа к пременным во внешней (не глобальной) области видимости. (Привет полноценные замыкания?
) - print теперь функциия, а не ключевое слово.
- Функция xrange() переименована в range().
- Функции zip(), map() и filter() возвращают итераторы.
- Удалены следующие функции: apply(), callable(), coerce(), execfile(), file(), reduce(), reload().
- Удален метод dict.has_key() (используйте вместо него k in dict)
Ссылки:
Утилита для упрощения перевода кода со второй версии на третью
Понравилась статья? Подпишись на обновления по RSS/E-mail

а что такое полноценное замыкание?
python 2.5:
def f(x):def inner_f(y):
return x*y
return inner_f
f10 = f(10)
print f10(3)
полноценное замыкание без nonlocal. но если внутри функции сделать x += 1, например, то “local variable ‘x’ referenced before assignment”, что исправляется nonlocal в python3. но если изменять “замкнутое” значение, то разве это замыкание?
Конечно. Классический пример замыкания на схеме:
(let ((count 0))
(lambda ()
(set! count (+ count 1))
count))
Первый раз здесь увидел про отмену callable(), и это пожалуй единственное, что не понравилось в изменениях. hasattr(obj, ‘__call__’) уж слишком волосато выглядит.
Итак, свершилось. В доказательство тому, что Python 3 не превратится в безнадежный долгострой на манер Perl 6 вышла первая альфа.
На счет времени появления Perl 6, я как Перловщик не сильно беспокоюсь. Дело в том, что Perl 6 будет новым языком программирования, который абсолютно обратно не совместим с Perl 5. Perl 6, по моему мнению, это не продолжение Perl 5, а попытка создать новый ОО-язык программирования, взявший за основу лишь базовые концепции от Perl 5.
Что касаться Питона, так каждая его новая версия – не совместима полностью с исходниками, написанными под предыдущею версию. С одной стороны – это попытка исправить «исторические» ошибки языка, с другой стороны такой подход несет очень большие неудобства для больших проектов.
> обусловленных необходимостью нести бремя обратной совместимости
Ага, как если бы она когда-то толком в питоне была.
Совершенно жуткое явление, когда что-либо становится популярным, при этом активно не желая становиться really deployable и тем более maintainable — в этом плане питон по воле Гуидо до сих пор лишь чуточку лучше php
>> Ага, как если бы она когда-то толком в питоне была.
> Ага, как если бы она когда-то толком в питоне была.
Очень странное заявление. Совместимость всегда была одним из ключевых факторов при выходе новых версий питона.
Собственно вместо удаления какой-либо особенности она просто начинала генерить warning но продолжала работать
дальше. За все время существования питона несовместимые изменения можно на пальцах пересчитать.
(для интереса загляните какое число всего в 2.5 питоне отмечено как depricated но при этом работает и
поддерживается).
что-то я сомневаюсь, что этот код имеет какой-то смысл. потому что значение возвращаемое функцией теперь зависит не только от параметров фунции, а ещё и от порядка вызова функций.
fx = closure(x)fx(y1)
fx(y2)
fx(y3)
и
fx = closure(x)fx(y1)
fx(y3)
fx(y2)
дадут разные результаты.
ещё интереснее, если мы замыкания подставим в вызовы функции: another_func(fx(1), fx(2)) в ленивыом языке, т.е. параметры будут вычислены не в момент вызова, а где-то внутри тела функции. изменение такого кода на выходе даст что-то вроде генератора случайных чисел.
вобщем интересная идея с замыканием, но нельзя ли увидеть use case?
> что-то я сомневаюсь, что этот код имеет какой-то смысл. потому что значение возвращаемое функцией теперь зависит
> не только от параметров фунции, а ещё и от порядка вызова функций.
> ……
> в ленивыом языке
Да, вы не ошиблись, это статья про питон а не про хаскел )).
А нужно это для организации внутренних атомарных переменных в замыкании, которые сохраняют значения между
вызовами (это можно было и раньше сделать, но неудобным способом).
def count_calls(func):
x = 0
def closure(*dt,**mp):
nonlocal x
x += 1
return func(x - 1,*dt,**mp)
return closure
@count_calls
def test(x,y):
print(x,y)
это классы-то “неудобный способ”? а что тогда удобный?
class count_calls:
def __init__(self, func):
self.counter = 0
self.func = func
def __call__(self, *args, **kwargs):
self.counter += 1
return self.func(*args, **kwargs)
@count_calls
def test(x, y):
print x + y
раньше замыкания классами эмулировали, теперь классы замыканиями?
В таком случае следующим вашим советом должно быть предложение вообще убрать замыкания?
Кто чем хочет, тот тем и пользуется, к тому-же вариант с замыканиями будет прим.
раза в 2 быстрее.
Можно еще так использовать. Тут с классами придется побольше кода написать.
def r(dt):
m = 1
def g(x):
nonlocal m
m += len(x)
return chot_tam_delat(x)
map(g,dt)
return m
> это классы-то “неудобный способ”? а что тогда удобный?
Сразу не понял к чему это было.
Раньше это через замыкания делалось примерно так:
def func(m):
closure_var = [m]
def closure(z):
closure_var[0] += 1
return chtoto_tam(z)
return closure
В таком случае следующим вашим советом должно быть предложение вообще убрать замыкания?спасибо, что додумываете за меня. мне так гораздо легче.
def f(x):m = 1
def inner_f(y):
nonlocal inner_z, m
m += 1
return inner_z(y)
def inner_z(y):
nonlocal inner_f, m
print(inner_f)
return y * x + m
return inner_f
теже же классы, что и раньше, только писанины добавилось.
я к тому, что я не вижу разницы между эмуляцией молотка микроскопом и эмуляцией микроскопа молотком (хотя, конечно, каждый пользуется тем, чем хочет). замыкания – удобный инструмент, классы – тоже удобный инструмент. зачем одно выражать через другое я не знаю и вообще-то об этом и спрашивал. может быть nonlocal имеет какое-то другое применение кроме “полноценных замыканий”?
Кто чем хочет, тот тем и пользуется, к тому-же вариант с замыканиями будет прим.раза в 2 быстрее.
а можно озвучить расчёты? потому что я не вижу большой разницы между вызовом метода класса с обращением к члену класса и вызовом функции и обращением к переменной.
Можно еще так использовать. Тут с классами придется побольше кода написать.скорее всего классы вообще не придётся писать. это цикл спрятанный в функцию.
> зачем одно выражать через другое я не знаю
???? собственно это вы начали рассказывать что вместо замыканий можно классы использовать
> может быть nonlocal имеет какое-то другое применение кроме “полноценных замыканий”?
Я уже привел пример в 10м посте.
> а можно озвучить расчёты?…..
> потому что я не вижу большой разницы между вызовом метода класса с
> обращением к члену класса и вызовом функции и обращением к переменной.
import timeit и вперед, или читаем основы оптимизации питоновского кода
Насчет callable: как я понял, предлагается “просто выполнить попытку вызова”. Если нужно обработать ошибку, придется ставить try/catch. По-моему тупо. Я лучше определю свою callable() для Py3k и выше.
> Насчет callable: как я понял, предлагается “просто выполнить попытку вызова”.
Особенно все странно если учесть что при попытке вызова объекта без метода __call__ генерится
TypeError а не какое-то специфическое исключение, т.е. в catch придется еще разбираться
где исключение было сгенерированно – при попытке вызова или уже при исполнении функции.
В общем причин убирания callable я так и не догнал, хотя это довольно долго мусолили в pydev
рассылке.
как раз это мне и не понятно. в 10 посте описан цикл for спрятанный в функцию и выполняющийся через вызов map(). обычный цикл for не имеет проблем с доступом к локальным переменным функции в которой он выполняется, поэтому зачем нужны такие телодвижения не ясно.
спасибо за ссылку. там написаны очень интересные вещи, но можно поступить несколько по-другому – не читать про низкоуровневую оптимизацию в языке высокого уровня, а взять профайлер и посмотреть.
def f_dec(func):
non_local = [ 0 ]
def dec(*args, **kwargs):
non_local[0] += 1
return func(*args, **kwargs)
return dec
class c_dec:
def __init__(self, func):
self.non_local = 0
self.func = func
def __call__(self, *args, **kwargs):
self.non_local += 1
return self.func(*args, **kwargs)
@f_dec
def test1(x, y):
return x + y
@c_dec
def test2(x, y):
return x + y
for x in xrange(1000000):
test1(1, 2)
test2(1, 2)
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 61.856 61.856 :0(execfile)
1 0.000 0.000 0.000 0.000 :0(setprofile)
1 0.000 0.000 61.856 61.856 :1()
1 17.937 17.937 61.856 61.856 perf.py:1()
1 0.000 0.000 0.000 0.000 perf.py:1(f_dec)
1000000 15.133 0.000 21.621 0.000 perf.py:12(__call__)
1000000 6.528 0.000 6.528 0.000 perf.py:16(test1)
1000000 6.488 0.000 6.488 0.000 perf.py:20(test2)
1000000 15.769 0.000 22.297 0.000 perf.py:3(dec)
1 0.000 0.000 0.000 0.000 perf.py:8(c_dec)
1 0.000 0.000 0.000 0.000 perf.py:9(__init__)
1 0.000 0.000 61.856 61.856 profile:0(execfile(’perf.py’))
0 0.000 0.000 profile:0(profiler)
почему-то получается не в два раза быстее, а как-то.. одинаково.
> поэтому зачем нужны такие телодвижения не ясно
http://www.python.org/dev/peps/pep-3104/ раздел Rationale, если и после этого будет “не ясно”
можно написать в python-dev-request@python.org что замыкания не нужны а nonlocal так вообще нафик.
> почему-то получается не в два раза быстее, а как-то.. одинаково.
Для 2.X скорость отличается не сильно в данном случае т.к. здесь присутствует оператор [],
который трансформируется в три питоновские инструкции. Для 3.0 в этом месте нет дополнительных
инструкций. Вариант через классы при каждом обращении к атрибуту требуют
двух дополнительных инструкций. Если бы счетчик не требовался то через замыкания было-бы быстрее
и в 2.X.
Интересно? ,eltn kb gjkyjwtyyfz gjllth;rf vyjujvthys[ vfccbdjd&
Интересно? будет ли полноценная поддержка многомерных массивов?
> Интересно? будет ли полноценная поддержка многомерных массивов?
Нет. Если очень нужно используйте numpy –
там есть тип для массивов с произвольными Python объектами.
http://www.python.org/dev/peps/pep-0209/
http://www.python.org/dev/peps/pep-3104/ раздел Rationale, если и после этого будет “не ясно” можно написать в python-dev-request@python.org что замыкания не нужны а nonlocal так вообще нафик.спасибо, что продолжаете нести бремя додумывания. у вас это хорошо получается.
в PEP’е, к счастью, приведён более вменяемый пример, теперь вроде бы понятно зачем нужен nonlocal. только в том примере работа с переменной не в глобальной, и не в локальной области видимости. можно ли считать эо замыканием – не знаю. технически, наверное да. но тогда можно глобальную область видимости назвать “такое большое замыкание”. но это не важно, спасибо за разъяснения.
Для 2.X скорость отличается не сильно в данном случае т.к. здесь присутствует оператор [], который трансформируется в три питоновские инструкции. Для 3.0 в этом месте нет дополнительных инструкций. Вариант через классы при каждом обращении к атрибуту требуютдвух дополнительных инструкций. Если бы счетчик не требовался то через замыкания было-бы быстрее и в 2.X.
сначала не хотел на это отвечать, потому что мерять “питоновские инструкции” – это бред. хотите считать инструкции – пишите на ассемблере. питон – это язык высокого уровня, хотите мерять производительность – берите хотя бы профайлер. сто раз это уже обмусоливалось, производительность программы зависит от алгоритмов, а не от 2 лишних инструкций.
всё-таки запустил профайлер на python3.
код f_dec стал выглядеть так:
def f_dec(func):non_local = 0
def dec(*args, **kwargs):
nonlocal non_local
non_local += 1
return func(*args, **kwargs)
return dec
ncalls tottime percall cumtime percall filename:lineno(function)1 0.000 0.000 0.000 0.000 :0(__build_class__)
2/1 0.000 0.000 97.174 97.174 :0(exec)
1 0.004 0.004 0.004 0.004 :0(setprofile)
2/1 26.746 13.373 97.174 97.174 :1()
1 0.000 0.000 0.000 0.000 :1(f_dec)
1 0.000 0.000 0.000 0.000 :10(__init__)
1000000 24.558 0.000 35.290 0.000 :13(__call__)
1000000 11.193 0.000 11.193 0.000 :18(test1)
1000000 10.733 0.000 10.733 0.000 :22(test2)
1000000 23.946 0.000 35.138 0.000 :3(dec)
1 0.000 0.000 0.000 0.000 :9(c_dec)
1 0.000 0.000 97.178 97.178 profile:0(exec('..
0 0.000 0.000 profile:0(profiler)
ерунда. ч.т.д.
Я уже почти устал.
> “питоновские инструкции” – это бред. хотите считать инструкции – пишите на ассемблере. питон – это язык высокого
> уровня, хотите мерять производительность….
Подавляющее большинство низкоуровневых питоновских инструкций исполняются за примерно одинаковое время
(а менно такие как add,getattr,getitem,mul,… , усли конечно соотв. операторы не перегружены python/C кодом
на что-нить нетривиальное)
Мерять такой код профайлером – мягко говоря неправильно т.к. накладные расходы профайлера ЗНАЧИТЕЛЬНО превышают время исполнения кода(что мы тут и видим). Для таких случаев давно уже есть timeit(о чем я,кстати, писал)
WinXP SP2,AthlonX2 3600@2.9Ghz
Python 3.0a1 (py3k:57844, Aug 31 2007, 16:54:27) [MSC v.1310 32 bit (Intel)] on win32
>>> def closure(func):
counter = 1
def cl(x):
nonlocal counter
counter += 1
return func(counter,x)
return cl
>>> class ccl:
def __init__(self,func):
self.func = func
self.counter = 1
def __call__(self,val):
self.counter += 1
return self.func(self.counter,val)
>>> @closure
def f1(x,y):
pass #мы вроде не сложение меряем а замыкания
>>> @ccl
def f2(x,y):
pass
>>> def
>>> f1(1)
>>> import timeit
>>> timeit.Timer("f1(1)","from __main__ import f1").timeit()
0.70828024232130105
>>> timeit.Timer("f2(1)","from __main__ import f2").timeit()
1.8935336753693548
>>> def f3(x,y):pass
>>> timeit.Timer("f3(1,1)","from __main__ import f3").timeit()
0.31531297972230732
Накладные расходы замыкания 0.708 - 0.315 = 0.392
Накладные расходы класса 1.894 - 0.315 = 1.579
С классом в 4(ЧЕТЫРЕ) раз медленнее.
Те-же данные для той-же машины и python 2.5.1
t_closure = 0.7415
t_class = 1.383
t_empty = 0.285
( 1.383 – 0.285 ) / ( 0.7415 – 0.285 ) = 2.4
это не тот же самый код. простая замена x, y на *args, **kwargs сразу же даёт проседание производительности по timeit() на 25%, что в принципе доказывает бредовость идеи меряния количества инструкций и делания на основе этого каких-то выводов – простое изменение кода может убрать всю выигранную производительность.
потому что это язык высокого уровня.
по поводу фактической производительности. измерение всего одной итерации всегда будет давать разный результат.
print(timeit.Timer("f2(1, 2)", "from __main__ import f2").timeit(1000000))print(timeit.Timer("f1(1, 2)", "from __main__ import f1").timeit(1000000))
3.90879893303
2.2824139595
быстрее не в 4 и не в 2 раза.
плюс с использованием *args, **kwargs, timeit() при разных замерах даёт отношение первого времени ко второму с вариациями +-10%, что говорит или о том, что timeit() не точен, или о том же, о чём я на писал в первом абзаце.
но в целом убедили, да. если дизассемблировать код и считать инструкции, то можно написать быстрее.
> измерение всего одной итерации всегда будет давать разный результат.
В методе timeit по умолчанию 1000000 отераций )))
да, это действительно так. ахаха, как это смешно ))0ноль)