Три «Черная магия» и «Операция Сан» на Python

Python

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

понимание списка

Несколько дней назад HR попросил меня рассказать о понимании списка. Я сказал, что часто использую его, то есть формулу для создания нового списка из старого списка. Он мне прямо отказал и попросил вернуться и пересмотреть Это удар, поэтому я решил помочь всем просмотреть его.

содержание

  • Понимание списка: старый список -> новый список
  • Понимание: понимание словаря понимание набора

1. Понимание списка:

Формат[表达式 for 变量 in 旧列表]
или[表达式 for 变量 in 旧列表 if 条件]
Пример 1: Создайте новый список с именами длиннее 3 и написанными с заглавной буквы.

names_old = ['tom', 'amy', 'daming', 'lingling']
names_new = [name.capitalize() for name in names_old if len(name) > 3]
print(names_new)

выход:

['Daming', 'Lingling']

Пример 2: (вопросы основного письменного теста Дачанга) Сгенерируйте список кортежей, требуя, чтобы каждый элемент(0-5偶数, 0-10奇数)форма. Результат:

[(0, 1), (0, 3), (0, 5), (0, 7), (0, 9), (2, 1), (2, 3), (2, 5), (2, 7), (2, 9), (4, 1), (4, 3), (4, 5), (4, 7), (4, 9)]

Для кода реализации цикла:

new_list = list()
for i in range(5):  # 偶数
    if i % 2 == 0:
        for j in range(10):  # 奇数
            if j % 2 != 0:
                new_list.append((i, j))

Код понимания списка:

new_list = [(i, j) for i in range(5) for j in range(10) if i % 2 == 0 and j % 2 != 0]

Пример 3: (вопросы основного письменного теста Дачан) Дайте список сотрудников:

employees_old = [{'name': "tmo", "salary": 4800},
                 {'name': "amy", "salary": 3800},
                 {'name': "daming", "salary": 7000},
                 {'name': "lingling", "salary": 5600}] 

Если зарплата сотрудника больше 5000, добавьте 200, в противном случае добавьте 500 и выведите новый список сотрудников.
Понимание списка:

employees_new = [employee['salary'] + 200 if employee['salary'] > 5000 else employee['salary'] + 500 for employee in employees_old]
print(employees_new)

выход:

[5300, 4300, 7200, 5800]

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

for employee in employees_old:
    if employee['salary'] > 5000:
        employee['salary'] += 200
    else:
        employee['salary'] += 500

print(employees_old)

выход:

[{'name': 'tmo', 'salary': 5300}, {'name': 'amy', 'salary': 4300}, {'name': 'daming', 'salary': 7200}, {'name': 'lingling', 'salary': 5800}]

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

employees_new = [
    {'name': employee['name'], 'salary': employee['salary'] + 200} if employee['salary'] > 5000 else
    {'name': employee['name'], 'salary': employee['salary'] + 500} for employee in employees_old]

print(employees_new)

2. Понимание словаря:

пример 1:

dict_old = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'C'}
dict_new = {value: key for key, value in dict_old.items()}
print(dict_new)

выход:

{'A': 'a', 'B': 'b', 'C': 'd'}

3. Установите понимание:

Подобно пониманию списка. Типичное использование: дедупликация.
пример 1:

list_old = [1, 2, 3, 5, 2, 3]
set_new = {x for x in list_old}
print(set_new)

выход:

{1, 2 ,3, 5}

резюме:

К настоящему времени, не является ли понимание списков просто формулой для создания списков? Помимо упрощения кода, установить X? Фактически, еще одним преимуществом обработки списков является то, что они более эффективны, чем циклы for, потому что обработки списков вызывают базовый код C Python при их выполнении, в то время как циклы for выполняются с кодом Python. О~ Что интервьюер хочет услышать больше всего, так это второй пункт.

итератор

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

концепция

возможноnext()Объекты, которые вызывает функция и продолжает возвращать следующее значение, называются итераторами:Iterator.
Итерация — это способ доступа к элементам коллекции, итератор — это объект, который запоминает, где проходить. Доступ к объектам Iterator осуществляется с первого элемента коллекции до тех пор, пока не будут доступны все элементы.
Итераторы могут идти только вперед, а не назад.

  • протокол итератора: означает, что объект должен предоставить__next__()метод, который либо возвращает следующий элемент в итерации, либо вызываетStopIterationисключение для прекращения итерации.
  • повторяемый объект: объект, реализующий протокол итератора.

Например, друзья, немного знакомые с Python, должны знать, что цикл for в Python можно использовать не только для обхода списков, но и файловых объектов, как показано ниже:

with open('F:/test/test.txt') as f:
    for line in f:
        print(line)

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

with open('F:/test/test.txt') as f:
    print(dir(f))

выход:

['__class__', '__del__', '__dict__', '__dir__', '__init__', '__iter__', '__next__', 'closed', 'line_buffering', 'newlines', 'read', 'readline'......]     

Является ли iterable обязательно итераторами?

  • Генераторы являются итерируемыми, а также итераторами.
  • listявляется итерируемым, но не итератором.listможно использоватьiter()функция превращает iterable в итераторlist->iter(list)->迭代器next():
    借助iter()生成迭代器

Итерируемые объекты:

  1. Строитель
  2. список кортежей набор строк словаря

Как определить, является ли объект итерируемым?

с помощьюisinstance()функция:

from collections import Iterable

print(isinstance([x for x in range(10)], Iterable))  # 列表
print(isinstance('hello world', Iterable))  # 字符串
print(isinstance(100, Iterable))  # 数字
print(isinstance((x for x in range(10)), Iterable))  # 迭代器

выход:

True
True
False
True

Строитель

Генераторы — одна из самых полезных функций Python и одна из наименее широко используемых. Причина в основном в том, что в других основных языках нет концепции генераторов. Именно потому, что генератор является «новой» вещью, он, с одной стороны, не привлек внимания большинства инженеров, а с другой стороны, также увеличил стоимость обучения инженеров и, наконец, заставил всех пропустить такую ​​полезную функцию в Python.

концепция

Мы уже знаем, что список может быть создан непосредственно с помощью генератора списков, но из-за нехватки памяти емкость списка должна быть ограничена. Более того, создание списка с 1 миллионом элементов не только занимает много места для хранения, но и если нам нужно получить доступ только к первым нескольким элементам, то большая часть пространства, занимаемого последними элементами, будет потрачена впустую. Поэтому, если элементы списка могут непрерывно вычислять последующие элементы в процессе зацикливания по определенному алгоритму, нет необходимости создавать полный список, что также может сэкономить много места. В Python этот механизм вычислений во время цикла называется генератором:generator.
Python обеспечивает поддержку отложенных операций с использованием генераторов. Так называемая отложенная операция означает, что результат получается только тогда, когда он необходим, а не сразу. Это также является основным преимуществом генераторов.

Генератор определений

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

Способ 1: С помощью понимания списка

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

my_generator = (x for x in range(5))  # 注意是()不是[]
print(my_generator)  # 发现不能打印出元素
print(type(my_generator))
print(my_generator.__next__())  # 三种得到元素的方法,注意看输出结果
print(next(my_generator))
for i in my_generator:
    print(i)

# 注意会抛出StopIteration异常
# print(next(my_generator))  
print(next(my_generator))   # generator只能遍历一次

выход:

Traceback (most recent call last):
  File "E:/pycharm/Leetcode/RL_Learning/printdata.py", line 11, in <module>
    print(next(my_generator))
StopIteration
<generator object <genexpr> at 0x0000000000513660>
<class 'generator'>
0
1
2
3
4

Способ 2: С помощью функций

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

шаг:

  1. Определите функцию, функция возвращает значение, используяyieldключевое слово;
  2. Позвоните в функцию и получите возвращаемое значение функции;
  3. Возвращенный результат - генератор;
  4. с помощьюnext()или__nest__()чтобы получить нужный элемент.

Пример 2: Пока отображается ваша функцияyieldключевое слово, ваша функция больше не является функцией, она становится генератором:

# 斐波那契数列:
def fib(length):    # 1. 定义函数
    a, b = 0, 1
    n = 0
    while n < length:
        n += 1
        yield b         # return b + 暂停
        a, b = b, a + b


g = fib(5)     # 2. 调用函数
print(g)     # 3. 返回的就是生成器
print(next(g))     # 4. 借助`next()`或`__nest__()`得到想要的元素
print(next(g))    # 每调用一次产生一个值
print(next(g))
print(g.__next__())
print(g.__next__())

выход:

<generator object fib at 0x0000000001DDDFC0>
1
1
2
3
5

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

резюме:

После использования генераторов меньше строк кода. Мы должны помнить, что если вы хотите написать код Pythonic, в соответствии с предпосылкой обеспечить читабельность кода, максимальное количество строк кода.
Разумное использование генератора для эффективного улучшения читаемости кода. Пока все полностью приняли концепцию генератора, понимая заявление о выходе и возврата оператора, он также возвращает значение. Затем вы можете понять, почему генератор лучше, чем генератор, чем генератор, вы можете понять, что генератор действительно может заставить код становиться ясным.
На практике полное использование генераторов Python может не только сократить использование памяти, но и улучшить читаемость кода. Освоение генераторов также является стандартным для мастеров Python. Если эта статья была вам полезна, не забудьте поставить лайк или добавить ее в избранное~

Еще галантерейные товары (требуемые навыки):
От принципа к реальному бою, досконально изучите Nginx
От принципа к реальному бою, досконально изучите Nginx (Advanced)
Обзор Kafka, глубокое понимание архитектуры