написать впереди
- Эта статья предназначена для среднего и продвинутого уровня разработки на Python, поэтому слишком простые темы здесь не рассматриваются.
- В этой статье рассматриваются только вопросы интервью, связанные с Python. Другие вопросы интервью, такие как сеть, MySQL и алгоритмы, будут организованы отдельно.
- не просто дать ответы,Бойкот Багувену! !Я надеюсь подробно объяснить определенную точку знаний с помощью демонстрации кода, изучения принципов и т. д., чтобы достичь полного понимания.
- Часть демо-кода также размещена у меня на гитхабесодержаниеВниз.
Основы языка
Основные типы данных в Python
В Python 3 есть шесть стандартных типов данных:
- Число (число) (в том числе целое, с плавающей запятой, комплексное, логическое и т. д.)
- Строка (строка)
- Список
- Кортеж (кортеж)
- Набор
- Словарь (словарь)
Среди шести стандартных типов данных Python3:
- Неизменяемые данные (3): Number (число), String (строка), Tuple (кортеж);
- Переменные данные (3): List (список), Dictionary (словарь), Set (коллекция).
Является ли Python статическим или динамическим типом? Является ли он строго типизированным или слабо типизированным?
- Динамически строго типизированный язык (многие ошибочно думают, что он слабо типизирован)
- Динамический или статический относится к тому, определяет ли компилятор или среда выполнения тип.
- Строгая типизация означает, что не происходит неявного преобразования типов.
js — типичный язык со слабой типизацией.Например, если вы моделируете добавление чисел и строк в консоли, вы обнаружите, что происходит преобразование типов.
И Python сообщит TypeError
какие бывают виды уток
«Когда птица ходит, как утка, плавает, как утка, и крякает, как утка, тогда эту птицу можно назвать уткой».
Утиная типизация связана с поведением объекта, а не с типом. Например, файлы, объекты StringIO и сокеты поддерживают методы чтения/записи.Например, объекты, определяющие магический метод __iter__, могут выполняться с помощью for.
Вот пример имитации утиного набора текста:
class Duck:
def say(self):
print("嘎嘎")
class Dog:
def say(self):
print("汪汪")
def speak(duck):
duck.say()
duck = Duck()
dog = Dog()
speak(duck) # 嘎嘎
speak(dog) # 汪汪
что такое самоанализ
Самоанализ — это способность определять тип объекта во время выполнения.
Все в python является объектом, используйте type, id, isinstance для получения информации о типе объекта.
Самоанализ, или рефлекс, обычно относится в компьютерном программировании к способности исследовать что-то, чтобы определить, что это такое, что оно знает и что оно может делать.
Основные методы, связанные с ним:
- hasattr(object, name) проверяет, имеет ли объект определенный атрибут имени. Возврат бул.
- getattr(object, name, default) получает атрибут имени объекта.
- setattr(object, name, default) устанавливает атрибут name для объекта
- delattr(object, name) удаляет атрибут name из объекта
- dir([object]) получает большинство атрибутов объекта
- isinstance(name, object) проверяет, является ли name объектом объекта
- type(object) для просмотра типа объекта
- callable(object) Определяет, является ли объект вызываемым объектом
Сравнение python3 и python2
- печать становится функцией
- проблема с кодировкой. python3 больше не имеет объектов unicode, str по умолчанию — unicode
- Разделите изменения. деление python3 возвращает число с плавающей запятой, если вы хотите вернуть целое число, вы должны использовать //
- Введите аннотации. Помогите IDE реализовать проверку типов
- Оптимизированный super() удобен для прямого вызова функции родительского класса. Одно различие между Python3.x и Python2.x заключается в следующем: Python 3 может использовать super().xxx напрямую вместо super(Class, self).xxx :
- Расширенные операции распаковки. а, б, *остальное = диапазон (10)
- только аргументы ключевого слова. Квалифицированные аргументы ключевого слова
- цепочки исключений. python3 повторно выдает исключение без потери информации о стеке
- Все возвращает итераторы. range, zip, map, dict.values и т. д. — все это итераторы.
- оптимизация производительности и т.д. . .
Как передать параметры в питоне
В официальной документации по Python:
"Помните, что в Python аргументы передаются путем присваивания. Поскольку присваивание просто создает ссылки на объекты, между именем аргумента в вызывающем и вызываемом объектах нет псевдонима, а значит, и вызова по ссылке как такового нет".
Чтобы быть точным, передача параметров Python осуществляется путем присваивания или передачи по ссылке на объект. Все типы данных в Python являются объектами, поэтому при передаче параметров просто позвольте новой переменной и исходной переменной указывать на один и тот же объект, и нет такой вещи, как передача по значению или по ссылке.
Передача по ссылке на объект дает два разных результата в зависимости от того, является ли объект изменяемым или неизменяемым. Если это изменяемый объект, измените его напрямую. Если это неизменяемый объект, создайте новый объект и пусть формальный параметр указывает на новый объект
Это можно смоделировать в сочетании со следующим примером кода:
def flist(l):
l.append(0)
print(id(l)) # 每次打印的id相同
print(l)
ll = []
print(id(ll))
flist(ll) # [0]
flist(ll) # [0,0]
print("=" * 10)
def fstr(s):
print(id(s)) # 和入参ss的id相同
s += "a"
print(id(s)) # 和入参ss的id不同,每次打印结果不相同
print(s)
ss = "sun"
print(id(ss))
fstr(ss) # a
fstr(ss) # a
Изменяемые/неизменяемые объекты для python
Неизменяемые объекты: bool/int/float/tuple/str/frozenset Изменяемые объекты: list/set/dict
Продолжайте смотреть на два примера кода здесь, чтобы увидеть, что получается на выходе.
def clear_list(l):
l = []
ll = [1,2,3]
clear_list(ll)
print(ll)
def fl(l=[1]):
l.append(1)
print(l)
fl()
fl()
ответ
[1,2,3]
[1]
[1,1]
На первый вопрос,l = []
На этом шаге создается новый объект и вставляется l (обратите внимание, что l внутри функции и l вне функции — это разница между формальным параметром и фактическим параметром, не думайте, что это одно и то же), поэтому исходный l не изменился.
Для второго вопроса параметры по умолчанию рассчитываются только один раз.
Заинтересованные друзья могут попробовать этот пример еще раз:
a = 1
def fun(a):
print("func_in",id(a))
a = 2
print("re-point",id(a), id(2))
print("func_out",id(a), id(1))
fun(a)
ответ:
func_out 2602672810288 2602672810288
func_in 2602672810288
re-point 2602672810320 2602672810320
Что касается передачи параметров Python, изменяемых/неизменяемых объектов, рекомендуется использовать stackoverflow выше.отвечать.
Arguments are passed by assignment. The rationale behind this is twofold:
the parameter passed in is actually a reference to an object (but the reference is passed by value)some data types are mutable, but others aren't
So: If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object.
If you pass an immutable object to a method, you still can't rebind the outer reference, and you can't even mutate the object.
в Питоне*args
а также **kwargs
для обработки переменных параметров,*args
упакован вtuple
,**kwargs
упакован вdict
Давайте посмотрим на некоторые примеры кода:
def print_multiple_args(*args):
print(type(args), args)
for idx, val in enumerate(args): # enumerate()枚举函数
print(idx, val)
print_multiple_args('a', 'b', 'c')
# 通过将列表前加*打包成关键字参数,指明了接收值参数必须是*args
print_multiple_args(*['a', 'b', 'c'])
def print_kwargs(**kwargs):
print(type(kwargs), kwargs)
for k, v in kwargs.items():
print('{}: {}'.format(k, v))
print_kwargs(a=1, b=2)
# 给字典前加**打包成关键字参数,指明接收值的参数必须是**kwargs
print_kwargs(**dict(a=1, b=2))
def print_all(a, *args, **kwargs):
print(a)
if args:
print(args)
if kwargs:
print(kwargs)
print_all('hello', 'world', name='monki')
Результат:
<class 'tuple'> ('a', 'b', 'c')
0 a
1 b
2 c
<class 'tuple'> ('a', 'b', 'c')
0 a
1 b
2 c
<class 'dict'> {'a': 1, 'b': 2}
a: 1
b: 2
<class 'dict'> {'a': 1, 'b': 2}
a: 1
b: 2
hello
('world',)
{'name': 'monki'}
механизм исключений Python
Обратитесь к классификации иерархии исключений в официальной документации Python.
docs.Python.org/this-talent/3/неделя…
Пример блока кода исключения Python:
try:
# func # 可能会抛出异常的代码
except (Exception1, Exception2) as e: # 可以捕获多个异常并处理
# 异常处理的代码
else:
# pass # 异常没有发生的时候代码逻辑
finally:
pass # 无论异常有没有发生都会执行的代码,一般处理资源的关闭和释放
Что такое GIL в Python?
Глобальная блокировка интерпретатора GIL, английское название Global Interpreter Lock, представляет собой метод синхронизации потоков в интерпретаторе.
Для каждого процесса интерпретатора существует GIL, и его прямым следствием является ограничение параллельного выполнения нескольких потоков в одном процессе интерпретатора, так что даже на многоядерном процессоре для одного процесса интерпретатора потоки, работающие одновременно только предел один. Для Python GIL — это не функция самого языка, а функция реализации интерпретатора CPython.
Скомпилированный байт-код кода Python выполняется в интерпретаторе.Во время выполнения GIL, существующий в интерпретаторе CPython, заставляет только один поток выполнять байт-код за раз. Самая непосредственная проблема, вызванная существованием GIL, заключается в невозможности использования многоядерных процессоров для достижения истинного параллелизма в процессе интерпретатора за счет многопоточности.
Таким образом, многопоточность Python является псевдомногопоточностью и не может использовать многоядерные ресурсы.На самом деле одновременно работает только один поток.
GIL ограничивает многоядерное выполнение программ
- Только один поток может выполнять байт-код за раз
- Программы, интенсивно использующие ЦП, изо всех сил пытаются использовать преимущества нескольких ядер.
- GIL будет выпущен во время ввода-вывода, что мало повлияет на программы с интенсивным вводом-выводом.
Несмотря на существование GIL, у нас есть несколько способов улучшить производительность.
- Для задач с интенсивным вводом-выводом мы можем использовать многопоточность или сопрограммы для их выполнения.
- Замена интерпретатора без GIL, такого как Jython, возможна, но не рекомендуется, так как вы пропустите полезные функции во многих модулях языка C.
- Интенсивный процессор может использовать несколько процессов + пул процессов.
- Перенесите задачи, требующие больших вычислительных ресурсов, в модуль расширения Python C/C++.
Зачем беспокоиться о безопасности потоков в GIL?
GIL гарантирует эксклюзивность каждого байт-кода в процессе выполнения, то есть выполнение каждого байт-кода является атомарным. В GIL есть механизм освобождения, поэтому GIL не гарантирует, что поток не переключится во время выполнения байт-кода, то есть между несколькими байт-кодами поток имеет возможность переключения.
Мы можем использовать модуль dis Python для просмотра байт-кода, выполняемого с помощью += 1, и обнаружить, что для завершения требуется несколько байт-кодов, а поток имеет возможность переключения, поэтому он не является потокобезопасным.
Операция является атомарной, если она может быть завершена инструкцией байт-кода.Неатомарная операция не является потокобезопасной, но атомарная гарантированно будет потокобезопасной.
Гранулярность GIL и мьютекса потока различна: GIL — это взаимное исключение на уровне интерпретатора Python, которое гарантирует согласованность общих ресурсов на уровне интерпретатора, а мьютекс потока — это взаимное исключение на уровне кода (или на уровне пользователя). Исключение гарантирует согласованность общих данных на уровне программы Python, поэтому нам по-прежнему нужны блокировки мьютексов потоков и другие методы синхронизации потоков для обеспечения согласованности данных.
Для конкретного введения в GIL Python, пожалуйста, обратитесь к моей другой статье«Объяснение GIL в Python»
Что такое итераторы и генераторы?
Эта картина более захватывающая, обобщающая различные понятия.
контейнер
Контейнер можно понимать как структуру данных, которая организует несколько элементов вместе.Элементы в контейнере могут быть итеративно получены один за другим, а ключевые слова in, not in могут использоваться для определения того, содержится ли элемент в контейнере. Например, общие объекты-контейнеры в Python — это список, очередь, набор.
Итерации (итерации)
Большинство контейнеров являются итерируемыми объектами. Например, list или set являются итерируемыми объектами. Можно сказать, что пока они могут возвращать итератор, их можно называть итерируемыми объектами.
итератор
В питоне есть много контейнеров, таких как списки, кортежи, словари, наборы и т. д. Контейнеры можно интуитивно представить как единое целое с несколькими элементами вместе, и все контейнеры итерабельны (итерабельны).
Обычно мы используем оператор for in для перечисления итерируемых объектов.Основной механизм:
Итерируемый объект возвращает итератор (итератор) через функцию iter(), а итератор предоставляет следующий метод. После вызова этого метода вы либо получаете следующий объект контейнера, либо получаете ошибку StopIteration.
Например:
>>> x = [1, 2, 3]
>>> # Get the iterator
>>> y = iter(items) # Invokes items.__iter__()
>>> # Run the iterator
>>> next(y) # Invokes it.__next__()
1
>>> next(y)
2
>>> next(y)
3
>>> type(x)
<class 'list'>
>>> type(y)
<class 'list_iterator'>
>>> next(y)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
В приведенном выше примереx=[1,2,3]
Это итерируемый объект, также называемый здесь контейнером.y=iter(x)
является итератором и реализует__iter__
а также__next__
метод.
Связь между ними показана на следующем рисунке:
Видно, что после прохождения метода iter это итератор. Это объект с состоянием. Когда вызывается метод next, он возвращает следующее значение в контейнере. Можно сказать, что любой объект, реализующий методы iter и next, является итератором. Iter возвращает сам итератор, а next возвращает следующее значение в контейнере.значение или выдает исключение, если в контейнере больше нет элементов.
Итератор похож на фабрику с ленивой загрузкой: он ждет, пока он кому-то понадобится, прежде чем генерировать значение и возвращать его, когда он не вызывается, он спит и ждет следующего вызова.
генератор
Генератор можно просто понимать как ленивую версию итератора.
Его преимущество перед итераторами в том, что генераторы не занимают столько памяти, сколько итераторы. Например, чтобы объявить итератор:[i for i in range(100000000)]
Вы можете объявить список из 100 миллионов элементов, каждый из которых сохраняется в памяти после генерации. Но на самом деле, нам может и не нужно сохранять так много вещей, мы только надеемся, что при использовании функции next() будет сгенерирована следующая переменная, так рождается генератор, который написан на питоне как (i for я в диапазоне (100000000))
Кроме того, у генераторов могут быть и другие формы, такие как функции-генераторы, которые возвращают результат методу next() через ключевое слово yield, например:
def frange(start, stop, increment):
x = start
while x < stop:
yield x
x += increment
for n in frange(0, 2, 0.5):
print(n)
0
0.5
1.0
1.5
По сравнению с итераторами генераторы имеют следующие преимущества:
- уменьшить память
- Расчет задержки
- Эффективно улучшить читаемость кода
Однажды у меня было резюме генераторов и итераторов:«Итераторы и генераторы в Python»
На stackoverflow есть отличный ответ о доходности:
stackoverflow.com/questions/2…
Что такое корутина?
Для получения дополнительной информации см. мою статью для деталей."Подробное объяснение сопрограмм Python"
Что такое закрытие?
Определите другую функцию внутри функции, и эта функция использует переменные внешней функции, тогда эта функция и некоторые используемые переменные называются замыканиями.
Проще говоря, если во внутренней функции делается ссылка на переменную во внешней области видимости (но не в глобальной области видимости), то внутренняя функция считается замыканием. Давайте рассмотрим несколько простых примеров:
Самый простой пример, реализующий дополнение
def addx(x):
def adder(y):
return x + y
return adder
c = addx(8)
print(type(c))
print(c.__name__)
print(c(10))
<class 'function'>
adder
18
Реализация последовательностей Фибоначчи с использованием замыканий
from functools import wraps
def cache(func):
store = {}
@wraps(func)
def _(n):
if n in store:
return store[n]
else:
res = func(n)
store[n] = res
return res
return _
@cache
def f(n):
if n <= 1:
return 1
return f(n-1) + f(n-2)
print(f(10))
Рекомендовать статью:blog.CSDN.net/yeoman92/AR…
Что такое глубокая и поверхностная копия Python?
Обратите внимание на разницу между reference и copy(), deepcopy()
Взгляните на следующий пример:
import copy
a = [1, 2, 3, 4, ['a', 'b']] # 原始对象
b = a # 赋值,传对象的引用
c = copy.copy(a) # 对象拷贝,浅拷贝
d = copy.deepcopy(a) # 对象拷贝,深拷贝
a.append(5) # 修改对象a
a[4].append('c') # 修改对象a中的['a', 'b']数组对象
print('a = ', a)
print('b = ', b)
print('c = ', c)
print('d = ', d)
Результат:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
Управление памятью Python
Python имеет механизм пула памяти, механизм Pymalloc, для управления приложениями памяти и выпусками. Давайте сначала посмотрим, почему существует пул памяти:
Когда создается большое количество объектов, потребляющих небольшой объем памяти, частые вызовы new/malloc в c вызовут сильную фрагментацию памяти, что приведет к снижению эффективности.
Концепция пула памяти заключается в том, чтобы заранее подать заявку на определенное количество блоков памяти одинакового размера в памяти и зарезервировать его в качестве запасного.Когда возникает новая потребность в памяти, он сначала выделяет память из пула памяти для этого требовать, а потом обращаться за новым, когда не хватает ОЗУ. Наиболее значительным преимуществом этого является то, что он может уменьшить фрагментацию памяти и повысить эффективность.
Глядя на исходный код, вы можете видеть, что Pymalloc Для небольших объектов Pymalloc будет применять пространство в пуле памяти, как правило, менее 236 КБ.Если это большой объект, напрямую вызовите new/malloc для применения нового пространства памяти.
При создании памяти ее необходимо перерабатывать.Механизм сборки мусора также является точкой знаний, которую необходимо задать на собеседовании по Python.Далее давайте посмотрим, что из себя представляет механизм сборки мусора.
Механизм сборки мусора Python
У сборщика мусора есть две задачи: во-первых, найти бесполезные ресурсы объектов мусора в памяти, а во-вторых, очистить найденные объекты мусора и освободить память для использования другими объектами.
Python GC в основном использует подсчет ссылок для отслеживания и сбора мусора. На основе подсчета ссылок проблема циклических ссылок, которые могут генерироваться объектами-контейнерами, решается с помощью «пометки и очистки», а эффективность сборки мусора повышается с помощью «сборки генерации» путем замены пространства временем.
подсчет ссылок
Структура каждого объекта в исходном коде представлена следующим образом:
typedef struct_object {
int ob_refcnt;
struct_typeobject *ob_type;
} PyObject;
PyObject является обязательным для каждого объекта, а ob_refcnt используется в качестве счетчика ссылок. Когда объект имеет новые ссылки, его ob_refcnt увеличивается, а когда объект, ссылающийся на него, удаляется, его ob_refcnt уменьшается. Когда счетчик ссылок равен 0, объект немедленно освобождается, а пространство памяти, занятое объектом, освобождается.
преимущество:
- Простой
- В режиме реального времени, когда нет ссылки, память освобождается напрямую. Не ждите определенного момента, как в других механиках.
недостаток:
- Требуется дополнительное пространство для хранения счетчиков ссылок.
- Циклическая ссылка на объект не может быть разрешена. (основной недостаток)
Далее поговорим о том, что такое циклические ссылки:
А и В ссылаются друг на друга, и нет внешней ссылки ни на А, ни на В. То есть объекты накладываются друг на друга, в результате чего цепочка ссылок образует кольцо.
>>>>>>a = { } #对象A的引用计数为 1
>>>b = { } #对象B的引用计数为 1
>>>a['b'] = b #B的引用计数增1
>>>b['a'] = a #A的引用计数增1
>>>del a #A的引用减 1,最后A对象的引用为 1
>>>del b #B的引用减 1, 最后B对象的引用为 1
После выполнения del объекты A и B больше не имеют ссылок на эти два объекта, но каждый из этих двух объектов содержит ссылку на другой объект, хотя последние два объекта не могут ссылаться на эти два объекта через другие переменные, это , это два неактивных объекта или мусорные объекты. Теоретически его нужно перерабатывать.
В соответствии с приведенным выше принципом подсчета ссылок коллекция не будет собираться до тех пор, пока счетчик не станет равным 0, но их счетчик ссылок не уменьшится до нуля. Следовательно, если для управления этими двумя объектами используется метод подсчета ссылок, они не будут восстановлены, они всегда будут находиться в памяти, что вызовет утечку памяти (пространство памяти не освобождается после использования).
Чтобы решить проблему циклической ссылки на объекты, Python вводит два механизма GC: очистку меток и повторное использование поколений.
метко-разметающий механизм
Очистка меток в основном предназначена для решения проблемы циклических ссылок.
Алгоритм маркировки-очистки — это алгоритм сборки мусора, основанный на технологии трассировки сборщика мусора.
Он разделен на два этапа: первый этап — этап маркировки, GC будет помечать все активные объекты, а второй этап — перерабатывать те объекты, которые не отмечены, т. е. неактивные объекты. Так как же GC определяет, какие объекты являются активными, а какие неактивными?
Объекты связаны между собой ссылками (указателями) для формирования ориентированного графа, объекты образуют узлы этого ориентированного графа, а отношения ссылок образуют ребра этого ориентированного графа. Начиная с корневого объекта, объекты обходят по направленному ребру, при этом достижимые объекты помечаются как активные объекты, а недоступные объекты являются неактивными объектами, подлежащими очистке. Корневыми объектами являются глобальные переменные, стеки вызовов и регистры.
Технология генерации
Коллекция поколений — это операция, которая обменивает пространство на время.
Python делит память на разные наборы в соответствии со временем выживания объектов. Каждый набор называется поколением. Python делит память на 3 «поколения», а именно: молодое поколение (0-е поколение), среднее поколение (1-е поколение), старое поколение (2-е поколение). генерации), они соответствуют 3 связанным спискам, и их частота сборки мусора уменьшается с увеличением времени выживания объекта. Вновь созданные объекты будут размещены в молодом поколении.Когда общее количество молодых репрезентативных связанных списков достигнет верхнего предела, будет запущен механизм сборки мусора Python, чтобы удалить те объекты, которые могут быть восстановлены, в то время как те, которые не будут восстановлены, будут быть перемещены в средний возраст и т. д., объекты в старости — это объекты, которые выживают дольше всего, даже в жизненном цикле всей системы. В то же время рециркуляция поколений основана на технологии маркировки.
Объектно-ориентированный
Что такое композиция и наследование?
- Композиция заключается в использовании другого экземпляра класса в качестве одного из его свойств (имеет отношение).
- Наследование заключается в том, что подкласс наследует свойства и методы родительского класса (является отношением)
- Предпочитайте композицию, чтобы код оставался простым
Разница между переменной класса и переменной экземпляра?
- Переменные класса являются общими для всех экземпляров
- Переменные экземпляра принадлежат только экземпляру и не зависят от других экземпляров.
- Переменные класса используются, когда нам нужно разделить переменные между разными экземплярами класса.
В чем разница между методом класса и статическим методом?
- Может использоваться Class.method()
- Первый параметр classmethod — cls, который может ссылаться на переменные класса.
- Использование статического метода такое же, как и обычных функций, за исключением того, что он организован в классе
- classmethod заключается в использовании переменных класса, staticmethod необходим для организации кода и может быть размещен вне класса
В следующем примере показано использование переменных класса, переменных экземпляра, методов класса, обычных методов и статических методов.
class Person:
Country = 'china'
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
@classmethod
def print_country(cls):
print(cls.Country)
@staticmethod
def join_name(first_name, last_name):
return print(last_name + first_name)
a = Person("Bruce", "Lee")
a.print_country()
a.print_name()
a.join_name("Bruce", "Lee")
Person.print_country()
Person.print_name(a)
Person.join_name("Bruce", "Lee")
Больше ссылок:
__new__
а также__init__
разница?
-
__new__
является статическим методом, а__init__
является методом экземпляра. -
__new__
метод возвращает созданный экземпляр, а__init__
ничего не возвращает. - только в
__new__
После возврата экземпляра cls__init__
быть вызванным. - Вызывается при создании нового экземпляра
__new__
, используется при инициализации экземпляра__init__
.
Мы можем провести несколько интересных экспериментов.
class Person:
def __new__(cls, *args, **kwargs):
print("in __new__")
instance = super().__new__(cls)
return instance
def __init__(self, name, age):
print("in __init__")
self._name = name
self._age = age
p = Person("zhiyu", 26)
print("p:", p)
Вывод этой программы:
in __new__
in __init__
p: <__main__.Person object at 0x00000261FE562E50>
Вы можете видеть, что новый метод сначала выполняется для создания объекта, а затем инициализируется init. Предполагая, что объект не возвращается в новом методе, каков будет результат?
class Person:
def __new__(cls, *args, **kwargs):
print("in __new__")
instance = super().__new__(cls)
#return instance
def __init__(self, name, age):
print("in __init__")
self._name = name
self._age = age
p = Person("zhiyu", 26)
print("p:", p)
Обнаружено, что если new не возвращает созданный объект, init не может быть инициализирован.
Результат:
in __new__
p: None
Что такое метакласс?
Метакласс — это класс, который создает класс
- Метаклассы позволяют нам управлять генерацией классов, например, изменять свойства классов и т. д.
- Используйте тип для определения метаклассов
- Одним из наиболее распространенных сценариев использования метаклассов являются фреймворки ORM.
Что такое декораторы в Python?
- Все в питоне является объектом, и функции также могут передаваться как параметры.
- Декоратор — это функция (класс), которая принимает функцию в качестве параметра и возвращает новую функцию после добавления функции
- Использование декораторов через @ в питоне, синтаксический сахар
Пример: Напишите декоратор, который записывает, сколько времени занимает функция:
import time
def log_time(func): # 接受一个函数作为参数
def _log(*args, **kwargs):
beg = time.time()
res = func(*args, **kwargs)
print('use time: {}'.format(time.time() - beg))
return res
return _log
@log_time # 装饰器语法糖
def mysleep():
time.sleep(1)
mysleep()
# 另一种写法,和上面的调用方式等价
def mysleep2():
time.sleep(1)
newsleep = log_time(mysleep2)
newsleep()
Конечно, декораторы могут принимать параметры
def log_time_with_param(use_int):
def decorator(func): # 接受一个函数作为参数
def _log(*args, **kwargs):
beg = time.time()
res = func(*args, **kwargs)
if use_int:
print('use time: {}'.format(int(time.time()-beg)))
else:
print('use time: {}'.format(time.time()-beg))
return res
return _log
return decorator
@log_time_with_param(True)
def my_sleep6():
time.sleep(1)
Вы также можете использовать класс в качестве декоратора
class LogTime:
def __call__(self, func): # 接受一个函数作为参数
def _log(*args, **kwargs):
beg = time.time()
res = func(*args, **kwargs)
print('use time: {}'.format(time.time()-beg))
return res
return _log
@LogTime()
def mysleep3():
time.sleep(1)
mysleep3()
Вы также можете добавить параметры в декораторы классов.
class LogTime2:
def __init__(self, use_int=False):
self.use_int = use_int
def __call__(self, func): # 接受一个函数作为参数
def _log(*args, **kwargs):
beg = time.time()
res = func(*args, **kwargs)
if self.use_int:
print('use time: {}'.format(int(time.time()-beg)))
else:
print('use time: {}'.format(time.time()-beg))
return res
return _log
@LogTime2(True)
def mysleep4():
time.sleep(1)
mysleep4()
@LogTime2(False)
def mysleep5():
time.sleep(1)
mysleep5()
Также поговорим о порядке вывода декоратора
@a
@b
@c
def f ():
pass
Последовательность выполнения вышеуказанной программы такова.f = a(b(c(f)))
магический метод в питоне
-
__new__
используется для создания экземпляра -
__init__
используется для инициализации экземпляра
Эти два были упомянуты выше, и есть еще магические методы:
__call__
Прежде всего, необходимо понять, что такое вызываемый объект.Обычно к вызываемым объектам относятся пользовательские функции, встроенные функции и классы.Все, что может применить к объекту пару скобок () можно назвать вызываемым объектом. Независимо от того, является ли объект вызываемым объектом, можно использовать вызываемую функцию.
Пожалуйста, обратитесь к следующему примеру кода, чтобы понять:
class A:
def __init__(self):
print("__init__ ")
super(A, self).__init__()
def __new__(cls):
print("__new__ ")
return super(A, cls).__new__(cls)
def __call__(self): # 可以定义任意参数
print('__call__ ')
a = A()
a()
print(callable(a)) # True
Результат:
__init__
__call__
True
__call__ печатается при выполнении a(). a является созданным объектом, а также вызываемым объектом.
-
__del__
, Деструктор, при удалении объекта будет выполняться этот метод, при уничтожении объекта в памяти этот метод будет вызываться автоматически.
import time
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def __del__(self): # 在对象被删除的条件下,自动执行
print('__del__')
obj = People("zhiyu", 26)
# del obj
time.sleep(5)
После выполнения программы можно обнаружить, что через 5 с вывод консоли
__del__
Каковы общие шаблоны проектирования в Python?
Из-за большого количества контента я составил отдельную статью.«Шаблоны проектирования, обычно используемые в Python»
Обратите внимание на различные способы написания шаблона singleton.
Статьи о фреймворке Django
todo
использованная литература
Китайская версия ответа stackoverflow:Prince Longxu.git books.IO/stack над Флоридой…
«Гладкий питон»
Китайская версия кулинарной книги Python:Python3-cookbook.Прочитайте документ S.IO/this_cn/latshan…
Завершение интервью на GitHub:
Ресурсы для интервью в Интернете:
Официальная документация Python: