五、深入类和对象
一、鸭子类型和多态
鸭子类型是一种动态类型的概念,它指的是在动态语言中,一个对象的适用性不是由它的类别(类型)决定的,而是由它的方法和属性决定的。这个概念来源于“走起来像鸭子,叫起来像鸭子,那么它就是鸭子”的说法。也就是说 ,如果一个对象具有某个方法或属性,那么它就可以被当作拥有该方法或属性的类型来使用。
多态是面向对象编程中的一个重要概念,它指的是同一个方法在不同的对象上有不同的行为。在多态的情况下,一个方法可以根据调用它的对象的类型,表现出不同的行为。这样可以提高代码的灵活性和可复用性,因为不同的对象可以共享相同的接口,但实现不同的行为。
鸭子类型和多态都是在编程中提高灵活性和可复用性的重要概念,它们都可以让代码更加灵活和易于扩展。在动态语言中,鸭子类型可以让我们更加灵活地处理对象的类型,而多态则可以让我们更加灵活地处理对象的行为。
class Cat(object):
def say(self):
print("i am a cat")
class Dog(object):
def say(self):
print("i am a dog")
def __str__(self):
return "Dog"
class Duck(object):
def say(self):
print("i am a duck")
class Company(object):
def __init__(self,employee_list):
self.employee_list = employee_list
def __getitem__(self, item):
return self.employee_list[item]
def __str__(self):
return ",".join(self.employee_list)
def __repr__(self):
return ",".join(self.employee_list)
company = Company([Cat,Dog,Duck])
#多态
for item in company:
item().say()
# extend
a = ['a1','a2']
name_set = set()
name_set.add("b1")
name_set.add("b2")
a.extend(name_set)
#company 找不到__iter__ 会去找__getitems__
a.extend(company)
print(a)
#结果
i am a cat
i am a dog
i am a duck
['a1', 'a2', 'b2', 'b1', <class '__main__.Cat'>, <class '__main__.Dog'>, <class '__main__.Duck'>]
二、抽象基类(abc模块)
Python抽象基类是一种用于定义接口和规范子类实现的类。它们通常用作基类,不能直接实例化。抽象基类定义了一组抽象方法,子类必须实现这些方法才能被实例化。
抽象基类可以帮助开发人员在设计和编写代码时更好地组织和管理类的结构。通过定义抽象基类,可以明确规定子类需要实现的方法和属性,从而提高代码的可读性和可维护性。
Python的抽象基类是通过abc模块提供的ABC类和abstractmethod装饰器来实现的。通过继承ABC类并使用abstractmethod装饰器来定义抽象方法,可以创建一个抽象基类。子类必须实现所有抽象方法才能被实例化,否则会引发TypeError异常。
总之,Python抽象基类是一种用于定义接口和规范子类实现的类,可以帮助开发人员更好地组织和管理类的结构,提高代码的可读性和可维护性。
import abc
#from collections.abc import *
#定义基类
class CacheBase(metaclass=abc.ABCMeta):
@abc.abstractmethod
def get(self,key):
pass
@abc.abstractmethod
def set(self,key,value):
pass
class RedisCache(CacheBase):
def __init__(self):
pass
#必须实现基类
def get(self,key):
pass
def set(self,key,value):
pass
redisCache = RedisCache()
三、使用isinstance而不是type
class A:
pass
class B(A):
pass
b=B()
print(isinstance(b,B)) #True
print(isinstance(b,A)) #True 根据链网上找,最后相同,打印True
print(type(b) is B) #True type(b) 实际上是指向的B这个对象,他们是比较的id() 值
print(type(b) == B) #True
print(type(b) == A) #False
# 在这个例子中:
#
# type(b) is B 和 type(b) == B 都返回 True,是因为 type(b) 返回的是 b 对象的类型,而这个类型正是 B。
# 类型对象本身是单例的(即每个类在内存中只有一个类型对象),因此 type(b) is B 和 type(b) == B 在这种情况下结果是一样的。
# 总结:
#
# is 用于判断两个变量是否引用同一个对象。
# == 用于判断两个变量的值是否相等。
四、类变量和示例变量
class A:
aa = 1 #类变量是所有实例共有的
def __init__(self,x,y):
self.x = x
self.y = y
a = A(2,3)
print(a.x,a.y,a.aa) #2 3 1 a.aa 实例找不到,于是向上查找,找到类变量
print(A.aa) #1
a.aa = 100
print(a.aa,A.aa) #100 1 a.aa 相当于给该实例添加属性并赋值, 但是不会影响类变量, 类变量可以通过A.aa 进行修改
五、类属性和实例属性的查找顺序
在Python中,当访问一个属性时,解释器会按照以下顺序查找属性:
1.首先查找实例属性:如果该属性在实例中存在,则返回实例属性的值。
2.如果实例中不存在该属性,则查找类属性:如果该属性在类中存在,则返回类属性的值。
3.如果类中也不存在该属性,则查找父类的属性:如果该属性在父类中存在,则返回父类属性的值。
4.如果以上步骤都没有找到该属性,则会引发AttributeError异常。
因此,查找顺序为:实例属性 -> 类属性 -> 父类属性。
MRO(Method Resolution Order)是指在多重继承的情况下,确定方法调用顺序的一种算法。在Python中,使用C3线性化算法来确定MRO查找顺序。
MRO查找顺序遵循以下规则:
1.首先考虑子类的MRO顺序,然后再考虑父类的MRO顺序。
2.如果一个类有多个父类,则会按照它们在类定义中的顺序进行查找。
3.如果一个类有多个父类,而这些父类又有共同的父类,则会按照深度优先的原则进行查找。
通过MRO查找顺序,Python能够确定在多重继承的情况下,方法的调用顺序,从而保证程序能够正确地执行。
六、静态方法、类方法以及对象方法以及参数
class Date:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
#实例方法
def tomorrow(self):
self.day += 1
#静态方法
@staticmethod
def parse_from_string(date_str):
#tuple入参为可迭代对象
year,month,day = tuple(date_str.split("-"))
return Date(int(year), int(month), int(day))
#类方法 cls为类对象本身
@classmethod
def from_string(cls,date_str):
# tuple入参为可迭代对象
year, month, day = tuple(date_str.split("-"))
return cls(int(year), int(month), int(day))
#相当于java 中的toString() 方法
def __str__(self):
return "{year}/{month}/{day}".format(year=self.year,month=self.month,day=self.day)
if __name__ == '__main__':
new_day = Date(2024,6,13)
new_day.tomorrow()
print(new_day) #2024/6/14
new_day_2 = Date.parse_from_string("2024-06-15")
print(new_day_2) #2024/06/15
new_day_3 = Date.from_string("2024-06-15")
print(new_day_3) #2024/06/15
七、数据封装和私有属性
在Python中,数据封装是一种将数据和操作数据的方法捆绑在一起的概念。这可以通过类和对象来实现。在类中,可以定义属性和方法来操作这些属性,从而实现数据封装。
Python中的私有属性是指在类的内部使用双下划线(__)开头命名的属性。这样的属性只能在类的内部访问,外部无法直接访问。但是,可以通过类的方法来间接访问和修改私有属性。这种做法可以保护数据,防止外部直接修改,从而提高数据的安全性和封装性。
八、python对象的自省机制
Python的自省机制是指Python解释器能够检查对象的类型、属性和方法的能力。通过自省机制,我们可以在运行时获取对象的信息,包括对象的类型、属性、方法等。
Python提供了一些内置函数和模块来实现自省机制,例如:
1.type()函数:用于获取对象的类型。
2.dir()函数:用于获取对象的所有属性和方法。
3.id()函数:用于获取对象的内存地址。
4.inspect模块:提供了更高级的自省功能,可以用于获取函数、类、模块等的源代码、注释等信息。
通过自省机制,我们可以在运行时动态地获取对象的信息,这对于调试、动态调用方法、动态创建对象等场景非常有用。同时,自省机制也是Python动态语言特性的体现,使得Python具有更灵活的编程能力。
class Person:
name = "张三"
class Student(Person):
def __init__(self,school_name):
self.school_name = school_name
if __name__ == '__main__':
user = Student("慕课网")
#通过__dict__查询属性
print(user.__dict__)
#赋值
user.__dict__['school_addr'] = '北京市'
print(user.school_addr)
print(Person.__dict__)
print(Person.name)
print(dir(user))
# {'school_name': '慕课网'}
# 北京市
# {'__module__': '__main__', 'name': '张三', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
# 张三
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'school_addr', 'school_name']
九、super是真的调用父类吗
根据mro顺序进行逐步调用
十、mixin模式
在Python中,Mixin模式是一种通过多继承来实现代码重用的方式。Mixin是一个包含一些方法和属性的类,它通常不会被单独实例化,而是被其他类继承并用于增强其功能。
Mixin模式的主要特点是将通用的功能封装在一个类中,然后通过多继承的方式将这些功能添加到其他类中。这样可以避免代码重复,提高代码的可重用性和可维护性。
在Python中,Mixin模式通常用于实现一些通用的功能,比如日志记录、缓存、权限控制等。通过将这些功能封装在Mixin类中,可以方便地将它们添加到其他类中,而不需要重复编写代码。
Mixin模式在Python中的应用非常广泛,它是一种简单而有效的代码重用方式,可以帮助我们编写更加模块化和可维护的代码。
十一、python中的with语句
先了解 try catch语句
def exe_try():
try:
print("code_started")
raise KeyError
return 1
except KeyError as e
print("keyError")
return 2
else:
print("other error")
return 3
finally:
print("finally")
return 4
exe_try() # 返回4 因为finally的return 会覆盖 except的return 如果注释掉finally的return , 会返回2
上下文管理器协议
class Sample:
def __enter__(self):
# 获取资源
print("enter")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# 释放资源
print("exit")
def do_something(self):
print("do something")
if __name__ == "__main__":
with Sample() as sample:
sample.do_something()
# 打印结果
# enter
# do something
# exit
十二、contextlib简化上下文管理器
import contextlib
@contextlib.contextmanager
def file_open(file_name):
print("file open")
yield {}
print("file close")
with file_open("bobby") as f_opened:
print("do something")
# 结果
C:\Users\Admin\miniconda3\python.exe F:/code/study/python_test/chapter4.4/contextlib_test.py
file open
do something
file close
评论区