Python之旅8 - Python面向对象
OOA 面向对象分析(全称Object-Oriented Analysis)
OOD 面向对象设计(全称Object-Oriented Design)
OOP 面向对象编程(全称Object-Oriented Programming)
面向对象里面最为基本的组成单元:类与对象
类与对象的基本概念::
类: 是对一个客观群体特征的抽象描述(类的两个基本组成单元:属性Variable 方法Method)
对象:表示的是一个个具体的事物的描述
类是对象的模板,对象是类的实例
示例:定义一个类,实例化并调用
1 # 定义一个类 2 class Member: 3 def set_info(self, name, age): # 定义一个设置信息的方法 4 """ 5 定义信息设置方法,该方法需要接收name,age两个参数 6 self描述的是当前对象的实例,只要是类中的方法都需要加上这个描述self 7 """ 8 self.name = name # 为类中的方法定义实例属性 9 self.age = age 10 11 def get_info(self): 12 return "姓名:%s,年龄:%d" % (self.name, self.age) 13 14 15 # 实例化一个men对象 16 men = Member() 17 men.set_info("小明", 18) 18 men.get_info() 19 print("类外部调用属性 name属性内容%s,age属性内容%d" % (men.name, men.age))
注意: 类中定义的是方法(Method)不是函数(Function)
面相关对象的3大特性:封装、继承、多态
1、封装属性:
封装性是面向对象的第一大特征,默认情况下,类中的全部属性可以在类的外部直接通过对象进行调用,这样就会造成属性操作的不安全性.
所以在类中定义的属性就需要通过封装来进行私有化定义,定义时 使用"__属性名称"(两个下划线)定义即可
示例:封装私有属性,并访问
1 class Meber2: 2 def set_info(self, name, age): 3 self.__name = name # 定义私有属性 4 self.__age = age 5 6 def get_info(self): 7 return "姓名:%s,年龄:%d" % (self.__name, self.__age) 8 9 def get_name(self): 10 return self.__name 11 12 def get_age(self): 13 return self.__age 14 15 16 men2 = Meber2() 17 men2.set_info("xiaoming", 18) 18 men2.get_info() 19 # print("类外部调用属性 name属性内容%s,age属性内容%d" % (men2.__name, men2.__age)) # 此时在类的外部不可以直接调用类属性 20 print(men2.get_name(), men2.get_age()) # 通过定义好的方法间接访问name和age属性
类的构造和析构
构造方法是在类中定义的一种特殊方法,主要功能是可以在类对象实例化时进行一些初始化操作的定义
定义要求如下:
构造方法的名称必须定义为__init__();
构造方法是实例化对象的起点,不允许有返回值;
一个类中只允许定义0个或1个构造方法,不允许出现多个构造方法的定义。
注意:其实在开发中没有我们没有定义构造方法时,python会自动帮我们生成一个无参数的构造方法
示例:
1 class Member3: 2 def __init__(self, name, age): 3 self.__name = name 4 self.__age = age 5 6 def get_info(self): 7 return "姓名:%s,年龄:%s" % (self.__name, self.__age) 8 9 10 men3 = Member3("小明", 18) 11 print(men3.get_info())
构造方法中的关键字参数
在构造方法中使用了可变的关键字参数,当用户调用无参构造时(不传递参数)对应的属性内容就设置为None
示例:
1 class Member4: 2 def __init__(self, **kwargs): 3 self.__name = kwargs.get("name") 4 self.__age = kwargs.get("age") 5 6 def get_info(self): 7 return "姓名:%s,年龄:%s" % (self.__name, self.__age) 8 9 10 mem4 = Member4(name="小明", age=18) 11 print(mem4.get_info()) # 姓名:小明,年龄:18 12 mem4_1 = Member4(age=20) 13 print(mem4_1.get_info()) # 姓名:None,年龄:20 14 mem4_2 = Member4(name="xiaoming") 15 print(mem4_2.get_info()) # 姓名:xiaoming,年龄:None 16 17 print(Member4(name="小小明", age=22).get_info()) # 定义匿名对象
析构方法:__del__()
主要作用在于对象回收前的资源释放操作,当一个对象不再使用了或使用del关键字删除对象时都会自动调用析构方法
定义析构方法:
# 定义析构方法 __del__ class Member5: def __init__(self): # 定义构造方法 pass def __del__(self): # 定义析构方法 pass
类属性
在python中,属性分为实例属性和类属性
实例属性 是每一个实例化对象所独自拥有的;
类属性 是所有实例化对象所共有的,类属性直接定义在类中即可.
注意:
在开发过程中,对于类中的属性首选的依然是实例属性,而在描述公共信息的时候才会考虑使用类属性定义
示例:定义类属性,当类属性和实例属性重名的情况,以及动态配置类属性
1 class Message: 2 msg_info = "Hello world" # 定义类属性 3 4 5 print(Message.msg_info) # 直接通过 类名.属性名 进行访问 6 Message.title = "Hello" # 在类外部设置类属性 7 # 当类属性和实例属性出现重名的情况,程序在调用时会首先使用实例属性 8 msg1 = Message() 9 msg2 = Message() 10 print("属性修改前msg1.msg_info:%s,msg1.msg_info:%s" % (msg1.msg_info, msg2.msg_info)) 11 msg1.msg_info = "Hello Python" # 为msg1对象追加msg_info实例属性 12 print("属性修改后msg1.msg_info:%s,msg1.msg_info:%s" % (msg1.msg_info, msg2.msg_info)) 13 print(msg1.title) # 调用类外部定义的类属性
__slots__系统属性
动态属性配置虽然很灵活,但有可能造成开发操作的不规范,
python提供__slots__系统属性来定义一个实例化对象属性的范围,类属性不受其影响
示例:
1 class Member6: 2 __slots__ = ("name", "age") # 所有实例化对象可以使用的实例属性名称 3 4 5 mem6 = Member6() 6 mem6.name = "张三" 7 mem6.age = 25 8 # mem6.sex = "男" # 实例化属性sex不在定义范围内,程序抛出AttributeError异常 9 Member6.sex = "男" 10 print(Member6.sex) # 类属性 sex 不在__slots__限制范围内
内部类:一种内部嵌套的结构类
目的:让内部嵌套的内部类(1个或多个)只为一个外部类所服务
示例:
1 class SendMessage: 2 def sender(self, msg): 3 conn = SendMessage.Connect() 4 if conn.create(): 5 print("SendMessage类发送消息%s" % msg) 6 conn.close() 7 else: 8 print("消息通道创建失败,无法进行消息发送") 9 10 class Connect: 11 def create(self): 12 print("Connect 类创建消息发送通道") 13 return True 14 15 def close(self): 16 print("Connect 类关闭消息发送通道")
注意事项:
内部类也可以在外部类的外部使用,直接利用"外部类.内部类"的形式进行实例化内部类对象,可直接调用内部类中定义的属性和方法.
内部类和外部类虽然属于嵌套关系,但是两个类彼此还是属于完全独立的状态
如果想要在内部类中调用外部类的方法,则必须将外部类的实例对象传递到内部类中
如果不想内部类被外部类所调用,则可以使用"__内部类"的形式进行内部类的封装定义
示例:
1 class Outer: # 定义外部类 2 def __init__(self): # 外部类构造方法初始化属性内容 3 self.__info = "Hello Python" # 定义外部类实例属性 4 5 def get_info(self): # 外部类定义获取实例属性 6 return self.__info 7 8 class __Inner: # 定义内部类(封装的内部类) 9 def __init__(self, out): # 内部类实例化时接收外部类实例 10 self.__out = out # 外部类实例作为内部类实例属性 11 12 def get_outer_info(self): # 内部类方法 13 print(self.__out.get_info()) # 通过外部类实例调用外部类方法 14 15 def fun(self): 16 innerobj = Outer.__Inner(self) # 实例化内部类对象,并传入外部类当前实例化对象 17 innerobj.get_outer_info() # 内部类实例化对象调用内部类方法 18 19 20 outer = Outer() # 实例化外部类对象 21 outer.fun() # 外部类实例化对象调用外部类方法
内部类除了可以定义在类中,也可以在方法中定义类;
在方法中定义的内部类,可以直接访问方法中的参数或局部变量
示例:
1 class Outter: 2 def __init__(self): 3 self.__info = "外部类定义的实例对象属性" 4 5 def get_info(self, title): 6 print(title, self.__info) 7 8 def fun(self, msg): 9 outter_obj = self 10 title_2 = "内部方法的变量" 11 12 class Inner2: # 在方法中定义的内部类 13 def sender(self): 14 outter_obj.get_info(msg + title_2) # 调用外部类实例 15 16 Inner2().sender() # 内部匿名对象 调用方法 17 18 19 outter = Outter() 20 outter.fun("result:") # result:内部方法的变量 外部类定义的实例对象属性
类关联结构:
① 一对一关联
② 自身关联
③ 一对多关联
示例:一对一关联 1个人拥有1个身份证
1 class Person: 2 def __init__(self, **kwargs): 3 self.__name = kwargs.get("name") 4 self.__gender = kwargs.get("gender") 5 6 def set_cards(self, cards): 7 self.__cards = cards 8 9 def get_cards(self): 10 return self.__cards 11 12 def get_info(self): 13 return "Person 信息==> 姓名:%s,性别:%s" % (self.__name, self.__gender) 14 15 16 class IdentityCards: 17 def __init__(self, **kwargs): 18 self.__card_id = kwargs.get("card_id") 19 self.__card_address = kwargs.get("card_address") 20 21 def set_person(self, people): 22 self.__people = people 23 24 def get_person(self): 25 return self.__people 26 27 def get_info(self): 28 return "Identity_Cards 信息==>身份证号:%s,家庭住址:%s" % (self.__card_id, self.__card_address)
示例:一对多关联 一个人有多个孩子,每个孩子都有自己的车
1 class People: 2 def __init__(self, **kwargs): 3 self.__name = kwargs.get("name") 4 self.__age = kwargs.get("age") 5 self.__children = [] # 定义孩子列表 6 7 def set_car(self, car): 8 self.__car = car 9 10 def get_car(self): 11 return self.__car 12 13 def get_info(self): 14 return "People信息==>姓名:%s,年龄:%d" % (self.__name, self.__age) 15 16 def get_children(self): 17 return self.__children # 返回一个人的全部孩子 18 19 20 class Car: 21 def __init__(self, **kwargs): 22 self.__brand = kwargs.get("brand") 23 self.__price = kwargs.get("price") 24 25 def set_people(self, peopel): 26 self.__people = peopel 27 28 def get_peolep(self): 29 return self.__people 30 31 def get_info(self): 32 return "Car信息==>品牌:%s,价格%d" % (self.__brand, self.__price) 33 34 35 people_father = People(name="王五", age=30) 36 people_boy = People(name="王小六", age=6) 37 people_girl = People(name="王小妞", age=2) 38 39 car_a = Car(brand="宝马X5", price=500000) 40 car_b = Car(brand="解放牌", price=588) 41 car_c = Car(brand="玩具车", price=58) 42 43 people_father.get_children().append(people_boy) 44 people_father.get_children().append(people_girl) 45 46 people_father.set_car(car_a) 47 people_boy.set_car(car_b) 48 people_girl.set_car(car_c) 49 50 car_a.set_people(people_father) 51 car_b.set_people(people_boy) 52 car_c.set_people(people_girl) 53 print(people_father.get_info()) 54 print("\t|-%s" % people_father.get_car().get_info()) 55 for child in people_father.get_children(): 56 print(child.get_info()) 57 print("\t|-%s" % child.get_car().get_info())
示例:一对多关联 一个部门有多个职员,每个部门有正副领导
1 class Employee: 2 def __init__(self, **kwargs): 3 self.__name = kwargs.get("name") 4 self.__salary = kwargs.get("salary") 5 6 def set_leader(self, leader): 7 self.__leader = leader 8 9 def get_leader(self): 10 if "_Employee__leader" in dir(self): 11 return self.__leader 12 else: 13 return None 14 15 def set_department(self, depart): 16 self.__depart = depart 17 18 def get_department_info(self): 19 return self.__depart 20 21 def get_employee_info(self): 22 return "职员信息 ==> 姓名:%s 月薪:%s" % (self.__name, self.__salary) 23 24 25 def show(): 26 department = Department(depart_name="市场部", depart_locate="杭州") # 实例化部门对象 27 employee_a = Employee(name="正领导", salary=30000) # 实例化员工对象 28 employee_b = Employee(name="副领导", salary=16000) 29 employee_c = Employee(name="小卡罗蜜", salary=6000) 30 employee_a.set_department(department) # 设置员工对象部门信息 31 employee_b.set_department(department) 32 employee_c.set_department(department) 33 employee_b.set_leader(employee_a) # 设置员工对象的上级领导对象 34 employee_c.set_leader(employee_b) 35 department.get_employee_info().append(employee_a) # 设置员工部门关联 36 department.get_employee_info().append(employee_b) 37 department.get_employee_info().append(employee_c) 38 print(department.get_department_info()) 39 print("===============================") 40 for emp in department.get_employee_info(): 41 print(emp.get_employee_info()) 42 if emp.get_leader() != None: 43 print("\t|- %s" % emp.get_leader().get_employee_info()) 44 45 46 show()
合成设计模式 Composite Pattern :
面向对象设计的本质在于模块化的定义,即将一个完整的程序类拆分为若干个子类型,通过引用关联就形成了合成设计。
合成设计模式的核心思想为:通过不同类的实现子结构定义,随后在父结构中将其整合。
示例:
1 class BlackBoard: 2 pass 3 4 5 class Map: 6 pass 7 8 9 class Platform: 10 pass 11 12 13 class DesksandChairs: 14 pass 15 16 17 class Classroom: 18 def __init__(self): 19 self.__blackboard = BlackBoard() 20 self.__map = Map() 21 self.__platform = Platform() 22 self.__desksandchairs = []
2、继承
继承的主要目的是在无须修改原始类定义的情况下,可以使用新的类对原始类进行功能扩展.
在面向对象设计中,通过继承创建的新类称为"子类"或"派生类"
被继承的父类称为"基类"或"超类"
定义语法:
class 子类名称(父类1,父类2,...)
子类代码
示例:
1 class Person(object): 2 def __init__(self): 3 self.__name = None 4 self.__age = 0 5 6 def set_name(self, name): 7 self.__name = name 8 9 def get_name(self): 10 return self.__name 11 12 def set_age(self, age): 13 self.__age = age 14 15 def get_age(self): 16 return self.__age 17 18 19 class Student(Person): 20 pass 21 22 23 def show(): 24 stu = Student() 25 stu.set_name("xiaoming") 26 stu.set_age(18) 27 print("姓名:%s,年龄:%s" % (stu.get_name(), stu.get_age())) 28 29 30 show()
在python中,一个子类可以同时继承多个父类,这样就可以直接拥有多个父类的功能.
在子类继承父类的结构中,子类会继承父类中所有的属性和方法.
注意:
在继承结构中,子类可以继承父类中的全部定义内容,但是构造方法的继承却有所不同
① 当父类定义了构造方法,但子类没有定义构造方法时,实例化子类对象会自动调用父类提供的无参构造方法,
如果子类同时继承了多个父类,则按照继承顺序执行无参构造方法
示例:
1 class A: 2 def __init__(self): 3 print("class A message") 4 5 6 class B: 7 def __init__(self): 8 print("class B message") 9 10 11 class C(A, B): 12 pass 13 14 15 c = C() # 执行结果class A message class C继承了A类和B类,默认调用了A类的构造函数
② 当子类定义了构造方法时,默认不在调用父类的构造方法,但是可以手动调用父类的构造方法.
使用super().__init__() 调用父类的构造方法
1 class A: 2 def __init__(self): 3 print("class A message") 4 5 6 class B: 7 def __init__(self): 8 print("class B message") 9 10 11 class D(A, B): 12 def __init__(self): 13 super().__init__() # super().__init__()调用父类的构造方法 14 15 16 d = D() # 执行结果class A message
关于子类调用父类构造方法的作用:
在实际开发过程中,子类继承父类的结构中,子类往往拥有比父类更多的功能,使用子类对象实例化会比较方便,
但有时父类需要通过构造方法对一些属性进行初始化操作,这样就可以通过子类构造将参数的内容传递到父类中
示例:
1 class A2: 2 def __init__(self, name, age): 3 self.__name = name 4 self.__age = age 5 6 def get_info(self): 7 return "姓名:%s,年龄:%s" % (self.__name, self.__age) 8 9 10 class B2(A2): 11 def __init__(self, name, age): 12 super().__init__(name, age) # 调用父类构造函数 13 14 15 b2 = B2("小明", 18) 16 print(b2.get_info())
在子类没有定义任何构造方法的情况下,Python子类对象实例化时会自动调用父类中的构造方法,
但是在多继承结构之中,由于一个子类会存在有多个父类,就会造成结构调用的二义性,
所以Python中为了解决这个问题,专门提供了一个MRO(Method Resolution Order方法解析顺序)算法,执行时按照从左至右的原则进行调用
获取继承信息的相关变量和函数:
① 变量__class__ 获取指定对象所属类class对象,与type()返回值相同
② 变量__base__ 获取一个类对应的所有父类
③ 函数__subclasses__()获取一个类对应的所有子类
④ 函数__issubclass(class类对象,父类)判断一个class类对象是否是某一个类的子类
示例:
1 class Base: 2 def __init__(self): 3 print("Base类构造方法") 4 5 6 class ParendA(Base): 7 def __init__(self): 8 print("ParendA类构造方法") 9 10 11 class ParendB: 12 def __init__(self): 13 print("ParendB类构造方法") 14 15 16 class Sub(ParendA, ParendB): 17 pass 18 19 20 sub = Sub() # 执行结果 ParendA类构造方法 21 print(Sub.mro()) # 获取mro信息 22 par_a = ParendA() 23 print(par_a.__class__) # 查看par_a对象所属类对象 =====> <class '__main__.ParendA'> 24 print(sub.__class__) # 查看sub对象所属类对象 =====> <class '__main__.Sub'> 25 print(Sub.__base__) # 查看Sub类的所有父类 26 print(Base.__subclasses__()) # 查看ParendA类的所有子类 27 print(issubclass(sub.__class__, ParendA)) 28 print(issubclass(ParendA, Base))
3、多态
在面向对象设计中多态性描述的是同一结构在执行时会根据不同的形式展现出不同的效果,在Python中多态性的体现有两种形式:
① 方法重写(覆写)子类继承父类后可以根据父类的方法名称进行方法体的重新定义
示例:
1 class A: 2 def sender_message(self): 3 print("A类发送信息") 4 5 6 class B(A): 7 def sender_message(self): # 重写父类方法 8 print("B类发送的信息") 9 10 11 sender = B() 12 sender.sender_message()
作用:方法重写是定义子类个性化的方法体,同时为了保持父类结构的形式,保留父类的方法名称
注意:
当通过子类实例化对象调用方法是所调用的方法是被重写过的方法,如果此时需要调用父类已被重写过的方法
在子类中可以通过super().方法()的形式来调用父类的方法
示例:
class A: def sender_message(self): print("A类发送信息") class C(A): def sender_message(self): super().sender_message() # 调用父类的方法 sender_c = C() sender_c.sender_message()
② 对象多态性: 在方法重写的基础上利用相同的方法名称作为标准,就可以在不考虑具体类型的情况下实现不同子类中相同方法的调用
主要作用:对象多态性的主要作用在于参数统一
示例:
1 class Message: 2 def get_info(self): 3 return "[Message]类 ===> sender message" 4 5 6 class DatabaseMessage(Message): 7 def get_info(self): 8 return "[DatabaseMessage]类 ===> sender database message" 9 10 11 class NetMessage(Message): 12 def get_info(self): 13 return "[NetMessage]类 ===> sender net message" 14 15 16 class Channel: 17 def send(self, msg): 18 if isinstance(msg, Message): # 判断msg是否是Message或其子类 19 print(msg.get_info()) 20 21 22 channel = Channel() 23 channel.send(Message()) 24 channel.send(DatabaseMessage()) 25 channel.send(NetMessage())
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下