Введение в основные заметки по Python (2)

искусственный интеллект регулярное выражение контейнер

предисловие

Эта статья в основном является дополнением к содержанию Python Basic Introductory Notes (1).

1. Итераторы и генераторы

1.1 Итераторы Python

Итератор — это объект, который запоминает, где проходить.

Доступ к объектам Iterator осуществляется с первого элемента коллекции до тех пор, пока не будут доступны все элементы.

Итераторы могут идти только вперед, а не назад.

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

Конкретные примеры:

# 1、字符创创建迭代器对象
str1 = 'jaybo'
iter1 = iter ( str1 )

# 2、list对象创建迭代器
list1 = [1,2,3,4]
iter2 = iter ( list1 )

# 3、tuple(元祖) 对象创建迭代器
tuple1 = ( 1,2,3,4 )
iter3 = iter ( tuple1 )

# for 循环遍历迭代器对象
for x in iter1 :
    print ( x , end = ' ' )

print('\n------------------------')

# next() 函数遍历迭代器
while True :
    try :
        print ( next ( iter3 ) )
    except StopIteration :
        break

Окончательный вывод:

j a y b o
------------------------
1
2
3
4

список (список) производства:

Синтаксис:

[expr for iter_var in iterable] 
[expr for iter_var in iterable if cond_expr]

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

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

Например, распечатайте таблицу умножения девяноста девяти одной строкой кода:

print('\n'.join([' '.join ('%dx%d=%2d' % (x,y,x*y)  for x in range(1,y+1)) for y in range(1,10)]))

Выходной результат:

1x1= 1
1x2= 2 2x2= 4
1x3= 3 2x3= 6 3x3= 9
1x4= 4 2x4= 8 3x4=12 4x4=16
1x5= 5 2x5=10 3x5=15 4x5=20 5x5=25
1x6= 6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7= 7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8= 8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9= 9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81

1.2 Генераторы

В Python функции, использующие yield, называются генераторами.

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

В процессе запуска генератора каждый раз, когда он сталкивается с yield, функция будет приостанавливать и сохранять всю текущую информацию о работе, а также возвращать значение yield. И продолжить работу с текущей позиции при следующем выполнении метода next().

①Создать:

Создание генераторов: самый простой и легкий способ — изменить [] понимания списка на ()

gen= (x * x for x in range(10))
print(gen)

Выходной результат:

generator object  at 0x0000000002734A40

Разница между созданием List и генератором только в самых внешних [] и () . Но генератор на самом деле не создает список чисел, а возвращает генератор, который «выдает» (выдает) запись каждый раз, когда она оценивается. Выражение генератора использует «ленивую оценку» (ленивая оценка, также переводится как «ленивая оценка», я думаю, что этот способ вызова по необходимости лучше перевести как ленивый) и присваивается только при извлечении (оценивается), так что это более эффективно использовать память, когда список длинный.

② Реализуйте генератор в виде функции:

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

Разница между генераторами и функциями:

Функции выполняются последовательно и возвращаются, когда сталкиваются с оператором return или последней строкой оператора функции. Функция, которая становится генератором, выполняется каждый раз, когда вызывается next(), и возвращается, когда сталкивается с оператором yield.Когда она выполняется снова, она продолжает выполняться с оператора yield, возвращенного в прошлый раз.

Например:

def odd():
    print ( 'step 1' )
    yield ( 1 )
    print ( 'step 2' )
    yield ( 3 )
    print ( 'step 3' )
    yield ( 5 )

o = odd()
print( next( o ) ) 
print( next( o ) ) 
print( next( o ) )

Выходной результат:

step 1
1
step 2
3
step 3
5

Видно, что odd — это не обычная функция, а генератор, в процессе выполнения он будет прерван при встрече с yield, и выполнение продолжится в следующий раз. После выполнения yield 3 раза выполнение yield не выполняется.Если вы продолжите печатать print(next(o)) , будет сообщено об ошибке. Поэтому ошибки обычно отлавливаются в функциях-генераторах.

Распечатайте треугольник Янхуэй:

def triangles( n ):         # 杨辉三角形
    L = [1]
    while True:
        yield L
        L.append(0)
        L = [ L [ i -1 ] + L [ i ] for i in range (len(L))]

n= 0
for t in triangles( 10 ):   # 直接修改函数名即可运行
    print(t)
    n = n + 1
    if n == 10:
        break

Выходной результат:

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

1.3 Расширение

① Обратная итерация

Используйте встроенные функции в Pythonreversed().

Следует отметить следующее:Итерации в обратном направлении только в том случае, если размер объекта может быть задан заранее или объект реализует__reversed__()специальный метод, чтобы вступить в силу. Если ни одно из них не совпадает, вы должны сначала преобразовать объект в список.

②Итерировать несколько последовательностей одновременно

Чтобы перебирать несколько последовательностей одновременно, используйте функцию zip(), конкретный пример:

names = ['jaychou', 'zjl', '周杰伦']
ages = [18, 19, 20]
for name, age in zip(names, ages):
     print(name,age)

Результат вывода:

jaychou 18
zjl 19
周杰伦 20

фактическиzip(a, b)создает итератор, который возвращает кортеж (x, y), где x происходит от a, а y происходит от b. Как только одна из последовательностей заканчивается, итерация заканчивается. Следовательно, длина итерации равна длине самой короткой последовательности в параметре. Обратите внимание, чтобы понять это предложение,То есть, если длины a и b несовместимы, кратчайшая из них будет стандартной, и обход закончится.

2. Модули и пакеты

2.1 Модули

2.1.1 Что такое модуль

В Питоне.pyФайл называется модулем.

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

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

Преимущества модулей:

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

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

    PS: Но также обратите внимание, что имя переменной не должно конфликтовать с именем встроенной функции. Общие встроенные функции:Прямая ссылка

Кстати, расширим содержимое пакета:

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

Python представляет организацию модулей по каталогам, называемым пакетами, например:

extensions
├─ __init__.py
├─ dog.py
└─ cat.py

в настоящее времяdog.pyИмя модуля становитсяextensions.dog.

PS: обратите внимание, что каждый каталог пакета будет иметь__init__.pyЭтот файл обязателен, иначе Python будет рассматривать этот каталог как обычный каталог, а не как каталог пакета.

Кроме того, как использовать модули в пакете (Module)? Напишите один следующим образомdog.pyМодуль:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '

__author__ = 'jack guo'

import sys

def shout():
    args = sys.argv
    if len(args)==1:
        print('Hello, I'm afei, welcome to world!')
    elif len(args)==2:
        print('Hello, %s!' % args[1])
   else:
        print('Yes,sir')

if __name__=='__main__':
    shout()

пожалуйста, объясни:

第1行注释可以让dog.py文件直接在linux上运行;
第2行注释表示.py文件本身使用标准UTF-8编码;
第4行表示模块的文档注释;
第6行表示模块的作者;

注意最后两行代码,当我们调试dog.py时,shout()会调用,当在其他模块导入dog.py时,shout()不执行。

Стандартный шаблон для модулей:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '

__author__ = 'jack guo'

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

2.1.2 Импорт модулей

Для импорта модулей мы используем ключевое словоimport, синтаксис следующий:import module1[, module2[,... moduleN]

как:import mathИмпортируйте математический модуль из стандартного модуля.

Модуль будет импортирован только один раз, независимо от того, сколько раз вы его запускаете.import. Это предотвращает повторное выполнение импортированных модулей.

Как интерпретатор Python находит соответствующий файл?

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

import sys

print(sys.path)

2.1.3 Импорт свойств и методов в модули и их вызов

① Как импортировать модуль

  • import 模块名
  • import 模块名 as 新名字
  • from 模块名 import 函数名: этого метода следует избегать в больших проектах, если вы не уверены, что не будет конфликтов имен; его преимущество в том, что его можно использовать напрямую.function()без добавленияmodule.function().

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

PS2: можно использоватьfrom ··· import *Оператор импортирует все свойства метода в модуль.

②Вызов переменных, функций, свойств и методов классов в модулях

  1. module.variable
  2. module.function()
  3. module.class.variable

2.1.4 Использование модуля sys пути поиска модуля)

(1) Каталог, в котором находится программа

(2) Путь установки стандартной библиотеки

(3) Путь, на который указывает переменная среды операционной системы PYTHONPATH.

  • Методы получения текущего пути поиска Python:

    import sys
    print(sys.path)
    

    вывод:

    ['D:\\workspace_pycharm', 'D:\\workspace_pycharm', 'D:\\python-practice', 'D:\\devInstall\\devPython\\Python36\\python36.zip', 'D:\\devInstall\\devPython\\Python36\\DLLs', 'D:\\devInstall\\devPython\\Python36\\lib', 'D:\\devInstall\\devPython\\Python36', 'D:\\devInstall\\devPython\\Python36\\lib\\site-packages']
    
  • Использование переменной argv модуля sys:

    • Модуль sys имеетargv(значения аргументов) переменная, использующая list для хранения всех аргументов командной строки.
    • argvСуществует по крайней мере один элемент, потому что первый элемент всегда.pyИмя файла.
    $ python solve.py 0    # 命令行语句
    # 获得argv变量的值
    sys.argv = ['solve.py', '0']
    sys.argv[0] = 'solve.py'
    sys.argv[1] = '0'
    

2.1.5 Основные и неосновные модули

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

Как отличить основной модуль от неосновного?

годный к употреблению__name__Атрибуты. Если значение атрибута__main__, то это означает, что этот модуль является основным модулем, и наоборот. Но будьте осторожны: это__main__Атрибуты только помогают нам определить, являются ли они основным модулем.Это не означает, что этот атрибут определяет, являются ли они основным модулем.Условием для определения того, являются ли они основным модулем, является только то, вызывался ли модуль. следующее:

if __name__ == '__main__':
    print('main')
else:
    print('not main')

Если вывод является основным, то модуль является основным модулем.

!!!Пополнить:В процессе изучения Python вы всегда можете столкнутьсяif __name__ == 'main'Предложения, мы просто пришли к пониманию.

Например, если содержимое файла A.py выглядит следующим образом:

def sayhello():
    print('Hello!')
print('Hi!')
print(__name__)

Выходной результат:

Hi!
__main__

В результате просто при запуске самого A.py переменная__name__Значение__main__.

Существует файл B.py со следующим кодом:

import A
A.sayhello()
print('End')

Как видите, в файле B.py импортируется модуль A, и результаты следующие:

Hi!
A
Hello!
End

Это связано с некоторыми проблемами порядка выполнения операторов.В файле B.py функция sayhello в модуле A выполняется при его вызове, но оператор print в A будет выполняться немедленно (поскольку нет отступа, он параллелен def ). Поэтому он будет выполняться последовательно:

print('Hi!')
print(__name__)

Затем выполните:

A.sayhello()
print('End')

текущий результатHi!Соответствует модулю А вprint('Hi!'), а результат A соответствуетprint(__name__), видно, что при вызове модуля A в файле B переменная__name__Значение определяется__main__становится именем модуля А.

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

def sayhello():
    print('Hello!')
print('Hi!')
print(__name__)

if __name__ == '__main__':
    print('I am module A')

Когда файл A.py снова запускается отдельно, в результатах будет большеI am module AЗаявление:

Hi!
__main__
I am module A

При запуске файла B.py, то есть вызове модуля A, этот оператор не отображается:

Hi!
A
Hello!
End

Подводя итог кратко:

свойства модуля__name__, значение которого задается интерпретатором Python. Если программа Python вызывается как основная программа, ее значение устанавливается равным__main__, если он импортирован как модуль другим файлом, его значением является его имя файла.

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

2.2 Пакет

2.2.1 Что такое пакет

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

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

2.2.2 Определение пакета и его преимущества

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

2.2.3 Создание пакета

  • Создайте папку для хранения связанных модулей,Имя папки - это имя пакета.
  • создать в папке__init__.pyСодержимое файла модуля может быть пустым (разница между обычной папкой и пакетом).
  • Поместите соответствующие модули в папку

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

①Хранение сумки

  • Если вы не хотите помещать соответствующие файлы модуля в созданную папку, то лучший вариант: поместить его в папку по умолчаниюsite-packagesпапка, потому что она используется для хранения файлов вашего модуля.
  • sys.path.append(‘模块的存放位置’)Он вступает в силу только во время выполнения и становится недействительным после завершения операции.
  • Добавьте путь хранения пакета в PYTHONPYTH в системной переменной среды пользователя, чтобы пакет можно было вызывать из любого места (рекомендуется).

② Импорт модулей в пакетах

  1. import 包名.模块名
  2. import 包名.模块名 as 新名字
  3. from 包名 import 模块名

③ Вызовы переменных, функций модулей в пакете, а также атрибутов и методов классов.

  1. package.module.variable
  2. package.module.function()
  3. package.module.class.variable

2.3 Область применения

Студенты, изучавшие Java, знают, что классы Java могут определять общедоступные (public) или частные (private) методы и свойства, главным образом потому, что мы надеемся, что некоторые функции и свойства могут использоваться другими или могут использоваться только для внутреннего использования. Изучая модули в Python, они на самом деле похожи на классы в Java, так как же реализовать в модуле одни функции и переменные, используемые другими, а некоторые функции и переменные используются только внутри модуля?

В Питоне через_префикс для достижения. Обычные имена функций и переменных общедоступны, и на них можно ссылаться напрямую, например:abc,ni12,PIЖдать.

похожий__xxx__Такие переменные являются специальными переменными, на которые можно напрямую ссылаться, но они имеют особые цели, такие как приведенные выше.__name__являются специальными переменными, и__author__Это также специальная переменная, используемая для идентификации автора. Обратите внимание, что наши собственные переменные обычно не используют такие имена переменных;похожий_xxxи__xxxТакие функции или переменные являются закрытыми, и на них нельзя ссылаться напрямую, например_abc,__abcЖдать.

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

Три, объектно-ориентированный

Программист контролирует доступ к атрибутам в Python.

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

3.1 Класс

3.1.1 Декораторы для методов

  • @classmethod: при вызове используйте имя класса напрямую вместо объекта

  • @property: методы можно вызывать как свойства

class UserInfo:

    ...

    @classmethod
    def get_name(cls):
        return cls.lv

    @property
    def get_age(self):
        return self._age

    if __name__ == '__main__':   
        ...

        # 直接使用类名类调用,而不是某个对象
        print(UserInfo.lv)
        # 像访问属性一样调用方法(注意看get_age是没有括号的)
        print(userInfo.get_age)

3.1.2 Наследование

Формат синтаксиса:

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

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

class ClassName(Base1,Base2,Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

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

Преимущества унаследованных подклассов:

  • Наследуют свойства и методы родительского класса
  • Вы можете определить свои собственные, переопределить свойства и методы родительского класса

3.1.3 Полиморфизм

Просто посмотрите на пример:

class User(object):
    def __init__(self, name):
        self.name = name

    def printUser(self):
        print('Hello !' + self.name)

class UserVip(User):
    def printUser(self):
        print('Hello ! 尊敬的Vip用户:' + self.name)

class UserGeneral(User):
    def printUser(self):
        print('Hello ! 尊敬的用户:' + self.name)

def printUserInfo(user):
    user.printUser()

if __name__ == '__main__':
    userVip = UserVip('大金主')
    printUserInfo(userVip)
    userGeneral = UserGeneral('水货')
    printUserInfo(userGeneral)

Выходной результат:

Hello ! 尊敬的Vip用户:大金主
Hello ! 尊敬的用户:水货

Как видите, userVip и userGeneral — это два разных объекта, вызовите для них метод printUserInfo, и они автоматически вызовут фактический тип метода printUser и ответят по-разному. В этом красота полиморфизма.

PS: При наследовании существует полиморфизм, и объекты разных классов будут по-разному реагировать на одно и то же сообщение.

3.1.4 Магические методы в Python

В Python все методы, заключенные в двойные символы подчеркивания "**", в совокупности называются "магическими методами". Например, у нас больше всего контактовinit__. Что делают магические методы?

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

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

class User(object):
    pass


if __name__ == '__main__':
    print(dir(User()))

Результат вывода:

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

1, контроль доступа к атрибутам

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

метод инструкция
__getattr__(self, name) Этот метод определяет поведение при попытке доступа к несуществующему свойству. Таким образом, переопределение этого метода может выявить орфографические ошибки, а затем перенаправить или предупредить о некоторых устаревших свойствах.
__setattr__(self, name, value) Определяет поведение при назначении и изменении свойств. Независимо от того, существует ли свойство объекта, этому свойству разрешено присваивать значение. Стоит отметить, что реализация__setattr__Чтобы избежать ошибки «бесконечной рекурсии» при
__delattr__(self, name) __delattr__и__setattr__Очень похоже, за исключением того, что он определяет поведение при удалении свойства. выполнить__delattr__заключается в том, чтобы одновременно избежать ошибок "бесконечной рекурсии"
__getattribute__(self, name) __getattribute__определяет поведение вашего свойства при доступе к нему по сравнению с__getattr__Работает только в том случае, если свойство не существует. Поэтому в поддержку__getattribute__Версия Python, вызывающая__getattr__должен быть вызван перед__getattribute__,__getattribute__Также избегайте ошибки «бесконечной рекурсии».

2. Дескриптор объекта

В общем, дескриптор — это атрибут объекта с «поведением привязки», управление доступом которого переопределяется методами протокола дескриптора. Эти методы__get__(),__set__()и__delete__(). Объекты с этими методами называются дескрипторами.

Управление доступом по умолчанию для свойств осуществляется из словаря объекта (__dict__)Get (получить), set (установить) и delete (удалить) в . Например,a.xПорядок поиска такойa.__dict__['x'],Потомtype(a).__dict__['x'], затем найдитеtype(a)родительский класс (за исключением метаклассов). Если найденное значение является дескриптором, Python вызывает методы дескриптора, чтобы переопределить поведение элемента управления по умолчанию. Где эта перезапись происходит в этом цикле поиска, зависит от того, какой метод дескриптора определен. Обратите внимание, что дескрипторы работают только внутри класса нового стиля.

Что касается самой важной особенности классов нового стиля, то все классы наследуются от классов типов или объектов.

В объектно-ориентированном программировании, если атрибуты класса взаимозависимы, использование дескрипторов для написания кода может очень разумно организовать логику. В ORM Джанго,models.ModelТакие поля, как InterField в , реализуются через дескриптор.

См. пример:

class User(object):
    def __init__(self, name='小明', sex='男'):
        self.sex = sex
        self.name = name

    def __get__(self, obj, objtype):
        print('获取 name 值')
        return self.name

    def __set__(self, obj, val):
        print('设置 name 值')
        self.name = val

class MyClass(object):
    x = User('小明', '男')
    y = 5

if __name__ == '__main__':
    m = MyClass()
    print(m.x)

    print('\n')

    m.x = '大明'
    print(m.x)

    print('\n')

    print(m.x)

    print('\n')

    print(m.y)

Выходной результат:

获取 name 值
小明


设置 name 值
获取 name 值
大明


获取 name 值
大明


5

3. Пользовательский контейнер (Контейнер)

Мы знаем, что в Python распространенными типами контейнеров являются: dict, tuple, list, string. В нем также упоминается концепция контейнера и неизменного контейнера. Где tuple и string — неизменяемые контейнеры, а dict и list — изменяемые контейнеры.

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

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

На данный момент нам нужно настроить контейнер, так что же нам делать?

Функции инструкция
Пользовательский неизменяемый тип контейнера необходимо определить__len__и__getitem__метод
Пользовательский контейнер изменяемого типа Добавление определений к неизменяемым типам контейнеров__setitem__и__delitem__
Пользовательские типы данных требуют итерации необходимо определить__iter__
Возвращает длину пользовательского контейнера необходимо реализовать__len__(self)
Пользовательские контейнеры могут вызыватьself[key], если тип ключа неверный, выбросить TypeError, если значение, соответствующее ключу, не может быть возвращено, метод должен выдать ValueError необходимо реализовать__getitem__(self, key)
при исполненииself[key] = valueВремя звонок__setitem__(self, key, value)Сюда
при исполненииdel self[key]метод На самом деле метод вызывается__delitem__(self, key)
когда вы хотите, чтобы ваш контейнер выполнялсяfor x in container:или использоватьiter(container)Время необходимо реализовать__iter__(self), который возвращает итератор

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

3.2 Класс перечисления

3.2.1 Что такое перечисление

Например, посмотрите непосредственно на код:

from enum import Enum

Month = Enum('Month1', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

# 遍历枚举类型
for name, member in Month.__members__.items():
    print(name, '---------', member, '----------', member.value)

# 直接引用一个常量
print('\n', Month.Jan)

Выходной результат:

Jan --------- Month1.Jan ---------- 1
Feb --------- Month1.Feb ---------- 2
Mar --------- Month1.Mar ---------- 3
Apr --------- Month1.Apr ---------- 4
May --------- Month1.May ---------- 5
Jun --------- Month1.Jun ---------- 6
Jul --------- Month1.Jul ---------- 7
Aug --------- Month1.Aug ---------- 8
Sep --------- Month1.Sep ---------- 9
Oct --------- Month1.Oct ---------- 10
Nov --------- Month1.Nov ---------- 11
Dec --------- Month1.Dec ---------- 12

Month.Jan

Видно, что мы можем напрямую использовать Enum для определения класса перечисления. В приведенном выше коде мы создали тип перечисления Month, который связан с месяцем.Здесь следует отметить параметры построения.Первый параметр Month представляет имя класса класса перечисления, а второй параметр кортежа представляет тип перечисления , Значение класса перечисления, разумеется, класс перечисления передается__members__Метод, который выполняет итерацию по всем своим членам.

Следует отметить, что member.value — это константа типа int, которая автоматически присваивается члену, начиная с 1 по умолчанию. И все члены Enum являются синглтонами (Singleton), и их нельзя создать и нельзя изменить.

3.2.2 Пользовательские типы перечисления

Иногда нам нужно управлять типом перечисления, тогда мы можем создать собственный класс из Enum, чтобы удовлетворить эту потребность. Измените приведенный выше пример:

from enum import Enum, unique

Enum('Month1', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

# @unique 装饰器可以帮助我们检查保证没有重复值
@unique
class Month1(Enum):
    Jan = 'January'
    Feb = 'February'
    Mar = 'March'
    Apr = 'April'
    May = 'May'
    Jun = 'June'
    Jul = 'July'
    Aug = 'August'
    Sep = 'September '
    Oct = 'October'
    Nov = 'November'
    Dec = 'December'

if __name__ == '__main__':
    print(Month1.Jan, '----------',
          Month1.Jan.name, '----------', Month1.Jan.value)
    for name, member in Month1.__members__.items():
        print(name, '----------', member, '----------', member.value)

Выходной результат:

Month1.Jan ---------- Jan ---------- January
Jan ---------- Month1.Jan ---------- January
Feb ---------- Month1.Feb ---------- February
Mar ---------- Month1.Mar ---------- March
Apr ---------- Month1.Apr ---------- April
May ---------- Month1.May ---------- May
Jun ---------- Month1.Jun ---------- June
Jul ---------- Month1.Jul ---------- July
Aug ---------- Month1.Aug ---------- August
Sep ---------- Month1.Sep ---------- September 
Oct ---------- Month1.Oct ---------- October
Nov ---------- Month1.Nov ---------- November
Dec ---------- Month1.Dec ---------- December

4.2.3 Сравнение классов перечисления

Поскольку члены перечисления не упорядочены, они поддерживают сравнение только по идентичности и равенству. Давайте взглянем==иisиспользование:

from enum import Enum

class User(Enum):
    Twowater = 98
    Liangdianshui = 30
    Tom = 12

Twowater = User.Twowater
Liangdianshui = User.Liangdianshui

print(Twowater == Liangdianshui, Twowater == User.Twowater)
print(Twowater is Liangdianshui, Twowater is User.Twowater)

try:
    print('\n'.join('  ' + s.name for s in sorted(User)))
except TypeError as err:
    print(' Error : {}'.format(err))

Выходной результат:

False True
False True
 Error : '<' not supported between instances of 'User' and 'User'

Вы можете посмотреть на окончательный вывод, и было сообщено об исключении, потому что операторы сравнения больше и меньше вызывают исключения TypeError. То есть перечисление класса Enum не поддерживает оператор сравнения размера.

Однако использование класса IntEnum для перечисления поддерживает функции сравнения.

import enum

class User(enum.IntEnum):
    Twowater = 98
    Liangdianshui = 30
    Tom = 12
    
try:
    print('\n'.join(s.name for s in sorted(User)))
except TypeError as err:
    print(' Error : {}'.format(err))

Выходной результат:

Tom
Liangdianshui
Twowater

Как видно из вывода, члены класса перечисления отсортированы по размеру их значения. То есть можно сравнивать размеры.

3.3 Метаклассы

3.3.1 Классы также являются объектами в Python

В большинстве языков программирования класс представляет собой набор сегментов кода, описывающих, как создать объект. То же самое верно и в Python. Однако классы в Python немного отличаются от большинства языков программирования.Класс можно понимать и как объект. Да, здесь нет опечатки, это объект.

потому что просто используйте ключевое словоclass, интерпретатор Python создает объект при выполнении. как:

class ObjectCreator(object):
    pass

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

3.3.2 Использование type() для динамического создания классов

Поскольку классы также являются объектами, мы можем создавать классы во время работы программы. Python — динамический язык. Самая большая разница между динамическими языками и статическими языками заключается в том, что определения функций и классов не определяются во время компиляции, а динамически создаются во время выполнения. Перед этим давайте разбиратьсяtype()функция.

class Hello(object):
    def hello(self, name='Py'):
        print('Hello,', name)

Затем другой модуль обращается к модулю hello и выводит соответствующую информацию. (вtype()Роль функции состоит в том, чтобы увидеть тип типа и переменной. )

from com.strivebo.hello import Hello

h = Hello()
h.hello()

print(type(Hello))
print(type(h))

Выходная информация:

Hello, Py
<class 'type'>
<class 'com.twowater.hello.Hello'>

Также упоминалось выше,type()Функции могут искать тип типа или переменной, Hello — это класс, тип которого — type, а h — экземпляр, тип которогоcom.strivebo.hello.Hello. фронтcom.striveboимя моего пакета, под которым находится модуль приветствия.

Давайте подумаем об этом здесь, в приведенном выше примере мы используемtype()Функция смотрит на тип типа или переменной. Он смотрит на тип класса Hello и выводит результат:<class 'type'>. фактическиtype()Функции могут не только возвращать тип объекта, но и создавать новые типы. Определение класса создается динамически во время выполнения, и способ создания класса заключается в использованииtype()функция. Например, мы можем пройтиtype()Функция создает класс Hello в приведенном выше примере, подробности см. в следующем коде:

def printHello(self, name='Py'):
    # 定义一个打印 Hello 的函数
    print('Hello,', name)

# 创建一个 Hello 类
Hello = type('Hello', (object,), dict(hello=printHello))

# 实例化 Hello 类
h = Hello()
# 调用 Hello 类的方法
h.hello()
# 查看 Hello class 的类型
print(type(Hello))
# 查看实例 h 的类型
print(type(h))

Выходной результат:

Hello, Py
<class 'type'>
<class '__main__.Hello'>

Здесь необходимо сначала разобраться вtype()Описание параметра функции для создания объекта класса:

  1. Имя класса, такое как имя в примереHello
  2. Коллекция унаследованных родительских классов. Обратите внимание, что Python поддерживает множественное наследование. Если есть только один родительский класс, кортеж должен быть записан в одноэлементном формате, в примере наследуется объектный класс, потому что он одноэлементный кортеж, поэтому он записывается как(object,)
  3. Имя метода класса привязано к функции, в примере функцияprintHelloпривязан к имени методаhelloсередина

Конкретный режим выглядит следующим образом:type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

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

3.3.3 Что такое метакласс

Когда мы создаем класс, большая часть этого заключается в создании экземпляра объекта класса. А как насчет метаклассов? Метаклассы используются для создания классов. Можно понимать и по-другому:Метакласс — это класс классов.

через вышеуказанноеtype()Введение функции, мы знаем, что мы можем пройтиtype()Функция для создания класса:MyClass = type('MyClass', (), {})

На самом деле функция type() является метаклассом.type()Это метакласс, который Python использует за кулисами для создания всех классов.

Итак, теперь мы также можем догадаться, почемуtype()Что, если функция является типом, а не типом?

Вероятно, это сделано для согласованности с классом str, используемым для создания строковых объектов, и классом int, используемым для создания целочисленных объектов. type — это класс, создающий объект класса.

Как видите, все вышеперечисленное, то есть все объекты создаются через классы, то нам может быть любопытно,__class__из__class__Что бы это могло быть? Другими словами, какой класс создал эти классы?

print(age.__class__.__class__)
print(name.__class__.__class__)
print(fu.__class__.__class__)
print(mEat.__class__.__class__)

Выходной результат:

<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>

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

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

3.3.4 Пользовательские метаклассы

Связь такова: сначала определите метакласс, вы можете создать класс и, наконец, создать экземпляр.

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

class MyObject(object):
    __metaclass__ = something…
[…]

Если бы это было написано таким образом, Python использовал бы метакласс для создания класса MyObject. когда ты пишешьclass MyObject(object), но объект класса MyObject не был создан в памяти. Python будет искать в определении класса для__metaclass__атрибут, если он найден, Python будет использовать его для создания класса MyObject, если он не найден, будет использовать встроенную функцию типа для создания класса. Если вы все еще не понимаете, взгляните на блок-схему ниже:

Например:

class Foo(Bar):
    pass

Каков его процесс?

Сначала определите, есть ли в Foo__metaclass__это свойство? Если есть, Python пройдет__metaclass__Создайте объект класса с именем Foo (обратите внимание, что это объект класса). Если Python не находит__metaclass__, он продолжит искать в Bar (родительский класс)__metaclass__свойства и попробуйте сделать то же самое, что и раньше. Если Python не найден ни в одном родительском классе__metaclass__, он будет выглядеть в иерархии модулей__metaclass__, и попробуйте сделать то же самое. Если вы все еще не можете найти его__metaclass__, Python будет использовать встроенный тип для создания этого объекта класса.

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

Теперь мы в основном понимаем__metaclass__атрибут, однако, не говорил о том, как использовать этот атрибут, или что можно положить в этот атрибут?

Ответ таков: вы можете создать класс вещей. Так что же можно использовать для создания класса? тип или все, что использует тип или тип подклассов.

3.4.5 Роль метаклассов

Основная цель метаклассов — автоматически изменять классы при их создании. Как правило, вы делаете что-то подобное для API и хотите иметь возможность создавать классы, соответствующие текущему контексту.

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

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

4. Потоки и процессы

Я не буду вдаваться в подробности концепций потоков и процессов. Вы можете искать информацию в Интернете.

Посмотрите прямо на проблему: что, если мы хотим выполнять несколько задач одновременно в Python?

Есть два решения:

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

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

Подводя итог, можно выделить три способа реализации многозадачности:

  • многопроцессорный режим;
  • многопоточный режим;
  • Многопроцессный + многопоточный режим.

Одновременное выполнение нескольких задач Обычно каждая задача не является несвязанной, но должна взаимодействовать и координировать друг с другом. Иногда задача 1 должна приостанавливаться и ждать завершения задачи 2, прежде чем продолжить выполнение. Иногда задача 3 и задача 4 не могут выполняться одновременно. , поэтому сложность многопроцессных и многопоточных программ намного выше, чем однопроцессных и однопоточных программ, которые мы написали ранее.

4.1 Многопоточное программирование

На самом деле, после создания потока, поток не всегда сохраняет состояние, и его состояние примерно следующее:

  • Новое создание
  • Runnable готов. ожидание расписания
  • Бег
  • Заблокировано. Блокировка может быть в режиме ожидания. Заблокировано. Спящий режим.
  • мертв

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

  • основной поток
  • дочерний поток
  • Поток демона (фоновый поток)
  • нить переднего плана

Создание темы:

Python предоставляет два модуля для многопоточных операций, а именноthreadиthreading

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

import time
import threading


class MyThread(threading.Thread):
    def run(self):
        for i in range(5):
            print('thread {}, @number: {}'.format(self.name, i))
            time.sleep(1)

def main():
    print("Start main threading")

    # 创建三个线程
    threads = [MyThread() for i in range(3)]
    # 启动三个线程
    for t in threads:
        t.start()

    print("End Main threading")


if __name__ == '__main__':
    main()

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

5. Регулярные выражения Python

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

Python добавил модуль re начиная с версии 1.5, который предоставляет шаблоны регулярных выражений в стиле Perl. Модуль re обеспечивает полные возможности регулярных выражений для языка Python.

Следующий код:

# 设定一个常量
a = '学习Python不难'

# 判断是否有 “Python” 这个字符串,使用 PY 自带函数

print('是否含有“Python”这个字符串:{0}'.format(a.index('Python') > -1))
print('是否含有“Python”这个字符串:{0}'.format('Python' in a))

Выходной результат:

是否含有“Python”这个字符串:True
是否含有“Python”这个字符串:True

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

Просто приведите пример использования регулярных выражений в Python: найдите все строчные буквы в строке.

Сначала пропишем правила для регулярных выражений в первом параметре функции findall, где[a-z]Он должен соответствовать любой строчной букве, а второму параметру нужно только заполнить строку для сопоставления. детали следующим образом:

import re

# 设定一个常量
a = '学习Python不难'

# 选择 a 里面的所有小写英文字母

re_findall = re.findall('[a-z]', a)

print(re_findall)

Выходной результат:

['y', 't', 'h', 'o', 'n']

Таким образом мы получаем все строчные буквы в строке.

Пополнить:

  • Жадный режим: его характеристикой является чтение всей строки за один раз, и, если она не совпадает, она выдает самый правый символ, а затем сопоставляется до тех пор, пока не будет найдена совпадающая строка или длина строки не станет равной 0. Его цель — прочитать как можно больше символов, поэтому он возвращается, как только будет прочитано первое совпадение.
  • Ленивый режим: его характеристика состоит в том, чтобы начать с левой стороны строки и попытаться сопоставить, не читая символы в строке.Если это не удается, прочитайте еще один символ, а затем сопоставьте и т. д. Когда совпадение найдено , он вернет строку match., а затем снова сопоставит до конца строки.

Дополнительные сведения о регулярных выражениях см. в онлайн-материалах.

6. Закрытие

Узнайте о замыканиях, решив проблему требования.

Это требование таково, что нам необходимо постоянно записывать собственное время обучения в минутах. Это как если я занимаюсь 2 минуты, возвращаю 2, а через некоторое время занимаюсь 10 минут, потом возвращаюсь к 12, и время обучения накапливается так.

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

time = 0

def insert_time(min):
    time = time + min
    return  time

print(insert_time(2))
print(insert_time(10))

На самом деле это ошибка в Python. Будет сообщено о следующей ошибке:UnboundLocalError: local variable 'time' referenced before assignment

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

Мы можем использовать ключевое слово global, измененное следующим образом:

time = 0

def insert_time(min):
    global  time
    time = time + min
    return  time

print(insert_time(2))
print(insert_time(10))

Результат выглядит следующим образом:

2
12

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

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

time = 0

def study_time(time):
    def insert_time(min):
        nonlocal  time
        time = time + min
        return time

    return insert_time

f = study_time(time)
print(f(2))
print(time)
print(f(10))
print(time)

Результат выглядит следующим образом:

2
0
12
0

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

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

Есть ли способ проверить, что эта функция является замыканием?

Да, все функции имеют один__closure__свойство, если функция является замыканием, то она возвращает объект-кортеж, состоящий из ячеек. Свойство cell_contents объекта ячейки — это переменная, хранящаяся в замыкании. Посмотрите на код:

ime = 0


def study_time(time):
    def insert_time(min):
        nonlocal  time
        time = time + min
        return time

    return insert_time


f = study_time(time)
print(f.__closure__)
print(f(2))
print(time)
print(f.__closure__[0].cell_contents)
print(f(10))
print(time)
print(f.__closure__[0].cell_contents)

Результат печати:

(<cell at 0x0000000000410C48: int object at 0x000000001D6AB420>,)
2
0
2
12
0
12

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

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

7. Декоратор

7.1 Что такое декоратор

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

def punch():
    print('昵称:小明  部门:研发部 上班打卡成功')

punch()

Результат вывода:

昵称:小明  部门:研发部 上班打卡成功

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

import time

def punch():
    print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
    print('昵称:小明  部门:研发部 上班打卡成功')

punch()

Результат вывода:

2018-01-09
昵称:小明  部门:研发部 上班打卡成功

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

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

import time

def punch():
    print('昵称:小明  部门:研发部 上班打卡成功')

def add_time(func):
    print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
    func()

add_time(punch)

Результат вывода:

2018-01-09
昵称:小明  部门:研发部 上班打卡成功

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

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

import time

def decorator(func):
    def punch():
        print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
        func()

    return punch

def punch():
    print('昵称:小明  部门:研发部 上班打卡成功')

f = decorator(punch)
f()

Результат вывода:

2018-01-09
昵称:小明  部门:研发部 上班打卡成功

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

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

7.2 Синтаксический сахар

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

Так как же использовать его синтаксический сахар? Это очень просто: после написания функции-декоратора в соответствии с описанным выше методом, добавьте ее непосредственно в исходную функцию.@и имя функции декоратора. следующее:

import time

def decorator(func):
    def punch():
        print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
        func()

    return punch

@decorator
def punch():
    print('昵称:小明  部门:研发部 上班打卡成功')

punch()

Выходной результат:

2018-01-09
昵称:小明  部门:研发部 上班打卡成功

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

Однако здесь всегда была проблема, то есть вывод врезной информации фиксированный, поэтому нам нужно передать ее через параметры.Как написать декоратор? Функция в декораторе может использовать*argsвариативные параметры, но использовать только*argsНевозможно полностью включить все параметры, такие как параметры ключевого слова. Чтобы быть совместимым с параметрами ключевого слова, нам также необходимо добавить**kwargs.

Поэтому окончательный вид декоратора можно записать так:

import time

def decorator(func):
    def punch(*args, **kwargs):
        print(time.strftime('%Y-%m-%d', time.localtime(time.time())))
        func(*args, **kwargs)

    return punch

 
@decorator
def punch(name, department):
    print('昵称:{0}  部门:{1} 上班打卡成功'.format(name, department))

@decorator
def print_args(reason, **kwargs):
    print(reason)
    print(kwargs)

punch('小明', '研发部')
print_args('小明', sex='男', age=99)

Результат вывода:

2018-01-09
昵称:小明  部门:研发部 上班打卡成功
2018-01-09
小明
{'sex': '男', 'age': 99}

Восемь, пользовательские исключения и активные исключения

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

поднять заявление:

Активно бросайте исключения. Формат:

  • Активно генерировать исключение, чтобы завершить программу
  • raise 异常名称(‘异常描述’)
raise RuntimeError('testError')

Активно сгенерируйте это исключение и объясните его.

Пользовательское исключение:

В python есть два типа исключений.

  1. Встроенные исключения — это исключения, определенные самим python.
  2. Недостаточно, определяемое пользователем исключение

Сначала взгляните на дерево наследования исключений Python:

Мы видим, что исключения Python имеют большой базовый класс. Затем наследуется Exception. Поэтому наш пользовательский класс также должен наследовать Exception.

#最简单的自定义异常
class FError(Exception):
    pass

Чтобы сгенерировать исключение, сгенерируйте с помощью try-except:

try:
    raise FError("自定义异常")
except FError as e:
    print(e)

Вот простой настраиваемый шаблон класса исключений.

class CustomError(Exception):
    def __init__(self,ErrorInfo):
        super().__init__(self) #初始化父类
        self.errorinfo=ErrorInfo
    def __str__(self):
        return self.errorinfo

if __name__ == '__main__':
    try:
        raise CustomError('客户异常')
    except CustomError as e:
        print(e)

--от:blog.CSDN.net/черепный клык/Ах…

Большая часть содержания этой статьи взята из: