Классы в python

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/.

Constructors in Python

Class functions that begin with double underscore are called special functions as they have special meaning.

Of one particular interest is the function. This special function gets called whenever a new object of that class is instantiated.

This type of function is also called constructors in Object Oriented Programming (OOP). We normally use it to initialize all the variables.

Output

2+3j
(5, 0, 10)
Traceback (most recent call last):
  File "<string>", line 27, in <module>
    print(num1.attr)
AttributeError: 'ComplexNumber' object has no attribute 'attr'

In the above example, we defined a new class to represent complex numbers. It has two functions, to initialize the variables (defaults to zero) and to display the number properly.

An interesting thing to note in the above step is that attributes of an object can be created on the fly. We created a new attribute attr for object num2 and read it as well. But this does not create that attribute for object num1.

9.4. Некоторые замечания

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

На атрибуты данных могут ссылаться методы, а также обычные пользовательские («клиенты») объекты. Другими словами, классы не могут быть использованы для реализации чисто абстрактных типов данных. На самом деле ничто в Python не позволяет обеспечить соблюдение сокрытия данных — все что есть основано лишь на соглашениях. (С другой стороны, реализация Python, написанная на C, может полностью скрыть детали реализации и контроль доступа к объекту при необходимости; это может быть использовано расширениями Python, написанными на C.)

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

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

Не существует сокращений для того, чтобы сослаться на атрибуты данных (или другие методы!) изнутри методов. Я считаю, что это на самом деле повышает удобство чтения методов: нет шансов запутаться в локальных переменных и переменных экземпляра, когда просматриваешь методы.

Часто первый аргумент метода называется . Это не более, чем соглашение: имя не имеет абсолютно никакого особого значение для Python. Однако следует отметить, что если не следовать соглашению, то ваш код может быть менее читаемым для других программистов Python, и также возможно, что класс browser программы может быть написан, полагаясь на такое соглашение.

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

Теперь и , и , и являются атрибутами класса C, который ссылается на функции-объекты, и, следовательно, все они являются методами экземпляров класса C — есть точный эквивалент

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

Методы могут вызывать другие методы путем использования аргумента :

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

Каждое значение является объектом, и поэтому имеет класс (также называемый его типом). Он хранится как .

Об этом курсе

Недавно просмотрено: 67,170

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

Классические книги по паттернам проектирования описывают их реализацию на C++, C#, Java. У языка Python есть своя специфика из-за которой он отлично подходит для использования паттернов проектирования.

Сертификат, ссылками на который можно делиться с другими людьми

Сертификат, ссылками на который можно делиться с другими людьми Получите сертификат по завершении

100% онлайн

100% онлайн Начните сейчас и учитесь по собственному графику.


Специализация

Курс 2 из 4 в программе Специализация Программирование на Python

Гибкие сроки

Гибкие сроки Назначьте сроки сдачи в соответствии со своим графиком.

Промежуточный уровень Промежуточный уровень

Часов на завершение Прибл. 27 часов на выполнение

Доступные языки

Русский Субтитры: Русский

Overview of OOP Terminology

  • Class − A user-defined prototype for an object that defines a set of attributes that characterize any object of the class. The attributes are data members (class variables and instance variables) and methods, accessed via dot notation.

  • Class variable − A variable that is shared by all instances of a class. Class variables are defined within a class but outside any of the class’s methods. Class variables are not used as frequently as instance variables are.

  • Data member − A class variable or instance variable that holds data associated with a class and its objects.

  • Function overloading − The assignment of more than one behavior to a particular function. The operation performed varies by the types of objects or arguments involved.

  • Instance variable − A variable that is defined inside a method and belongs only to the current instance of a class.

  • Inheritance − The transfer of the characteristics of a class to other classes that are derived from it.

  • Instance − An individual object of a certain class. An object obj that belongs to a class Circle, for example, is an instance of the class Circle.

  • Instantiation − The creation of an instance of a class.

  • Method − A special kind of function that is defined in a class definition.

  • Object − A unique instance of a data structure that’s defined by its class. An object comprises both data members (class variables and instance variables) and methods.

  • Operator overloading − The assignment of more than one function to a particular operator.

Indentation

Use 4 spaces per indentation level.

Continuation lines should align wrapped elements either vertically using Python’s implicit line joining inside parentheses, brackets and braces, or using a hanging indent . When using a hanging indent the following should be considered; there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line:

# Correct:

# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Add 4 spaces (an extra level of indentation) to distinguish arguments from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# Hanging indents should add a level.
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)
# Wrong:

# Arguments on first line forbidden when not using vertical alignment.
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Further indentation required as indentation is not distinguishable.
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

The 4-space rule is optional for continuation lines.

Optional:

# Hanging indents *may* be indented to other than 4 spaces.
foo = long_function_name(
  var_one, var_two,
  var_three, var_four)

When the conditional part of an if-statement is long enough to require that it be written across multiple lines, it’s worth noting that the combination of a two character keyword (i.e. if), plus a single space, plus an opening parenthesis creates a natural 4-space indent for the subsequent lines of the multiline conditional. This can produce a visual conflict with the indented suite of code nested inside the if-statement, which would also naturally be indented to 4 spaces. This PEP takes no explicit position on how (or whether) to further visually distinguish such conditional lines from the nested suite inside the if-statement. Acceptable options in this situation include, but are not limited to:

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

(Also see the discussion of whether to break before or after binary operators below.)

The closing brace/bracket/parenthesis on multiline constructs may either line up under the first non-whitespace character of the last line of list, as in:

my_list = 
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

or it may be lined up under the first character of the line that starts the multiline construct, as in:

F-строки (Python 3.6+)

Сложно делать что-либо без строк в Python и чтобы сохранить адекватность, вам нужно иметь структурированный способ работы со строками. Большая часть людей, работающих с Python, предпочитают метод .

Python

user = «Андрей» action = «покупка»

log_message = ‘Пользователь {} зашел на сайт и выполнил действие: {}’.format( user, action )

print(log_message) # Пользователь Андрей зашел на сайт и выполнил действие: покупка

1 2 3 4 5 6 7 8 9 10

user=»Андрей»

action=»покупка»

log_message=’Пользователь {} зашел на сайт и выполнил действие: {}’.format(

user,

action

)  

print(log_message)

# Пользователь Андрей зашел на сайт и выполнил действие: покупка

Наряду с , Python 3 предоставляет гибкий способ выполнения интерполяции строк через f-строки. Тот же код, что и показанный выше, с использованием f-strings выглядит так:

Python

user = «Юрий» action = «продажа»

log_message = f’Пользователь {user} зашел на сайт и выполнил действие: {action}’

print(log_message) # Пользователь Юрий зашел на сайт и выполнил действие: продажа

1 2 3 4 5 6 7

user=»Юрий»

action=»продажа»

log_message=f’Пользователь {user} зашел на сайт и выполнил действие: {action}’

print(log_message)

# Пользователь Юрий зашел на сайт и выполнил действие: продажа

cmath[править]

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

Причина, по которой имеются два таких схожих модуля, в том, что многим пользователям не нужны комплексные числа или они просто не знают что это такое. В этих случаях будет даже лучше, если при math.sqrt(-1) будет возбуждено исключение, чем будет найдено комплексное решение. При этом отметим, что функции в модуле всегда возвращают комплексное число, даже если исходные числа не содержат мнимой части.

Переход к полярным координатам и обратноправить

Комплексное число z может быть представлено в Декартовой системе координат в представлении, что действительная z.real часть откладывается по оси x, а мнимая z.imag — по оси y. Само число z записывается:

z = z.real + z.imag*1j

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

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

  • cmath.phase

    Возвращает фазовый угол φ для числа x, phase(x) эквивалентно math.atan2(x.imag, x.real). Результат лежит в интервале .

    (x)
  • cmath.polar

    Возвращает представление x в полярных координатах, то есть возвращает пару (r, phi).

    (x)
  • cmath.rect(r, phi)

    Возвращает обычное комплексное представление x из представления в полярных координатах.

    (x)

Другие функцииправить

Модуль содержит также ряд функций, с которыми мы ознакомились в модуле math, имеющими то же применение не только к действительным, но и к комплексным числам:

Константыправить

  • cmath.pi
  • cmath.e

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

Почему это так противоречиво?


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

К сожалению, все не так просто. Прежде всего, мы сталкиваемся с проблемой, с которой сталкивается каждая микросервисно-ориентированная архитектура, то есть с риском перехода от «божественных» объектов (экстремальная монолитная архитектура) к почти пустым объектам (экстремально распределенный подход), обременяя программиста слишком тонким детальным контролем, который в конечном итоге приводит к созданию системы, в которой отношения между объектами настолько сложны, что становится невозможным понять влияние изменений в коде.

Однако в множественном наследовании существует более насущная проблема. Как это происходит с естественным наследованием, родители могут предоставить одну и ту же «генетическую черту» в двух разных вариантах, но у получающегося в результате этого человека будет только одна. Оставляя в стороне генетику (которая невероятно сложнее, чем программирование) и возвращаясь к ООП, мы сталкиваемся с проблемой, когда объект наследуется от двух других объектов, которые предоставляют тот же атрибут.

Итак, если ваш класс Child наследует от родителей Parent1 и Parent2, и оба предоставляют метод __init__, какой из них следует использовать вашему объекту?

class Parent1():
    def __init__(self):
        


class Parent2():
    def __init__(self):
        


class Child(Parent1, Parent2):
    # наследуется Parent1 и Parent2, какой __init__ будет использоваться?
    pass


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

class Parent1:
    def __init__(self, status):
        


class Parent2:
    def __init__(self, name):
        


class Child(Parent1, Parent2):
    # какой __init__ используется?
    pass


Проблема может быть расширена еще дальше, введя общего предка выше Parent1 и Parent2.

class Ancestor:
    def __init__(self):
        


class Parent1(Ancestor):
    def __init__(self, status):
        


class Parent2(Ancestor):
    def __init__(self, name):
        


class Child(Parent1, Parent2):
    pass


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

д.), Важной частью является то, что он является общим для Parent1 и Parent2. Это так называемая проблема алмаза, так как граф наследования имеет форму ромба

Таким образом, в то время как при наследовании с одним родителем правила просты, с множественным наследованием у нас сразу возникает более сложная ситуация, в которой нет тривиального решения. Помогает ли все это реализовать множественное наследование?

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

В python всё — объекты.

*Аудитория в шоке, особо нервные дамочки падают в обморок*

  • Числа — объекты
  • Строки — объекты
  • Списки — объекты
  • Классы — объекты

Если говорить просто, то «объекты» — это некая структура.

И было слово…

  • Класс — это схема, описывающая нашу структуру, возможные внутри неё данные и присущие ей методы.
  • Метод — это функция. Т.е. метод объекта — это функция, описанная внутри объекта, и присущая этому объекту. Метод — это функция, которая действует на объекты данного вида. Для удобства у разных видов объектов могут быть методы с одинаковыми именами, работающие по разному, но схожим образом.
  • Экземпляр — это конкретный объект, созданный из класса.

Класс как модуль

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

>>> class B:
...     n = 5
...     def adder(v):
...             return v + B.n
... 
>>> B.n
5
>>> B.adder(4)
9

Однако в случае классов используется немного иная терминология. Пусть имена, определенные в классе, называются атрибутами этого класса. В примере имена и – это атрибуты класса . Атрибуты-переменные часто называют полями или свойствами. Свойством является . Атрибуты-функции называются методами. Методом в классе является . Количество свойств и методов в классе может быть любым.

OrderedDict

Модуль Python collections имеет еще один замечательный наследуемый класс dict под названием OrderedDict. Как подразумевается в его названии, этот словарь отслеживает порядок ключей после их добавления. Если вы создадите обычный dict, вы заметите, что данные в нем неупорядоченные:

Python

d = {‘banana’: 3, ‘apple’:4, ‘pear’: 1, ‘orange’: 2} print(d) # {‘apple’: 4, ‘banana’: 3, ‘orange’: 2, ‘pear’: 1}

1 2 3

d={‘banana’3,’apple’4,’pear’1,’orange’2}

print(d)

# {‘apple’: 4, ‘banana’: 3, ‘orange’: 2, ‘pear’: 1}

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

Python

d = {‘banana’: 3, ‘apple’:4, ‘pear’: 1, ‘orange’: 2}

keys = d.keys() keys = sorted(keys)

for key in keys: print (key, d)

1 2 3 4 5 6 7

d={‘banana’3,’apple’4,’pear’1,’orange’2}

keys=d.keys()

keys=sorted(keys)

forkey inkeys

print(key,dkey)

Результат

Python

apple 4 banana 3 orange 2 pear 1

1 2 3 4

apple4

banana3

orange2

pear1

Давайте создадим экземпляр OrderedDict, используя оригинал dict, но на этапе создания мы отсортируем ключи в этом словаре:

Python

from collections import OrderedDict

d = {‘banana’: 3, ‘apple’:4, ‘pear’: 1, ‘orange’: 2} new_d = OrderedDict(sorted(d.items()))

print(new_d) # OrderedDict()

for key in new_d: print (key, new_d)

1 2 3 4 5 6 7 8 9 10

fromcollectionsimportOrderedDict

d={‘banana’3,’apple’4,’pear’1,’orange’2}

new_d=OrderedDict(sorted(d.items()))

print(new_d)

# OrderedDict()  

forkey innew_d

print(key,new_dkey)

Результат

Python

apple 4 banana 3 orange 2 pear 1

1 2 3 4


apple4

banana3

orange2

pear1

Здесь мы создали наш OrderedDict, сортируя его при помощи встроенной функции Python sorted. Функция sorted берет объекты словаря, который является списком кортежей, отображающих пары ключей словаря. Данная функция сортирует их, затем передает в OrderedDict, который сохраняет указанный порядок. Таким образом, когда мы выводим ключи и значения, они будут в том порядке, который мы и ожидаем. Если вы создадите цикл над обычным словарем (с неотсортированным списком ключей), порядок будет меняться каждый раз

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

Обычный словарь только смотрит на содержимое словаря, не обращая никакого внимание на порядок этого содержимого. Наконец, OrderedDicts содержит два новых метода в Python 3: popitem и move_to_end.

  • Метод popitem возвращает и удаляет пары (ключей или объектов).
  • Метод move_to_end двигает существующий ключ в любой конец OrderedDict. Объект будет смещен в правый угол, если последний аргумент OrderedDict указан как True (это по умолчанию), или в начало, если он указан как False.

Любопытно, но OrderedDicts поддерживает обратную итерацию, используя встроенную функцию reversed:

Python

for key in reversed(new_d): print (key, new_d)

1 2

forkey inreversed(new_d)

print(key,new_dkey)

Результат

Python

pear 1 orange 2 banana 3 apple 4

1 2 3 4

pear1

orange2

banana3

apple4

Весьма точно, однако, вероятно вам такой функционал не понадобится.

deque

В соответствии с документацией Python, deque – это обобщение стеков и очередей. Они являются контейнером замен для списка Python. Они защищены от потоков и поддерживают эффективность соединения памяти, а также сноски с обеих сторон deque. Список оптимизирован под быстрые операции с фиксированной длиной. За всеми подробностями можете обратиться к . Наш deque поддерживает аргумент maxlen, который устанавливает границы для deque. В противном случае deque будет расти до произвольных размеров. Когда ограниченный deque заполнен, любые новые объекты, которые были добавлены, вызовут такое же количество элементов, которые выскочат с другого конца. Вот основное правило: если вам нужно что-то быстро дописать или вытащить, используйте deque. Если вам нужен быстрый случайный доступ, используйте list. Давайте уделим пару минут, и посмотрим, как мы можем создавать и использовать deque.

Python

from collections import deque import string

d = deque(string.ascii_lowercase) for letter in d: print(letter)

1 2 3 4 5 6

fromcollectionsimportdeque

importstring

d=deque(string.ascii_lowercase)

forletter ind

print(letter)

Здесь мы импортируем deque из нашего модуля collections, а также модуль string. Для того, чтобы создать экземпляр deque, нам нужно передать его итерируемой. В данном случае, мы передали его string.ascii_lowercase, и получили список всех строчных букв в алфавите. Наконец, мы сделали цикл над deque и вывели каждый объект. Теперь давайте взглянем на несколько методов, которыми обладает deque.

Python

d.append(‘bork’) print(d)

# deque()

d.appendleft(‘test’) print(d)

# deque()

d.rotate(1) print(d)

# deque()

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

d.append(‘bork’)

print(d)

  # deque()  

d.appendleft(‘test’)

print(d)

  # deque()  

d.rotate(1)

print(d)

  # deque()

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

Python

from collections import deque

def get_last(filename, n=5): «»» Возвращаем последние N кол-во строк из файла «»» try: with open(filename) as f: return deque(f, n) except OSError: print(«Файл не открывается: {}».format(filename)) raise

1 2 3 4 5 6 7 8 9 10 11 12 13

fromcollectionsimportdeque

defget_last(filename,n=5)

«»»

    Возвращаем последние N кол-во строк из файла     «»»

try

withopen(filename)asf

returndeque(f,n)

exceptOSError

print(«Файл не открывается: {}».format(filename))

raise

Этот код работает по схожему принципу с программой-хвостом Linux. Здесь мы передаем имя файла нашему скрипту вместе с n количеством строк, которые мы хотим вернуть. Наш deque ограничен той или иной цифрой, которую мы указываем как n. Это значит, что как только deque заполнится, когда новые строки прочитаны и добавлены в deque, старые строки выпадают из другого конца и отбрасываются. Я также завернул открываемый в операторе файл в простой обработчик исключений, так как очень легко выполнить передачу по неверному пути. Таким образом, мы поймаем несуществующие файлы, к примеру. Теперь мы готовы идти дальше и приступить к изучению namedtuple.

Заключение

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

Теперь вы можете:

  • Упростите циклы и вызовы map() с помощью использования декларативный представлений
  • Использовать условную логику в представление
  • Создать set и dictionary представления
  • Определить, когда ясность кода или производительность диктует альтернативный подход

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

Помните, что хотя list comprehensions привлекает к себе большое внимание, ваша интуиция и способность использовать расчетные данные, помогут вам написать чистый код, который выполняет поставленную задачу. Это, в конечном счете, ключ к созданию вашего кода Pythonic!


С этим читают