Украинское сообщество программистов

Вышла первая альфа 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, argsraise 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)

Ссылки:

Список изменений

Утилита для упрощения перевода кода со второй версии на третью

Теги: ,

1 звезда2 звезды3 звезды4 звезды5 звезд (Еще не оценили)
Загрузка ... Загрузка ...

Понравилась статья? Подпишись на обновления по RSS/E-mail

Подписаться, не оставляя комментарий

Все комментарии (26) к “Вышла первая альфа Python 3.0” RSS

  1. Anonymous

    (Привет полноценные замыкания? ;) )

    а что такое полноценное замыкание?

    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. но если изменять “замкнутое” значение, то разве это замыкание?

  2. decorator

    но если изменять “замкнутое” значение, то разве это замыкание?

    Конечно. Классический пример замыкания на схеме:


    (let ((count 0))
    (lambda ()
    (set! count (+ count 1))
    count))

  3. Иван Сагалаев

    Первый раз здесь увидел про отмену callable(), и это пожалуй единственное, что не понравилось в изменениях. hasattr(obj, ‘__call__’) уж слишком волосато выглядит.

  4. DmitryZhariy

    Итак, свершилось. В доказательство тому, что Python 3 не превратится в безнадежный долгострой на манер Perl 6 вышла первая альфа.

    На счет времени появления Perl 6, я как Перловщик не сильно беспокоюсь. Дело в том, что Perl 6 будет новым языком программирования, который абсолютно обратно не совместим с Perl 5. Perl 6, по моему мнению, это не продолжение Perl 5, а попытка создать новый ОО-язык программирования, взявший за основу лишь базовые концепции от Perl 5.
    Что касаться Питона, так каждая его новая версия – не совместима полностью с исходниками, написанными под предыдущею версию. С одной стороны – это попытка исправить «исторические» ошибки языка, с другой стороны такой подход несет очень большие неудобства для больших проектов.

  5. Michael Shigorin

    > обусловленных необходимостью нести бремя обратной совместимости
    Ага, как если бы она когда-то толком в питоне была.

    Совершенно жуткое явление, когда что-либо становится популярным, при этом активно не желая становиться really deployable и тем более maintainable — в этом плане питон по воле Гуидо до сих пор лишь чуточку лучше php :(

  6. koder

    >> Ага, как если бы она когда-то толком в питоне была.

    > Ага, как если бы она когда-то толком в питоне была.

    Очень странное заявление. Совместимость всегда была одним из ключевых факторов при выходе новых версий питона.
    Собственно вместо удаления какой-либо особенности она просто начинала генерить warning но продолжала работать
    дальше. За все время существования питона несовместимые изменения можно на пальцах пересчитать.
    (для интереса загляните какое число всего в 2.5 питоне отмечено как depricated но при этом работает и
    поддерживается).

  7. Anonymous

    Конечно. Классический пример замыкания на схеме:

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

    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?

  8. koder

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

    Да, вы не ошиблись, это статья про питон а не про хаскел )).

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


    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)

  9. Anonymous

    это классы-то “неудобный способ”? а что тогда удобный?

    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

    раньше замыкания классами эмулировали, теперь классы замыканиями?

  10. koder

    В таком случае следующим вашим советом должно быть предложение вообще убрать замыкания?
    Кто чем хочет, тот тем и пользуется, к тому-же вариант с замыканиями будет прим.
    раза в 2 быстрее.

    Можно еще так использовать. Тут с классами придется побольше кода написать.

    def r(dt):
    m = 1
    def g(x):
    nonlocal m
    m += len(x)
    return chot_tam_delat(x)
    map(g,dt)
    return m

  11. koder

    > это классы-то “неудобный способ”? а что тогда удобный?

    Сразу не понял к чему это было.
    Раньше это через замыкания делалось примерно так:


    def func(m):
    closure_var = [m]
    def closure(z):
    closure_var[0] += 1
    return chtoto_tam(z)
    return closure

  12. Anonymous

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

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

    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 быстрее.

    а можно озвучить расчёты? потому что я не вижу большой разницы между вызовом метода класса с обращением к члену класса и вызовом функции и обращением к переменной.

    Можно еще так использовать. Тут с классами придется побольше кода написать.

    скорее всего классы вообще не придётся писать. это цикл спрятанный в функцию.

  13. koder

    > зачем одно выражать через другое я не знаю

    ???? собственно это вы начали рассказывать что вместо замыканий можно классы использовать

    > может быть nonlocal имеет какое-то другое применение кроме “полноценных замыканий”?

    Я уже привел пример в 10м посте.

    > а можно озвучить расчёты?…..
    > потому что я не вижу большой разницы между вызовом метода класса с
    > обращением к члену класса и вызовом функции и обращением к переменной.

    import timeit и вперед, или читаем основы оптимизации питоновского кода

  14. Макс Ищенко

    Насчет callable: как я понял, предлагается “просто выполнить попытку вызова”. Если нужно обработать ошибку, придется ставить try/catch. По-моему тупо. Я лучше определю свою callable() для Py3k и выше.

  15. koder

    > Насчет callable: как я понял, предлагается “просто выполнить попытку вызова”.

    Особенно все странно если учесть что при попытке вызова объекта без метода __call__ генерится
    TypeError а не какое-то специфическое исключение, т.е. в catch придется еще разбираться
    где исключение было сгенерированно – при попытке вызова или уже при исполнении функции.
    В общем причин убирания callable я так и не догнал, хотя это довольно долго мусолили в pydev
    рассылке.

  16. Anonymous

    Я уже привел пример в 10м посте.

    как раз это мне и не понятно. в 10 посте описан цикл for спрятанный в функцию и выполняющийся через вызов map(). обычный цикл for не имеет проблем с доступом к локальным переменным функции в которой он выполняется, поэтому зачем нужны такие телодвижения не ясно.

    import timeit и вперед, или читаем основы оптимизации питоновского кода

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

    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)

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

  17. koder

    > поэтому зачем нужны такие телодвижения не ясно

    http://www.python.org/dev/peps/pep-3104/ раздел Rationale, если и после этого будет “не ясно”
    можно написать в python-dev-request@python.org что замыкания не нужны а nonlocal так вообще нафик.

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

    Для 2.X скорость отличается не сильно в данном случае т.к. здесь присутствует оператор [],
    который трансформируется в три питоновские инструкции. Для 3.0 в этом месте нет дополнительных
    инструкций. Вариант через классы при каждом обращении к атрибуту требуют
    двух дополнительных инструкций. Если бы счетчик не требовался то через замыкания было-бы быстрее
    и в 2.X.

  18. @spect

    Интересно? ,eltn kb gjkyjwtyyfz gjllth;rf vyjujvthys[ vfccbdjd&

  19. @spect

    Интересно? будет ли полноценная поддержка многомерных массивов?

  20. koder

    > Интересно? будет ли полноценная поддержка многомерных массивов?

    Нет. Если очень нужно используйте numpy –
    там есть тип для массивов с произвольными Python объектами.
    http://www.python.org/dev/peps/pep-0209/

  21. Anonymous

    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)

    ерунда. ч.т.д.

  22. koder

    Я уже почти устал.

    > “питоновские инструкции” – это бред. хотите считать инструкции – пишите на ассемблере. питон – это язык высокого
    > уровня, хотите мерять производительность….

    Подавляющее большинство низкоуровневых питоновских инструкций исполняются за примерно одинаковое время
    (а менно такие как 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(ЧЕТЫРЕ) раз медленнее.

  23. koder

    Те-же данные для той-же машины и 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

  24. Anonymous

    это не тот же самый код. простая замена 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() не точен, или о том же, о чём я на писал в первом абзаце.

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

  25. koder

    > измерение всего одной итерации всегда будет давать разный результат.

    В методе timeit по умолчанию 1000000 отераций )))

  26. Anonymous

    В методе timeit по умолчанию 1000000 отераций )))

    да, это действительно так. ахаха, как это смешно ))0ноль)

Оставить комментарий

Указать свой сайт могут только зарегистрированные пользователи. Регистрация или вход.

Архив

Добавить статью

Станьте автором нашего сайта!

Какие материалы подходят для публикации? — Такие.

Присылайте статьи на editors@developers.org.ua.

Подробнее.

Популярные теги

Все теги

Комментарии

Последние комментарии

интернет-магазин цифровой техники

Бытовая техника
Холодильники
Купить часы
Телевизоры ЖК
Стиральные машины
Швейцарские часы