Когда вы впервые изучаете Python или другие объектно-ориентированные языки программирования, вы неизбежно не будете хорошо понимать классы и объекты. поэтому сегодняПоделитесь с вами классами и объектами в python и получите глубокое понимание классов и объектов в python.
1. Утиный тип
Когда вы видите птицу, которая ходит, как утка, плавает, как утка, и крякает, как утка, тогда эту птицу можно назвать уткой. Это определение утиного типа.В питоне неважно, какого типа объект, только его поведение. Тип объекта выводится из поведения. Например, списки, кортежи, словари и т. д. Эти классы являются итерируемыми, поэтому они являются итерируемыми объектами.
from collections import Iterable
l = [1, ]
t = (1, )
d = {'d': 3}
print(isinstance(l, Iterable))
print(isinstance(t, Iterable))
print(isinstance(d, Iterable))
# 结果
True
True
True
2. Переменные класса и переменные экземпляра
Переменные класса определены в классе, но не в методе, и префикс не имеет ссылки на себя. Переменная экземпляра — это переменная, которая существует в классе со ссылкой на себя. Переменные класса являются общими для всех объектов, и при изменении в классе другие объекты также будут изменяться. Однако следует отметить, что если объект используется для ссылки на переменную класса для модификации, здесь заново создается только переменная экземпляра с тем же именем, что и у переменной класса, и она не модифицируется. Код объясняется ниже.
class Student(object):
conutry = 'China' # 这个是类变量
def __init__(self, name, sex):
self.name = name # 这个是实例变量,也就是对象变量
self.sex = sex # 对象变量
s1 = Student('张三', 'man')
s2 = Student('里斯', 'woman')
print(s1.conutry)
print(s2.conutry)
print(Student.conutry)
Вышеприведенные результаты - это все три China, это легко понять, когда класс используется для ссылки на изменение
Student.conutry = 'cn' # 这个是用类引用来进行修改
После модификации следующие три результата будут напечатаны как измененные результаты. Но как насчет того, что ниже?
s1.conutry = 'zhongguo' # 用实例来引用进行修改
На этот раз результат другой, изменилась только переменная класса s1, а две другие не изменились. Почему это? Как упоминалось выше, когда ссылка на экземпляр используется для изменения переменной класса, это не модификация, а новая переменная. А поскольку python ищет переменные снизу вверх, он сначала найдет только что созданную переменную.
3. Порядок доступа между атрибутами класса и атрибутами экземпляра
Свойства класса — это методы и переменные, определенные в классе, а также свойства экземпляра. Порядок доступа ищется снизу вверх, и вы можете испытать его с помощью кода.
class A():
name = 'A'
def __init__(self):
self.name = 'a'
a = A()
print(a.name)
# 结果
a
Поскольку сначала загружается переменная класса, а затем инициализируется объект, запускается метод __init__(), поэтому результат, очевидно, будет a. Поскольку класс не имеет наследования, он не очень сложен, но когда происходит множественное наследование, между несколькими классами становится очень сложно, и порядок доступа в это время намного сложнее. Давайте поговорим об этих двух ситуациях ниже.После освоения этих двух ситуаций, в принципе, нет проблем с другой.
(1. Подходит для поиска в глубину
A наследует B, C, B, C наследует D, E соответственно. Поиск в глубину заключается в том, чтобы сначала перейти к A, если такого атрибута в A нет, перейти к B, а затем перейти к D, чтобы найти его. Если вы не можете найти его в D, перейдите в C, чтобы найти его. Этот случай поиска в порядке, но другой случай - нет.
2) Подходит для поиска в ширину
Это то, что A наследует B, C, а B и C наследуют D. Если при этом используется алгоритм поиска в глубину, возникнет проблема, поскольку порядок поиска в глубину следующий: A->B->D->C. Это неразумно. Когда метод в D перегружен в C, B не перегружен. Если вы хотите найти метод в C, вы можете найти исходный метод в D только с помощью алгоритма поиска в глубину, поэтому это неправильно чтобы сказать, что в настоящее время необходимо использовать алгоритм поиска в ширину В настоящее время порядок поиска A->B->C->D. Но когда возникает описанная выше ситуация, ошибка возникает снова. Что мне делать тогда? python3 объединяет все алгоритмы поиска атрибутов в один алгоритм: алгоритм C3, который здесь не обсуждается, потому что он слишком сложен:) Соответствующий алгоритм будет реализован согласно соответствующей ситуации, и следующий код будет использоваться для проверки вышеописанного два соответственно ситуация
class E():
pass
class D():
pass
class C(E):
pass
class B(D):
pass
class A(B, C):
pass
print(A.__mro__)
# 结果
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
Атрибут __mro__ — это порядок поиска для получения атрибутов.Видно, что, как мы сказали выше, используется алгоритм поиска в глубину. посмотри на другой
class D():
pass
class C(D):
pass
class B(D):
pass
class A(B, C):
pass
print(A.__mro__)
# 结果
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
В настоящее время используется алгоритм поиска в ширину, который соответствует тому, что мы только что сказали, и это алгоритм C3.
4. Действительно ли super вызывает родительский класс?
Любой, кто изучал Java, знает, что метод super() должен вызывать метод родительского класса, но не обязательно в python. Давайте сначала посмотрим на использование супер
class A():
def __init__(self):
print('A')
class B(A):
def __init__(self):
# python2做法是
# super(A, self).__init__()
super().__init__() # 调用父类的初始化方法
print('B')
b = B()
# 结果
A
B
Выше приведено использование.Использование python2 и python3 отличается.Здесь мы используем только python3 для работы. Далее смотрим на реальный вызов супер.
class A():
def __init__(self):
print('A')
class B(A):
def __init__(self):
super().__init__()
print('B')
class C(A):
def __init__(self):
super().__init__()
print('C')
class D(B, C):
def __init__(self):
super().__init__()
print('D')
d = D()
Вышеуказанное является множественным наследованием, подходящим для алгоритма в ширину, о котором мы упоминали ранее.Согласно нашему предыдущему пониманию, super вызывает родительскую функцию, тогда результатом будет:
A B C D
Видимо неправильно, результат такой
Вы находите это странным, но знакомым? Да, это также выполняется в том же порядке поиска, что и сейчас. Если вы не верите, мы можем напечатать __mro__, чтобы узнать
Это просто воспоминание? Поскольку мы сначала печатаем родительский класс, а затем собственный, порядок обратный. Давайте посмотрим на другую ситуацию, также осуществимую
class A():
def __init__(self):
print('A')
class B():
def __init__(self):
super().__init__()
print('B')
class C(A):
def __init__(self):
super().__init__()
print('C')
class D(B):
def __init__(self):
super().__init__()
print('D')
class E(D, C):
def __init__(self):
super().__init__()
print('E')
e = E()
print(E.__mro__)
# 结果
A
C
B
D
E
(<class '__main__.E'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Также как и ожидалось. Как правило, super не обязательно вызывает родительский класс, и его последовательность вызова также следует алгоритму mro, который представляет собой алгоритм поиска атрибутов, совместимый с упомянутым выше алгоритмом C3.
Если у вас есть какие-либо вопросы, задавайте их в области сообщений или указывайте на неуместные места.
p.s. Если вы считаете, что статья хорошая, ставьте лайк и перешлите в поддержку
Изучайте Python каждый день
Код — это не только баги, но и красота и веселье