Как эффективно использовать классы python

Увеличение объема памяти: полный успех

Связанные, несвязанные и статические методы

Идея связанных и несвязанных методов был удален в Python 3 . В Python 3 при объявлении метода в классе, вы используете ключевое слово, тем самым создавая объект функции. Это обычная функция, и окружающий класс работает как пространство имен. В следующем примере мы указываем метод в пределах класса , и это становится функцией :

класс A (объект): def f (self, x): return 2 * x Af #  (в Python 3.x)

В Python 2 поведение отличается: объекты функций внутри класса были неявно заменены объектами типа , которые назывались несвязанных метода , потому что они не были связаны с каким — либо конкретным экземпляром класса. Удалось получить доступ к основной функции с помощью свойства.

Af #  (в Python 2.x) Af__class__ #  Af__func__ #

Последнее поведение подтверждается проверкой — методы распознаются как функции в Python 3, в то время как различие поддерживается в Python 2.

импорт inspect inspect.isfunction (Af) # True inspect.ismethod (Af) # False  импорт inspect inspect.isfunction (Af) # False inspect.ismethod (Af) # True

В обеих версиях функции Python / метод может быть вызван непосредственно, при условии , что вы передаете экземпляр класса в качестве первого аргумента.

Теперь предположим , что является экземпляром класса , что тогда? Ну, интуитивно это должно быть тем же самым методом класса , только он должен каким — то образом «знает» , что он был применен к объекту — в Python это называется метод , связанный с .

В суровых буднях детали следующим образом : запись вызывает магический метод , который сначала проверяет , является ли имеет атрибут с именем (не), а затем проверяет , класс , содержит ли это метод с таким именем (он делает), и создает новый объект типа , который имеет ссылку на исходные в и ссылку на объект в . Когда этот объект вызывается как функция, он просто выполняет следующие действия : . Таким образом , этот объект называется связанный метод потому , что при вызове он знает , чтобы поставить объект был привязан к качестве первого аргумента. (Эти вещи работают одинаково в Python 2 и 3).

Наконец, Python имеет методы класса и статические методы — специальные виды методов. Методы класса работают точно так же , как и обычные методы, за исключением того, что при вызове на объекте они связываются с классом объекта , а не к объекту. Таким образом , . При вызове такого связанного метода, он проходит класс в качестве первого аргумента. Статические методы еще проще: они вообще ничего не связывают и просто возвращают базовую функцию без каких-либо преобразований.

Обратите внимание, что методы класса привязаны к классу даже при обращении к экземпляру:

Стоит отметить , что на самом низком уровне, функции, методы, staticmethods и т.д., на самом деле дескрипторы , которые вызывают , и , возможно , `del__` специальные методы. Для более подробной информации о методах классов и статических методах:

9.5. Inheritance¶

Of course, a language feature would not be worthy of the name “class” without
supporting inheritance. The syntax for a derived class definition looks like
this:

class DerivedClassName(BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>

The name must be defined in a scope containing the
derived class definition. In place of a base class name, other arbitrary
expressions are also allowed. This can be useful, for example, when the base
class is defined in another module:

class DerivedClassName(modname.BaseClassName):

Execution of a derived class definition proceeds the same as for a base class.
When the class object is constructed, the base class is remembered. This is
used for resolving attribute references: if a requested attribute is not found
in the class, the search proceeds to look in the base class. This rule is
applied recursively if the base class itself is derived from some other class.

There’s nothing special about instantiation of derived classes:
creates a new instance of the class. Method references
are resolved as follows: the corresponding class attribute is searched,
descending down the chain of base classes if necessary, and the method reference
is valid if this yields a function object.

Derived classes may override methods of their base classes. Because methods
have no special privileges when calling other methods of the same object, a
method of a base class that calls another method defined in the same base class
may end up calling a method of a derived class that overrides it. (For C++
programmers: all methods in Python are effectively .)

An overriding method in a derived class may in fact want to extend rather than
simply replace the base class method of the same name. There is a simple way to
call the base class method directly: just call . This is occasionally useful to clients as well. (Note that this
only works if the base class is accessible as in the global
scope.)

Python has two built-in functions that work with inheritance:

  • Use to check an instance’s type:
    will be only if is or some class
    derived from .

  • Use to check class inheritance:
    is since is a subclass of . However,
    is since is not a
    subclass of .

Переменные класса или переменные экземпляра?

Когда переменная определяется на уровне класса, она называется переменной класса. Когда переменная определяется в конструкторе, она называется переменной экземпляра.

Переменные класса являются общими для всех экземпляров класса, тогда как переменные экземпляра уникальны для экземпляра

Итак, очень важно понимать, когда использовать переменную класса, а когда — переменную экземпляра

В предыдущих примерах атрибут employee_id уникален для экземпляра Employee, поэтому лучше иметь его в качестве переменной экземпляра и определять в конструкторе.

Предположим, мы хотим отслеживать количество созданных экземпляров сотрудников и выделенных идентификаторов сотрудников. В этом случае мы можем использовать переменные класса для хранения этих данных и обновления экземплярами.

class Employee:
    count = 0
    ids_list = []

    def __init__(self, i):
        self.id = i
        Employee.count += 1
        self.ids_list.append(i)


for x in range(0, 10):
    emp = Employee(x)

print(f'Number of employees created = {Employee.count}')
print(f'List of employee ids allocated = {Employee.ids_list}')

emp = Employee(1000)
print(f'List of employee ids allocated = {emp.ids_list}')

Выход:

Number of employees created = 10
List of employee ids allocated = 
List of employee ids allocated = 

Примечание: мы можем получить доступ к переменным класса через имя класса, а также через переменную экземпляра.

9.8. Iterators¶

By now you have probably noticed that most container objects can be looped over
using a statement:

for element in 1, 2, 3]:
    print(element)
for element in (1, 2, 3):
    print(element)
for key in {'one'1, 'two'2}:
    print(key)
for char in "123"
    print(char)
for line in open("myfile.txt"):
    print(line, end='')

This style of access is clear, concise, and convenient. The use of iterators
pervades and unifies Python. Behind the scenes, the statement
calls on the container object. The function returns an iterator
object that defines the method which accesses
elements in the container one at a time. When there are no more elements,
raises a exception which tells the
loop to terminate. You can call the method
using the built-in function; this example shows how it all works:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

Having seen the mechanics behind the iterator protocol, it is easy to add
iterator behavior to your classes. Define an method which
returns an object with a method. If the class
defines , then can just return :

class Reverse
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 
            raise StopIteration
        self.index = self.index - 1
        return self.dataself.index

8.8. Coroutines¶

New in version 3.5.

8.8.1. Coroutine function definition

async_funcdef ::=  [] "async" "def"  "(" [] ")"
                    ":" 

Execution of Python coroutines can be suspended and resumed at many points
(see ). Inside the body of a coroutine function, and
identifiers become reserved keywords; expressions,
and can only be used in
coroutine function bodies.

Functions defined with syntax are always coroutine functions,
even if they do not contain or keywords.

It is a to use a expression inside the body
of a coroutine function.

An example of a coroutine function:

async def func(param1, param2):
    do_stuff()
    await some_coroutine()

8.8.2. The statement

async_for_stmt ::=  "async" 

An is able to call asynchronous code in its
iter implementation, and can call asynchronous
code in its next method.

The statement allows convenient iteration over asynchronous
iterators.

The following code:

async for TARGET in ITER
    SUITE
else
    SUITE2

Is semantically equivalent to:

iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True

while running
    try
        TARGET = await type(iter).__anext__(iter)
    except StopAsyncIteration
        running = False
    else
        SUITE
else
    SUITE2

See also and for details.

It is a to use an statement outside the
body of a coroutine function.

8.8.3. The statement

async_with_stmt ::=  "async" 

An is a that is
able to suspend execution in its enter and exit methods.

The following code:

async with EXPRESSION as TARGET
    SUITE

is semantically equivalent to:

manager = (EXPRESSION)
aenter = type(manager).__aenter__
aexit = type(manager).__aexit__
value = await aenter(manager)
hit_except = False

try
    TARGET = value
    SUITE
except
    hit_except = True
    if not await aexit(manager, *sys.exc_info()):
        raise
finally
    if not hit_except
        await aexit(manager, None, None, None)

See also and for details.

It is a to use an statement outside the
body of a coroutine function.

See also

PEP 492 — Coroutines with async and await syntax

The proposal that made coroutines a proper standalone concept in Python,
and added supporting syntax.

Footnotes

The exception is propagated to the invocation stack unless
there is a clause which happens to raise another
exception. That new exception causes the old one to be lost.

A string literal appearing as the first statement in the function body is
transformed into the function’s attribute and therefore the
function’s .

A string literal appearing as the first statement in the class body is
transformed into the namespace’s item and therefore the class’s
.

Обработка после инициализации

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

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

Например, добавим сгенерированное описание книги

Параметры только для инициализации

Одна из возможностей, связанных с методом — параметры, используемые только для инициализации. Если при объявления поля указать в качестве его типа , его значение будет передано как параметр метода . Никак по-другому такие поля не используются в классе данных.

свойства

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

Объекта , класса , будет иметь имеют свойство , однако его поведение теперь жестко контролируется:

Помимо полезного синтаксиса, описанного выше, синтаксис свойства позволяет проверять или добавлять другие дополнения к этим атрибутам. Это может быть особенно полезно с общедоступными API-интерфейсами, где пользователю должен быть предоставлен определенный уровень помощи.

Другое распространенное использование свойств — это предоставление классу возможности представлять «виртуальные атрибуты» — атрибуты, которые на самом деле не хранятся, но вычисляются только по запросу.

Python Tutorial

Python HOMEPython IntroPython Get StartedPython SyntaxPython CommentsPython Variables
Python Variables
Variable Names
Assign Multiple Values
Output Variables
Global Variables
Variable Exercises

Python Data TypesPython NumbersPython CastingPython Strings
Python Strings
Slicing Strings
Modify Strings
Concatenate Strings
Format Strings
Escape Characters
String Methods
String Exercises

Python BooleansPython OperatorsPython Lists
Python Lists
Access List Items
Change List Items
Add List Items
Remove List Items
Loop Lists
List Comprehension
Sort Lists
Copy Lists
Join Lists
List Methods
List Exercises

Python Tuples
Python Tuples
Access Tuples
Update Tuples
Unpack Tuples
Loop Tuples
Join Tuples
Tuple Methods
Tuple Exercises

Python Sets
Python Sets
Access Set Items
Add Set Items
Remove Set Items
Loop Sets
Join Sets
Set Methods
Set Exercises

Python Dictionaries
Python Dictionaries
Access Items
Change Items
Add Items
Remove Items
Loop Dictionaries
Copy Dictionaries
Nested Dictionaries
Dictionary Methods
Dictionary Exercise

Python If…ElsePython While LoopsPython For LoopsPython FunctionsPython LambdaPython ArraysPython Classes/ObjectsPython InheritancePython IteratorsPython ScopePython ModulesPython DatesPython MathPython JSONPython RegExPython PIPPython Try…ExceptPython User InputPython String Formatting

Возвращает тип объекта и является собственным метаклассом языка Python.

Параметры:

  • — объект, тип которого определяется
  • — имя для создаваемого типа
  • — кортеж с родительскими классами
  • — словарь, будет являться пространством имён для тела класса

Возвращаемое значение:

  • тип объекта, при ,
  • объект нового типа при .

Вызов класса с одним аргументом:

Класс с одним аргументом возвращает тип объекта. Возвращаемое значение — это как правило, тот же объект, что и возвращаемый .

Рекомендуется для проверки типа объекта использовать встроенную функцию , так как она принимает во внимание подклассы

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

>>> x = 1
>>> type(x)
# <class 'int'>

>>> x = 1, 2, 3
>>> type(x)
# <class 'list'>

# проверка типа объекта
>>> x = 1
>>> isinstance(x, int)
# True
>>> x = 1, 2, 3
>>> isinstance(x, list)
# True

Вызов класса с тремя аргументами:

Класс с тремя аргументами вернет объект нового типа. Это по сути динамическая форма инструкции , ее еще называют метакласс.

Другими словами класс , вызванный с тремя аргументами на самом деле ! Класс это метакласс, который Python внутренне использует для создания всех классов.

Все, с чем имеем дело в Python, является объектом. Сюда входят функции и классы целые числа, строки и т.д. Все они объекты. И все они созданы из класса.

# type - это тип всех типов, для 
# которых не указан явно иной метакласс
>>> type(type)
# <class 'type'>
>>> type(object)
# <class 'type'>
>>> type(list)
# <class 'type'>
>>> type(int)
# <class 'type'>
>>> class Bar(object): pass
>>> type(Bar)
# <class 'type'>

В общем — это класс всех классов в языке Python и является собственным метаклассом. Класс нельзя воспроизвести на чистом Python.

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

Понятия класс и тип по сути являются синонимами. Пользовательские типы данных могут быть сконструированы налету, во время исполнения, при помощи вызова с тремя аргументами или определены в коде, например при помощи инструкции .

Важно понимать, что тип, как и другие сущности в Python, тоже является объектом. Изменено в Python 3.6: подклассы, которые не переопределяют, больше не могут использовать форму с одним аргументом для получения типа объекта

Изменено в Python 3.6: подклассы, которые не переопределяют, больше не могут использовать форму с одним аргументом для получения типа объекта.

Источники

«Голое» исключение

Есть еще один способ поймать ошибку:

Python

try:
1 / 0
except:
print(«You cannot divide by zero!»)

1
2
3
4

try

1

except

print(«You cannot divide by zero!»)

Но мы его не рекомендуем. На жаргоне Пайтона, это известно как голое исключение, что означает, что будут найдены вообще все исключения. Причина, по которой так делать не рекомендуется, заключается в том, что вы не узнаете, что именно за исключение вы выловите. Когда у вас возникло что-то в духе ZeroDivisionError, вы хотите выявить фрагмент, в котором происходит деление на ноль. В коде, написанном выше, вы не можете указать, что именно вам нужно выявить. Давайте взглянем еще на несколько примеров:

Python

my_dict = {«a»:1, «b»:2, «c»:3}

try:
value = my_dict
except KeyError:
print(«That key does not exist!»)

1
2
3
4
5
6

my_dict={«a»1,»b»2,»c»3}

try

value=my_dict»d»

exceptKeyError

print(«That key does not exist!»)

Python

my_list =

try:
my_list
except IndexError:
print(«That index is not in the list!»)

1
2
3
4
5
6

my_list=1,2,3,4,5

try

my_list6

exceptIndexError

print(«That index is not in the list!»)

В первом примере, мы создали словарь из трех элементов. После этого, мы попытались открыть доступ ключу, которого в словаре нет. Так как ключ не в словаре, возникает KeyError, которую мы выявили. Второй пример показывает список, длина которого состоит из пяти объектов. Мы попытались взять седьмой объект из индекса.

Помните, что списки в Пайтоне начинаются с нуля, так что когда вы говорите 6, вы запрашиваете 7. В любом случае, в нашем списке только пять объектов, по этой причине возникает IndexError, которую мы выявили. Вы также можете выявить несколько ошибок за раз при помощи одного оператора. Для этого существует несколько различных способов. Давайте посмотрим:

Python

my_dict = {«a»:1, «b»:2, «c»:3}

try:
value = my_dict
except IndexError:
print(«This index does not exist!»)
except KeyError:
print(«This key is not in the dictionary!»)
except:
print(«Some other error occurred!»)

1
2
3
4
5
6
7
8
9
10

my_dict={«a»1,»b»2,»c»3}

try

value=my_dict»d»

exceptIndexError

print(«This index does not exist!»)

exceptKeyError

print(«This key is not in the dictionary!»)

except

print(«Some other error occurred!»)

Это самый стандартный способ выявить несколько исключений. Сначала мы попробовали открыть доступ к несуществующему ключу, которого нет в нашем словаре. При помощи try/except мы проверили код на наличие ошибки KeyError, которая находится во втором операторе except

Обратите внимание на то, что в конце кода у нас появилась «голое» исключение. Обычно, это не рекомендуется, но вы, возможно, будете сталкиваться с этим время от времени, так что лучше быть проинформированным об этом

Кстати, также обратите внимание на то, что вам не нужно использовать целый блок кода для обработки нескольких исключений. Обычно, целый блок используется для выявления одного единственного исключения. Изучим второй способ выявления нескольких исключений:

Python

try:
value = my_dict
except (IndexError, KeyError):
print(«An IndexError or KeyError occurred!»)

1
2
3
4

try

value=my_dict»d»

except(IndexError,KeyError)

print(«An IndexError or KeyError occurred!»)

Обратите внимание на то, что в данном примере мы помещаем ошибки, которые мы хотим выявить, внутри круглых скобок. Проблема данного метода в том, что трудно сказать какая именно ошибка произошла, так что предыдущий пример, мы рекомендуем больше чем этот

Зачастую, когда происходит ошибка, вам нужно уведомить пользователя, при помощи сообщения.

В зависимости от сложности данной ошибки, вам может понадобиться выйти из программы. Иногда вам может понадобиться выполнить очистку, перед выходом из программы. Например, если вы открыли соединение с базой данных, вам нужно будет закрыть его, перед выходом из программы, или вы можете закончить с открытым соединением. Другой пример – закрытие дескриптора файла, к которому вы обращаетесь. Теперь нам нужно научиться убирать за собой. Это очень просто, если использовать оператор finally.

Атрибут __dict__

В Python у объектов есть встроенные специальные атрибуты. Мы их не определяем, но они есть. Одним из таких атрибутов объекта является свойство __dict__. Его значением является словарь, в котором ключи – это имена свойств экземпляра, а значения – текущие значения свойств.

>>> class B:
...     n = 5
...     def adder(self, v):
...             return v + self.n
... 
>>> w = B()
>>> w.__dict__
{}
>>> w.n = 8
>>> w.__dict__
{'n': 8}

В примере у экземпляра класса B сначала нет собственных атрибутов. Свойство и метод – это атрибуты объекта-класса, а не объекта-экземпляра, созданного от этого класса. Лишь когда мы выполняем присваивание новому полю экземпляра, у него появляется собственное свойство, что мы наблюдаем через словарь __dict__.

В следующем уроке мы увидим, что свойства экземпляра обычно не назначаются за пределами класса. Это происходит в методах классах путем присваивание через self. Например, .

Атрибут __dict__ используется для просмотра всех текущих свойств объекта. С его помощью можно удалять, добавлять свойства, а также изменять их значения.

>>> w.__dict__ = 100
>>> w.__dict__
{'n': 8, 'm': 100}
>>> w.m
100

9.6. Приватные переменные

В Python не существует «частных» (приватных) переменных экземпляра, т.е. тех, которые не могут быть доступны, кроме как изнутри объекта. Тем не менее есть соглашение, которое поддерживается большей частью кода Python: идентификатор с префиксом нижней черты (например ) должны рассматриваться как непубличная часть API (будь то функция, метод или элемент данных). Следует учитывать, детали реализации и предмет могут быть изменены без предварительного уведомления.

Поскольку есть действительные прецеденты для приватных членов класса (а именно, чтобы избежать конфликтов имен с именами, определенными подклассами), есть ограниченная поддержка такого механизма, называемого корректировкой имен (name mangling). Любой идентификатор вида (по крайней мере с двумя первыми подчеркиваниями и не более чем одним завершающим) текстуально заменяются на , где — это текущее имя класса с начальным символом(ами) подчеркивания. Эта корректировка делается безотносительно к синтаксической позиции идентификатора до тех пор, пока это происходит в определении класса.

Корректировка имен полезна для того, чтобы позволить подклассам переопределять методы, не нарушая внутриклассовых вызовов методов. Например:

Хотя в основном правила корректировки предназначены для избежания несчастных случаев, но все равно можно получить доступ или изменить переменную, которая считается приватной. Это даже может быть полезно при особых обстоятельствах, например, в отладчике.

Обратите внимание, что код, передающийся или , не учитывает имя класса вызывающего класса к текущему классу; это похоже на эффект оператора , эффект, который также ограничивается кодом, который байт-скомпилированный вместе. То же ограничение применяется к , и , а также при обращении к напрямую

Множественное наследование

Python использует C3 линеаризацию алгоритм для определения порядка , в котором для решения атрибутов класса, включая методы. Это известно как Порядок разрешения методов (MRO).

Вот простой пример:

Теперь, если мы создаем экземпляр FooBar, если мы ищем атрибут foo, мы видим, что атрибут Foo находится первым

а также

Вот MRO FooBar:

Можно просто сказать, что алгоритм Python MRO

  1. Глубина первого (например , затем ) , если
  2. общий родительский ( ) блокируется ребенком ( ) и
  3. круговые отношения не допускаются.

То есть, например, Bar не может наследовать от FooBar, а FooBar наследует от Bar.

Для комплексного примера в Python см запись Википедии .

Другая характерная особенность в наследстве является . Супер может получить функции родительских классов.

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

для примера ниже Foo метод инициализировать класс вызывался класс Bar не INIT вызывался

Выход:

Но это не значит , что бар класс не наследуется. Instance конечного класса FooBar также экземпляр класса Bar и класса Foo.

Выход:

9.5. Наследование

Несомненно свойство языка не имела бы право называться «классом» без поддержки наследования. Синтаксис для определения производного класса выглядит следующим образом:

Имя должны быть определено в пределах области видимости производного класса. На месте имени базового класса также допускается иные произвольные выражения. Это может быть использовано, например, когда базовый класс определен в другом модуле:

Выполнение определения производного класса протекает так же, как для базового класса. Когда объект класса создается, базовый класс запоминается. Это используется для выяснения ссылок на атрибуты: если запрошенный атрибут не найден в классе, поиск продолжается в базовом классе. Это правило применяется рекурсивно, если сам базовый класс является производным от другого класса.

Нет ничего особенного в экземплярах производных классов: создает новый экземпляр класса. Ссылки на методы разрешаются следующим образом: требуемый атрибут класса ищется по убыванию вниз по цепочке базовых классов, если это необходимо, и ссылка на метод работает, если она дает объект функции.

Производные классы могут переопределить методы их базовых классов. Потому как методы не имеют особых привилегий при вызове других методов того же объекта, так метод базового класса, что вызывает другой метод, определенный в том же базовом классе, может в конечном итоге вызвать метод производного класса, который переопределяет его. (Для программистов на C++: все методы в Python фактически являются .)

Переопределенный метод в производном классе на самом деле может потребоваться расширить, а не просто заменить метод базового класса с тем же именем. Существует простой способ вызвать метод базового класса напрямую: просто напишите . Это также иногда полезно для клиентов. (Заметим, что это работает только если базовый класс доступен как в глобальной области видимости.)

У Python есть две встроенные функции, которые работают с наследованием:

  • Используйте isinstance(), чтобы проверить тип экземпляра: вернет , если только является int или некоторый класс, производный от int.
  • Используйте issubclass() для проверки наследования классов: есть , поскольку bool — это подкласс int. Однако, ложно, так как float не является подклассом int.

9.5.1. Множественное наследование

Python также поддерживает форму множественного наследования. Определение класса с несколькими базовыми классами выглядит следующим образом:

Для большинства целей, в простейших случаях, вы можете думать о поиске атрибутов, унаследованных от родительского класса, как сначала в глубину, затем слева-направо, не ищет дважды в том же классе, где есть совпадение в иерархии. Таким образом, если атрибут не найден в , он ищется в , затем (рекурсивно) в базовых классах , и если не был найден там, поиск будет продолжен в и так далее.

На самом деле все немного сложнее; порядок выбора метода динамически изменяется для поддержки совместных вызовов к . Такой подход известен в некоторых других языках с множественным наследованием как «вызов следующего метода» и является более мощным, чем вызов super, присутствующего в языках с одиночным наследованием.

Динамическое следование необходимо потому, что все случаи множественного наследования обладают одним или несколькими взаимосвязанными отношениями (где по крайней мере один из родительских классов может быть доступен через множество путей от самого нижнего класса). Например, все классы унаследованы от , так что любой случай множественного наследования обеспечивает более одного пути, чтобы добраться до . Чтобы сохранить базовые классы от доступа более одного раза, динамический алгоритм делает линейным порядок поиска таким образом, чтобы сохранить порядок слева-направо, указанный в каждом классе, который вызывает каждого родителя только один раз (это означает, что от класса можно создать подкласс не затрагивая порядок приоритетов его родителей). Взятые вместе эти свойства делают возможным создание надежных и расширяемых классов с множественным наследованием. Более подробно см. python.org/download/releases/2.3/mro/.

8.5. The with statement¶

The statement is used to wrap the execution of a block with
methods defined by a context manager (see section ).
This allows common ……
usage patterns to be encapsulated for convenient reuse.

with_stmt ::=  "with"  ("," )* ":" 
with_item ::=   

The execution of the statement with one “item” proceeds as follows:

  1. The context expression (the expression given in the ) is
    evaluated to obtain a context manager.

  2. The context manager’s is loaded for later use.

  3. The context manager’s is loaded for later use.

  4. The context manager’s method is invoked.

  5. If a target was included in the statement, the return value
    from is assigned to it.

    Note

    The statement guarantees that if the
    method returns without an error, then will always be
    called. Thus, if an error occurs during the assignment to the target list,
    it will be treated the same as an error occurring within the suite would
    be. See step 6 below.

  6. The suite is executed.

  7. The context manager’s method is invoked. If an exception
    caused the suite to be exited, its type, value, and traceback are passed as
    arguments to . Otherwise, three arguments are
    supplied.

    If the suite was exited due to an exception, and the return value from the
    method was false, the exception is reraised. If the return
    value was true, the exception is suppressed, and execution continues with the
    statement following the statement.

    If the suite was exited for any reason other than an exception, the return
    value from is ignored, and execution proceeds at the normal
    location for the kind of exit that was taken.

The following code:

with EXPRESSION as TARGET
    SUITE

is semantically equivalent to:

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try
    TARGET = value
    SUITE
except
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally
    if not hit_except
        exit(manager, None, None, None)

With more than one item, the context managers are processed as if multiple
statements were nested:

with A() as a, B() as b
    SUITE

is semantically equivalent to:

with A() as a
    with B() as b
        SUITE

Changed in version 3.1: Support for multiple context expressions.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector