Главная страница
Навигация по странице:

  • Только именованные аргументы

  • Объекты класса Ellipsis как выражения

  • Улучшенная реализация функции super()

  • Создать сообщение ответа, используя строки (Юникод) >>> status = 200 >>> msg = “OK” >>> proto = “HTTP/1.0” >>> response = “%s %d %s” % (proto, status, msg)

  • Новая система ввода-вывода

  • справочник по Python. мм isbn 9785932861578 9 785932 861578


    Скачать 4.21 Mb.
    Названиемм isbn 9785932861578 9 785932 861578
    Анкорсправочник по Python
    Дата08.05.2022
    Размер4.21 Mb.
    Формат файлаpdf
    Имя файлаBizli_Python-Podrobnyy-spravochnik.440222.pdf
    ТипСправочник
    #518195
    страница71 из 82
    1   ...   67   68   69   70   71   72   73   74   ...   82
    foo(3,-2)
    5
    >>> foo(-5,2)
    Traceback (most recent call last):
    File “”, line 1, in
    File “meta.py”, line 19, in call def assert_call(*args,**kwargs):
    AssertionError: a must be positive
    (Перевод:
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 1, в
    Файл “meta.py”, строка 19, в вызове def assert_call(*args,**kwargs):

    776
    Приложение A. Python 3
    AssertionError: a должно быть положительным
    )
    >>>
    Только именованные аргументы
    Ф
    ункцию можно определить так, что она будет принимать некоторые аргу- менты только как именованные аргументы. Достигается это за счет добав- ления дополнительных аргументов после первого аргумента со звездочкой в имени. Например:
    def foo(x, *args, strict=False):
    инструкции
    В вызове такой функции аргумент strict может быть указан только как именованный. Например:
    a = foo(1, strict=True)
    Любые дополнительные позиционные аргументы будут помещаться в кор- теж args и не будут использоваться для установки значения аргумента strict
    . Если нежелательно, чтобы функция принимала переменное чис- ло аргументов, но желательно, чтобы некоторые аргументы принимались только как именованные, этого можно добиться, добавив одиночный сим- вол * в список аргументов. Например:
    def foo(x, *, strict=False):
    инструкции
    Ниже приводится пример использования:
    foo(1,True) # Ошибка. TypeError: foo() takes 1 positional argument
    # TypeError: foo() принимает 1 позиционный аргумент foo(1,strict=True) # Ok.
    Объекты класса Ellipsis как выражения
    Объект класса Ellipsis object (...) теперь может использоваться в качестве выражения. Это позволяет сохранять такие объекты в контейнерах и в пе- ременных. Например:
    >>> x = ... # Присвоит объект класса Ellipsis
    >>> x
    Ellipsis
    >>> a = [1,2,...]
    >>> a
    [1, 2, Ellipsis]
    >>> ... in a
    True
    >>> x is ...
    True
    >>>
    Способ интерпретации многоточий остается за использующим их приложе- нием. Эта особенность позволяет использовать многоточие (...) как часть син-

    Новые возможности языка
    777
    таксиса в библиотеках и фреймворках (например, как шаблонный символ, как признак продолжения и для обозначения других подобных понятий).
    Цепочки исключений
    Теперь имеется возможность объединять исключения в цепочки. По сути это обеспечивает возможность передать в текущем исключении информа- цию о предыдущем исключении. Для явного объединения исключений ис- пользуется инструкция raise с квалификатором from. Например:
    try:
    инструкции
    except ValueError as e:
    raise SyntaxError(“Couldn’t parse configuration”) from e
    В случае возбуждения исключения SyntaxError будет выведено следующее сообщение об ошибке, содержащее информацию о двух исключениях:
    Traceback (most recent call last):
    File “”, line 2, in
    ValueError: invalid literal for int() with base 10: ‘nine’
    ёёё
    The above exception was the direct cause of the following exception:
    ёёё
    Traceback (most recent call last):
    File “”, line 4, in
    SyntaxError: Couldn’t parse configuration
    (Перевод:
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 2, в
    ValueError: недопустимый литерал в вызове int() с основанием 10: ‘nine’
    ёёё
    Исключение, приведенное выше, стало причиной следующего исключения:
    ёёё
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 4, в
    SyntaxError: Ошибка разбора файла с настройками
    )
    Объекты исключений обладают атрибутом __cause__, в котором сохраняет- ся предыдущее исключение. Квалификатор from в инструкции raise уста- навливает значение этого атрибута.
    Более сложный пример объединения исключений связан с возбуждением исключения в обработчике другого исключения. Например:
    def error(msg):
    print(m) # Обратите внимание: преднамеренная ошибка (имя m не определено)
    ёёё
    try:
    инструкции
    except ValueError as e:
    error(“Couldn’t parse configuration”)
    Если попытаться выполнить этот фрагмент в Python 2, будет выведено сообщение о единственном исключении NameError, возникшем в функции

    778
    Приложение A. Python 3 error()
    . В Python 3 предыдущее обрабатываемое исключение будет объеди-
    Python 3 предыдущее обрабатываемое исключение будет объеди-
    3 предыдущее обрабатываемое исключение будет объеди- нено с результатом. Например, будет получено следующее сообщение:
    Traceback (most recent call last):
    File “”, line 2, in
    ValueError: invalid literal for int() with base 10: ‘nine’
    ёёё
    During handling of the above exception, another exception occurred:
    ёёё
    Traceback (most recent call last):
    File “”, line 4, in
    File “”, line 2, in error
    NameError: global name ‘m’ is not defined
    (Перевод:
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 2, в
    ValueError: недопустимый литерал в вызове int() с основанием 10: ‘nine’
    ёёё
    В процессе обработки исключения, приведенного выше, возникло другое исключение:
    ёёё
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 4, в
    Файл “”, строка 2, в error
    NameError: глобальное имя ‘m’ не определено
    )
    При неявном объединении ссылка на предыдущее исключение сохраняет- ся в атрибуте __context__ экземпляра последнего исключения.
    Улучшенная реализация функции super()
    Функция super() производит поиск методов в базовых классах. В Python 3 она может вызываться без аргументов. Например:
    class C(A,B):
    def bar(self):
    return super().bar() # Вызовет метод bar() базового класса
    В Python 2 пришлось бы вызывать эту функцию как super(C,self).bar().
    Старый синтаксис по-прежнему поддерживается, но он выглядит менее удобочитаемым.
    Улучшенные метаклассы
    В Python 2 имеется возможность определять метаклассы, которые изменя-
    Python 2 имеется возможность определять метаклассы, которые изменя-
    2 имеется возможность определять метаклассы, которые изменя- ют поведение других классов. Важной особенностью реализации являет- ся то, что обработка метаклассом выполняется только после того, как все тело класса будет выполнено интерпретатором. То есть после того, как ин- терпретатор выполнит все тело класса и заполнит словарь. Как только сло- варь будет заполнен, он передается конструктору метакласса (после того, как тело класса уже будет выполнено).
    В Python 3 метаклассы могут выполнять дополнительные операции перед тем, как интерпретатор приступит к выполнению тела класса. Это достига- ется за счет определения в метаклассе специального метода с именем __pre- pre-

    Новые возможности языка
    779
    pare__(
    cls, name, bases, **kwargs)
    . В качестве результата данный метод дол- жен возвращать словарь. Этот словарь будет заполняться интерпретатором по мере выполнения определений в теле класса. Ниже приводится пример, иллюстрирующий простейшую обработку:
    class MyMeta(type):
    @classmethod def __prepare__(cls,name,bases,**kwargs):
    print(“подготавливается”,name,bases,kwargs)
    return {}
    def __new__(cls,name,bases,classdict):
    print(“создается”,name,bases,classdict)
    return type.__new__(cls,name,bases,classdict)
    В Python 3 для определения метаклассов можно использовать альтерна-
    Python 3 для определения метаклассов можно использовать альтерна-
    3 для определения метаклассов можно использовать альтерна- тивный синтаксис. Например, ниже приводится определение класса, ис- пользующего метакласс MyMeta:
    class Foo(metaclass=MyMeta):
    print(“Начало определения методов”)
    def __init__(self):
    pass def bar(self):
    pass print(“Конец определения методов”)
    Выполнив предыдущий программный код, вы увидите следующие резуль- таты, иллюстрирующие порядок выполнения:
    подготавливается Foo () {}
    Начало определения методов
    Конец определения методов создается Foo () {‘__module__’: ‘__main__’,
    ‘bar’: ,
    ‘__init__’: }
    Методу __prepare__() метакласса передаются дополнительные именован- ные аргументы, которые указываются в списке базовых классов инструк- ции class. Например, при использовании инструкции class Foo(metaclass=
    MyMeta,spam=42,blah=”Hello”)
    метод MyMeta.__prepare__() получит именован- ные аргументы spam и blah. Это соглашение может использоваться для пере- дачи метаклассу произвольных параметров настройки.
    Чтобы заставить новый метод __prepare__() метаклассов произвести какие- то полезные действия, его можно обязать возвращать объект словаря, об- ладающий дополнительными свойствами. Например, если необходимо реализовать дополнительную обработку, которая должна выполняться в процессе определения класса, следует объявить класс, производный от класса dict, и переопределить в нем метод __setitem__(), в котором реали- зовать обработку операций присваивания элементам словаря класса. Сле- дующий пример иллюстрирует такую возможность, объявляя метакласс, который сообщает об ошибках, если какой-либо метод или атрибут класса объявляется несколько раз.

    780
    Приложение A. Python 3 class MultipleDef(dict):
    def __init__(self):
    self.multiple= set()
    def __setitem__(self,name,value):
    if name in self:
    self.multiple.add(name)
    dict.__setitem__(self,name,value)
    ёёё
    class MultiMeta(type):
    @classmethod def __prepare__(cls,name,bases,**kwargs):
    return MultipleDef()
    def __new__(cls,name,bases,classdict):
    for name in classdict.multiple:
    print(name,”повторное определение”)
    if classdict.multiple:
    raise TypeError(“Присутствует несколько определений “)
    return type.__new__(cls,name,bases,classdict)
    Е
    сли применить этот метакласс к определению другого класса, он будет сообщать об ошибке при обнаружении повторного определения любого из методов. Например:
    class Foo(metaclass=MultiMeta):
    def __init__(self):
    pass def __init__(self,x): # Ошибка. __init__ повторное определение.
    pass
    Типичные ошибки
    Если вы планируете переход с версии Python 2 на версию Python 3, имейте в виду, что Python 3 – это не только новый синтаксис и возможности язы-
    Python 3 – это не только новый синтаксис и возможности язы-
    3 – это не только новый синтаксис и возможности язы- ка. При переделке основных частей ядра и библиотеки в некоторых слу- чаях вносились неожиданные, не ставящие своей целью обеспечение со- вместимости, изменения. Некоторые аспекты Python 3 могут выглядеть, как ошибки для программистов, использующих Python 2. Некоторые кон-
    Python 2. Некоторые кон-
    2. Некоторые кон- струкции, «простые» в использовании в версии Python 2, теперь считают-
    Python 2, теперь считают-
    2, теперь считают- ся недопустимыми.
    В этом разделе отмечаются некоторые наиболее серьезные ошибки, кото- рые часто допускаются программистами, привыкшими использовать Py-
    Py- thon 2.
    Текст и байты
    В Python 3 проводится очень строгое разграничение между текстовыми строками (символы) и двоичными данными (байты). Такие литералы, как
    “hello”
    , представляют текстовые данные и хранятся в виде строк Юникода, а литералы, такие как b”hello”, представляет строки байтов (в данном слу- чае строку, содержащую символы ASCII).

    Типичные ошибки
    781
    В Python 3 не допускается смешивать типы str и bytes. Например, если по- пытаться выполнить конкатенацию текстовой строки и строки байтов, бу- дет возбуждено исключение TypeError. Это важное отличие от Python 2, где строка байтов автоматически была бы преобразована в строку Юникода.
    Чтобы преобразовать текстовую строку s в строку байтов, необходимо вы- звать метод s.encode(encoding). Например, вызов s.encode(‘utf-8’) преобразу- ет s в строку байтов в кодировке UTF-8. Чтобы строку байтов t преобразовать обратно в текстовую строку, необходимо вызвать метод t.decode(encoding).
    Методы encode() и decode() можно рассматривать как своеобразные опера- ции «приведения типов» между текстовыми строками и строками байтов.
    Наличие четкого разделения между текстом и двоичными данными мож- но считать удачным решением – правила смешивания строковых типов в Python 2 по меньшей мере были неясными и трудными для понимания.
    Однако одно из последствий такого разграничения состоит в том, что стро- ки байтов в Python 3 не обеспечивают такой же гибкости в представлении
    «текста». Несмотря на наличие стандартных строковых методов, таких как split()
    и replace(), многие другие особенности строк байтов отличаются от тех, что имеются в Python 2. Например, если вывести строку байтов с помо-
    Python 2. Например, если вывести строку байтов с помо-
    2. Например, если вывести строку байтов с помо- щью функции print(), вывод будет произведен с помощью функции repr() в виде b’содержимое’. Точно так же ни одна из строковых операций формати- рования (%, .format()) не будет работать со строками байтов. Например:
    x = b’Hello World’
    print(x) # Выведет b’Hello World’
    print(b”You said ‘%s’” % x) # TypeError: % operator not supported
    # TypeError: оператор % не поддерживается
    Отсутствие некоторых возможностей, присущих текстовым строкам, явля- ется потенциальной ловушкой для системных программистов. Несмотря на повсеместное распространение Юникода, во многих случаях бывает не- обходимо работать с текстом, представленным однобайтовыми символа- ми, такими как ASCII. Чтобы избежать лишних сложностей, связанных с Юникодом, может появиться желание использовать тип bytes. Однако на самом деле это только осложнит обработку такого текста. Ниже приводит- ся пример, иллюстрирующий потенциальную проблему:
    >>> # Создать сообщение ответа, используя строки (Юникод)
    >>> status = 200
    >>> msg = “OK”
    >>> proto = “HTTP/1.0”
    >>> response = “%s %d %s” % (proto, status, msg)
    >>> print(response)
    HTTP/1.0 200 OK
    ёёё
    >>> # Создать сообщение ответа, используя строки байтов (ASCII)
    >>> status = 200
    >>> msg = b”OK”
    >>> proto = b”HTTP/1.0”
    >>> response = b”%s %d %s” % (proto, status, msg)
    Traceback (most recent call last):
    File “”, line 1, in

    782
    Приложение A. Python 3
    TypeError: unsupported operand type(s) for %: ‘bytes’ and ‘tuple’
    (Перевод:
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 1, в
    TypeError: неподдерживаемые типы операндов для %: ‘bytes’ и ‘tuple’
    )
    ёёё
    >>> response = proto + b” “ + str(status) + b” “ + msg
    Traceback (most recent call last):
    File “”, line 1, in
    TypeError: can’t concat bytes to str
    (Перевод:
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 1, в
    TypeError: невозможно объединить данные типов bytes и str
    )
    ёёё
    >>> bytes(status)
    b’\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....’
    ёёё
    >>> bytes(str(status))
    Traceback (most recent call last):
    File “”, line 1, in
    TypeError: string argument without an encoding
    (Перевод:
    Трассировочная информация (самый последний вызов – самый нижний):
    Файл “”, строка 1, в
    TypeError: не указана кодировка для строкового аргумента
    )
    ёёё
    >>> bytes(str(status),’ascii’)
    b’200’
    ёёё
    >>> response = proto + b” “ + bytes(str(status),’ascii’) + b” “ + msg
    >>> print(response)
    b’HTTP/1.0 200 OK’
    ёёё
    >>> print(response.decode(‘ascii’))
    HTTP/1.0 200 OK
    >>>
    В примере можно видеть, насколько четко в Python 3 проведена грань между текстом и двоичными данными. Даже операции, которые на пер- вый взгляд должны выполняться очень просто, такие как преобразование целых чисел в символы ASCII, оказываются намного сложнее при работе с байтами.
    В итоге, если предполагается выполнять какие-либо операции по обработ- ке или форматированию текста, практически всегда лучше использовать стандартные текстовые строки. Если по завершении обработки необходи- мо получить строку байтов, для преобразования строки Юникода в строку байтов можно воспользоваться методом s.encode(‘latin-1’).
    Различие между текстом и двоичными данными может быть менее четким при использовании различных библиотечных модулей. Некоторые модули

    Типичные ошибки
    783
    одинаково хорошо работают как с текстовыми строками, так и со строками байтов, тогда как другие вообще не могут работать с байтами. В некоторых случаях поведение модуля может зависеть от типа входных данных. На- пример, функция os.listdir(dirname) возвращает имена файлов, которые могут быть успешно декодированы как строки Юникода, только если в ар- гументе dirname передается текстовая строка. Если в аргументе dirname пе- редать строку байтов, все возвращаемые имена файлов будут представлены строками байтов.
    Новая система ввода-вывода
    В Python 3 была реализована совершенно новая система ввода-вывода, описание которой приводится в главе 19 «Службы операционной систе- мы», в разделе с описанием модуля io. Новая система ввода-вывода также отражает существенные различия между текстом и двоичными данными, представленными в виде строк.
    Если предполагается выполнять какие-либо операции ввода-вывода с тек- стовыми данными, в Python 3 потребуется открывать файлы в «текстовом режиме» и указывать кодировку, если кодировка по умолчанию (обычно
    UTF-8) по каким-либо причинам не подходит. При выполнении операций ввода-вывода с двоичными данными файлы должны открываться в «дво- ичном режиме», и операции должны выполняться над строками байтов.
    Типичной ошибкой является попытка вывести данные в файл или в поток ввода-вывода, открытый не в том режиме. Например:
    >>> f = open(“foo.txt”,”wb”)
    >>>
    1   ...   67   68   69   70   71   72   73   74   ...   82


    написать администратору сайта