11.7-11.11 周末小结
一、面向对象三大特性之封装
1.封装简介:
封装:就是将数据和功能封装起来,封装是一种概念
baike封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将[数据]与操作数据的[源代码]进行有机的结合,形成“类”
2.隐藏
隐藏:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别(在接口内添加额外的操作)
类在定义阶段,名字前面加两个下划线,那么该名字会被隐藏起来,无法直接访问
class MyClass: __name = 'duo' def __func(self): pass # 属性和方法名字前面加双下__也可以隐藏
3.伪装
伪装:将类中的方法伪装成属性,可以用点号运算符来调用,被修饰符@property修饰的函数
(1)只有 @property
表示 只读 。
(2)同时有 @property
和@*.setter
表示 可读可写 。
(3)同时有 @property
和 @*.setter
和@*.deleter
表示可读可写可删除。
二、面向对象三大特性之多态
1.多态的含义
多态:一种事物的多种形态
面向对象的多态:拥有相同功能的类,这些类的功能应该被命名为同一个方法名
2.抽象与多态
多态的实际操作:抽象
由于类 Cat 中有talk方法,而其他和Cat相同类别的类,也可以有talk方法,所以可以将talk方法抽象出来,让Cat和具有相同功能的类去继承这个基类Animal,这个时候我们可以说Animal是抽象基类。
import abc # 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化 class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法 def talk(self): # 抽象方法中无需实现具体的功能 pass class Cat(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准 def talk(self): pass cat = Cat() # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化
三、面向对象之反射
反射:introsepction自省的一种方式,利用字符串操作对象的数据和方法,
主要用于和对象交互
1. hasattr:判断一个方法是否存在与这个类中 2. getattr:根据字符串去获取obj对象里的对应的方法的内存地址,加"()"括号即可执行 3. setattr:通过setattr将外部的一个函数绑定到实例中 4. delattr:删除一个实例或者类中的方法
1.hasattr(object, name)
返回布尔值,判断某个属性或者方法是否在这个对象中
2.getattr(object, name)
拿到对象中名字所对应的值并返回,如果没有则报错
3.setattr(object, name, value)
根据字符串给对象设置或者修改数据
4.delattr(object, name)
根据字符串删除对象里面的名字
四、面向对象之魔法方法
(1)__init__
对象实例化的时候自动触发
(2)__str__
对象被执行打印(print、前端展示)操作的时候自动触发,方法必须返回字符串类型的数据,很多时候用来更加精准的描述对象(通过str方法可以区分打印的是哪个对象)
(3)__call__
对象加括号调用的时候自动触发,当类中没有__call__
的时候该类产生的对象不可调用
(4)__getattr__
对象查找不存在名字的时候自动触发
(5)__getattribute__
只要对象查找名字无论名字是否存在都会执行该方法,如果类中有__getattribute__
方法 那么就不会去执行__getattr__
方法
(6)__setattr__
对象在执行添加属性操作的时候自动触发 >>> obj.变量名=变量值
(7)__enter__
当对象被当做with上下文管理操作的开始自动触发,并且该方法返回什么 as后面的变量名就会接收到什么
(8)__exit__
对象被执行with上下文管理语法结束之后自动触发
(9)__del__
对象被执行(被动、主动)删除操作之后自动执行
(10)__new__
__new__
方法来产生的一个空对象
五、元类
1.元类简介
我们定义的类其实都是有type类产生的>>>type类被称为元类,类本身不过是一个名为 type 类的实例
2.元类的用法
(1)元类定制类的行为:创建类的两种方法
1)使用关键字class
class MyClass: pass print(MyClass) print(MyClass.__dict__) -------------结果------------- <class '__main__.MyClass'>
2)利用元类type
元类初始化实例的参数为**:type(类名what, 类的父类bases,类的名称空间dict)
# 则可以用变量名来接收元类type初始化实例后的结果,其结果就是一个type元类产生的类 cls = type('Student', (object,), {}) print(cls) print(cls.__dict__) -----------结果-------------- <class '__main__.Student'> {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None} # 通过type也可以产生类,并且cls的名称空间中也具有和关键字class所产生的类一样的名字
(2)元类定制类的产生行为
1.自定义元类:继承了type到类也称之为元类 class MyMetaClass(type): def __init__(self, what, bases=None, dict=None): """what是类名,bases是父类,dict是名称空间""" if not what.istitle(): raise TypeError('类名首字母应该大写') super().__init__(what, bases, dict) 2.指定类的元类:利用关键值metaclass指定类的元类 class myclass(metaclass=MyMetaClass): # TypeError: 类名首字母应该大写 当首字母没有大写当时候,则会报错 desc = '你好' class Myclass(metaclass=MyMetaClass): # 类名首字母大写则不会报错 desc = '你好'
(3)元类定制对象的产生行为
class MyMetaClass(type): def __call__(self, *args, **kwargs): if args: raise TypeError('无法位置传参') return super().__call__(*args, **kwargs) # __call__的值必须返回才能获得 class Student(metaclass=MyMetaClass): def __init__(self, name, age, hobby): print('init') self.name = name self.age = age self.hobby = hobby obj = Student(name='duoduo', age=18, hobby='read') print(obj.__dict__) # {'name': 'duoduo', 'age': 18, 'hobby': 'read'}
六、设计模式之单例模式
设计模式:前人通过大量的验证,所创建出来的解决一些问题的固定高效方法
单例模式:确保一个类最多只有一个实例,在整个程序就使用一个对象,可以节省内存空间
1.基于模块的单例
提前产生一个对象,之后导模块使用
class C1: def __init__(self, name): self.name = name obj = C1('duoduo') """ 在其他py文件中,去导入该obj, 由于导入模块只发生一次,那么在该文件中 那么这些对象的id()是一样的 """
2.装饰器@classmethod实现单例模式
class C1: __instance = None def __init__(self, host, port): self.host = host self.port = port @classmethod def singleton(cls): if not cls.__instance: cls.__instance = cls('duoduo', []) return cls.__instance obj1 = C1.singleton() obj2 = C1.singleton() obj3 = C1.singleton() # 此时obj1、obj2、obj3的id地址都是一样的
七、pickle序列化模块
pickle能够序列化python中所有类型的数据,但是只限制于python中使用。一般用于将一个对象序列化到文件中保存,这样用pickle读取出来还是这样一个对象。
pickle读取或者写入的时候,都只能用二进制模式。
import pickle # 写入 with open(r'a.txt', 'wb') as f: pickle.dump(obj, f) # 读取 with open(r'a.txt', 'rb') as f: res = pickle.load(f) print(res) # <__main__.C1 object at 0x10454bdc0>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)