Advertisement

面向对象的Python编程学习:类与对象 [持续更新中… 欢迎关注~]

阅读量:

本文内容源于个人日常的学习总结与归纳,不适用于完全缺乏相关经验的学习者。建议具备一定基础知识的读者参考阅读,若文中存在疏漏之处,请不吝赐教。鉴于距今已有一段时日,部分内容或许已模糊不清,诚邀各位共同探讨与交流

希望各位能够给予点赞支持并进行收藏操作,在此恳请各位的关注!生活中的进步往往源于相互激励与支持

本文重点探讨了类与对象相关的核心要点:面向对象程序设计最具代表性的三大特性——数据封装技术、类间继承机制以及多态概念;同时涉及特殊方法定义、函数重载实现及多层继承等进阶主题...

通过具体实例演示相关概念的应用场景,请读者具备相应基础知识储备。文中部分代码采用Python交互式环境编写(当时尚未熟练掌握PyCharm工具),敬请理解!实践过程中请注意环境差异!

目录

一、 Python语言兼具过程式编程与面向对象编程特性(涵盖封装机制、继承机制及多重继承模式)

  1. 构建坐标点模型(实现数据封装)
  2. 设计矩形结构体
  3. 银行账户系统开发(私有属性定义与访问控制)
  4. 学生信息管理系统(构造函数初始化参数解析)
  5. 车辆管理架构设计(基类/派生类关系建立[super()调用父类初始化方法])* 继承机制详解*
  6. 对象组合应用案例(self参数表示实例化主体)
  7. 类属性绑定技术(通过dict实现内省功能)

二、 构造函数实现原理及复杂继承问题解析

  1. 初始化方法设计规范
  2. 方法覆盖技巧(通过类名直接调用未绑定父类方法)
  3. 多重继承冲突解决方案* super()函数应用*

① 优化方案:super()函数消除冗余调用
② super()执行依赖于MRO(方法解析顺序)规则: C.mro()或C.mro

三、 面向对象实践分析(多级继承遵循从左至右原则)

  1. Mixin模式应用实例
  2. 典型应用场景剖析

四、 多态性实现原理与鸭子类型概念解析

鸭子类型理论核心在于行为规范匹配度判定

例证:
① 多态现象展示(同一接口不同表现)
② 自定义多态接口设计(参数接受不同类型的实例并动态执行对应方法)

五、 私有成员变量控制与slots内存优化策略

实例:
① 私有变量命名转换时机(发生在实例创建阶段)
② 单下划线前后缀标识含义解析
③ 内存效率提升方案
Python因灵活性可能产生内存浪费问题
slots限制(丧失动态属性扩展能力) 注: 父类slots约束不适用于子类

六、 特殊方法定制实践指南

应用场景:
① 不可变类型修改策略
② 对象销毁管理(del方法触发条件:引用计数归零时自动执行)
补充说明: __del__方法调用时机由垃圾回收器决定,开发者无法直接控制其触发时刻

七、 运算符重载相关魔法方法实现

复制代码
操作示例:
① add运算符重写 注意参数顺序(self,other)
② radd反向运算前提条件分析
③ 对象转整型操作实现方式
④ 按位运算符覆盖(& | ~ ^ << >>)

八、 索引访问相关魔法方法及属性控制技术

复制代码
 使用情境:
 ① 索引操作触发条件分析
 ② 属性访问控制体系构建(含关联函数/魔法方法)
 ③ getattr动态获取属性值 
 ④ setattr设置属性值 

九、 索引切片处理及迭代协议实现方案

复制代码
 技术要点:
 ① 切片操作具体实现方式 
 ② 迭代协议标准接口设计  

一、 python既是面向过程编程,又是面向对象编程(封装、继承、多重继承)

01.定义一个点类(封装)

复制代码
 # 定义一个点类

    
 import math
    
 ​
    
 class Point():
    
     #__init__对x,y进行初始化
    
         def __init__(self,x = 0,y = 0):
    
             self.__x = x
    
             self.__y = y
    
         def move(self,dx,dy):
    
             self.__x += dx
    
             self.__y += dy
    
 ​
    
         def distance_to_origin(self):
    
             return math.sqrt(self.__x**2 + self.__y**2)
    
 p = Point(3,4)
    
 print(p.distance_to_origin())

02.创建一个矩形类

复制代码
 # 创建一个矩形类

    
 题目描述:
    
 创建一个名为 Rectangle 的类,用来描述矩形,包括:
    
 ​
    
 私有属性 width 和 height(矩形的宽和高)。
    
 初始化方法,设置 width 和 height 的初始值。
    
 方法 area(),返回矩形的面积。
    
 方法 perimeter(),返回矩形的周长。
    
 ​
    
 ​
    
 # 3.创建一个矩形类:计算面积和周长的方法
    
 class Rectangle:
    
     #进行初始化
    
     def __init__(self,width,height):           #__init__:表示构造函数
    
         self.width = width
    
         self.height = height
    
     def area(self):
    
         return self.width * self.height
    
 ​
    
     def perimeter(self):
    
         return (self.width + self.height)*2
    
 # 调用
    
 r = Rectangle(4,5)
    
 print(r.area())
    
 print(r.perimeter())
    
 '''

03.银行账户类(定义私有属性,方法)

复制代码
  # 银行账户类

    
 题目描述:
    
 设计一个名为 BankAccount 的类,用来模拟银行账户,包括:
    
 私有属性 balance(账户余额)。
    
 初始化方法,接收一个初始存款额度。
    
 方法 deposit(amount),存款。
    
 方法 withdraw(amount),取款,如果账户余额不足,打印警告。
    
 '''
    
 '''
    
 class BankAccount:
    
     # 使用双下划线来表示私有属性
    
     def __init__(self,balance = 0):
    
         self.__balance = balance
    
     def deposit(self,amount):
    
         self.__balance += amount
    
     def withdraw(self,amount):
    
         if amount > self.__balance:
    
             print('余额不足')
    
         else:
    
             self.__balance -= amount
    
     def get_balance(self):
    
         return self.__balance
    
 # 调用
    
 BK = BankAccount(1000)
    
 BK.deposit(500)
    
 BK.withdraw(600)
    
 print(BK.get_balance())
    
 BK.withdraw(1000)
    
 '''

04.学生信息管理(init 表示构造函数

复制代码
 '''

    
 '''
    
 练习题4: 学生信息管理
    
 题目描述:
    
 编写一个名为 Student 的类,用以存储一个学生的信息,包括:
    
 ​
    
 私有属性 name 和 scores(学生名字和成绩列表)。
    
 初始化方法,设置学生的名字和成绩。
    
 方法 add_score(score),添加一个新的成绩到列表中。
    
 方法 average(),返回学生的平均成绩。
    
 '''
    
 '''
    
 ​
    
 class Student:
    
     def __init__(self,name,scores = None):
    
         if scores is None:
    
             scores = []
    
         self.__name = name
    
         self.__scores = scores
    
     def add_score(self,score):
    
         self.__scores.append(score)
    
     def average(self):
    
         if self.__scores:
    
             return sum(self.__scores) / len(self.__scores)
    
         return 0
    
 # 调用
    
 Stu = Student('张三')
    
 Stu.add_score(95)
    
 Stu.add_score(88)
    
 Stu.add_score(95)
    
 print(Stu.average())
    
 '''

05.车辆管理系统(基类、派生类,即子类父类[super().init(self,year,model)函数,继承父类的变量])继承***

复制代码
 # 车辆管理系统

    
 题目描述:
    
 实现一个名为 Vehicle 的基类,以及两个派生类 Car 和 Truck,其中:
    
 ​
    
 Vehicle 类包含属性 year(年份), make(制造商)和 model(型号),所有属性为私有。
    
 Vehicle 类还包含方法 description(),返回一个包含年份、制造商和型号的字符串。
    
 Car 类增加属性 doors(车门数),覆盖 description() 方法以包括门数。
    
 Truck 类增加属性 bed_length(车厢长度),覆盖 description() 方法以包含车厢长度。
    
 '''
    
 '''
    
 class Vehicle:
    
     def __init__(self,year,make,model):
    
         self.__year = year
    
         self.__make = make
    
         self.__model = model
    
     def description(self):
    
         str = f'年份为:{self.__year},制造商是:{self.__make},型号是:{self.__model}'
    
         return str
    
 class Car(Vehicle):
    
     def __init__(self,year,make,model,doors):
    
         super().__init__(self,year,model)
    
         self.doors = doors
    
     def description(self):
    
         str = f'年份为:{self.__year},制造商是:{self.__make},型号是:{self.__model},门数是{self.doors}'
    
         return str
    
 class Truck(Vehicle):
    
     def __init__(self, year, make, model, bed_length):
    
         super().__init__(self, year, model)
    
         self.bed_length = bed_length
    
     def description(self):
    
         return f'年份为:{self.__year},制造商是:{self.__make},型号是:{self.__model},车厢长度是{self.bed_length}'
    
 ​
    
 car = Car(2019, "Toyota", "Camry", 4)
    
 truck = Truck(2020, "Ford", "F150", "5.5 ft")
    
 print(car.description())  # 输出: 2019 Toyota Camry with 4 doors
    
 print(truck.description())  # 输出: 2020 Ford F150 with a bed length of 5.5 ft

06.组合(self是实例化对象本身)

复制代码
 # 组合

    
 class Turtle:
    
     def say(self):
    
         print('不积跬步无以至千里!')
    
 class Cat:
    
     def say(self):
    
         print('喵喵喵~')
    
 class Dog:
    
     def say(self):
    
         print('呦呵,我是一只修狗~')
    
 # 现在我们想把小狗和小猫放在一个花园里面,很明显两者之间并不是继承关系,这时候我们就用到了组合
    
 class Garden:
    
     t = Turtle()
    
     c = Cat()
    
     d = Dog()
    
     def say(self):
    
         self.t.say()
    
         self.d.say()
    
         self.c.say()
    
 g = Garden()
    
 g.say()
    
 ​
复制代码

07.绑定(dict 进行内省)

复制代码
 # 定义一个空类(可以当做字典来存储数据)

    
 class C :
    
     pass
    
 C.x = 250
    
 C.y = "小甲鱼"
    
 C.z = [1,2,3]
    
 print(C.x)
    
 print(C.y)
    
 print(C.z)
    
 ​
    
 # 生成实例对象的方法
    
 class C:
    
     pass
    
 c = C()
    
 c.x = 250
    
 c.z = [1,2,3]
    
 c.y = "小甲鱼"
    
 ​
    
 c.y = 660
    
 print(c.__dict__)
    
 ​
    
 class C:
    
     def set_x(self,v):
    
         self.x = v
    
 c = C()
    
 print(c.__dict__)       #{}
    
 c.set_x(250)
    
 print(c.__dict__)       #{'x': 250}
    
 print(c.x)              #250
    
 ​
    
 ​
    
 class C:
    
     x = 100
    
     def set_x(self,v):
    
         x = v
    
 c = C()
    
 c.set_x(250)
    
 print(c.x)          #100
    
 print(C.x)          #100
    
 C.x = 250
    
 print(c.x)          #250
    
 c.__dict__          #{}

二、构造函数、重写、钻石继承

01.构造函数

复制代码

02.重写(直接通过类名访问类里面的方法的做法称之为调用未绑定的父类方法)

复制代码

03.钻石继承(调用super函数来解决)

复制代码
复制代码

01. 解决方法:super()函数(避免重复调用)

复制代码
复制代码

02. surper()函数依靠于MRO(Method Resolution Order)来运行:方法解析顺序 C.mro()或者C.mro

复制代码

三、类与对象案例分析(继承类的顺序为从左至右的顺序来继承)

01.基于Mixin的实践案例解析

复制代码
 # 类与对象案例分析:Mixin(混入,乱入)4.22

    
 class Animal:
    
     def __init__(self,name,age):
    
         self.name = name
    
         self.age = age
    
     def say(self):
    
         print(f'我叫{self.name},今年{self.age}岁')
    
 ​
    
 class FlyMixin:
    
     def fly(self):
    
         print('哦吼,我还会飞')
    
 class Pig(FlyMixin,Animal):             #此处pig类继承于FlyMixin、Animal父类
    
     def special(self):
    
         print('我的技能是拱大白菜!')
    
 ​
复制代码

02.案例分析

在代码实现过程中首要遵循自左向右的原则沿袭LoggerMinin基类所定义的展示技术途径,在调用super()机制时因其严格遵照MRO解析规则会优先触发Dispalyer父级组件的相关实现并输出字符串"This is a text"。后续的日志记录操作将基于当前实例对象self展开,并且该功能模块源自于与***模块内部建立关联的方法实体

四、多态和鸭子类型(鸭子类型(它的行为是否合乎规矩))

例01 多态(不同场景不同表现形式)

复制代码

例02 自定义函数如何实现多态接口,接收不同的对象作为参数,并且不检查其类型的情况下执行它的方法

复制代码
 # 自定义函数如何实现多态接口,接收不同的对象作为参数,并且不检查其类型的情况下执行它的方法

    
 class Cat:
    
     def __init__(self,name,age):
    
         self.name = name
    
         self.age = age
    
     def intro(self):
    
         print(f'我是一只猫,我叫{self.name},今年{self.age}岁啦~~~')
    
     def say(self):
    
         print('miao~~~')
    
 class Dog:
    
     def __init__(self,name,age):
    
         self.name = name
    
         self.age = age
    
     def intro(self):
    
         print(f'我是一只修狗,我叫{self.name},今年{self.age}岁啦~~~')
    
     def say(self):
    
         print('呦吼~~~')
    
 class Pig:
    
     def __init__(self,name,age):
    
         self.name = name
    
         self.age = age
    
     def intro(self):
    
         print(f'我是一只小猪,我叫{self.name},今年{self.age}岁啦~~~')
    
     def say(self):
    
         print('oink~~~')
    
 # 实例化对象
    
 c = Cat('hah',5)
    
 p = Pig('huh',3)
    
 d = Dog('布布',6)
    
 ​
    
 # 多态
    
 def animal(x):
    
     x.intro()
    
     x.say()
    
 animal(c)
    
 animal(d)
    
 animal(p)
复制代码

五、私有变量和slots

例01 私有变量(名字改编是发生在类实例化对象的时候)

复制代码
>       1. # '私有变量'和__slots__

>  
>       2. # name mangling
>  
>       3. class C:
>  
>       4.     def __init__(self,x):
>  
>       5.         self.__x = x            #__开头表示私有变量
>  
>       6.     def set_x(self,x):
>  
>       7.         self.__x = x
>  
>       8.     def get_x(self):
>  
>       9.         print(self.__x)
>  
>       10. # 想要访问私有变量的值就要通过接口
>  
>       11. c = C(250)
>  
>       12. # c.__x 这样是没有办法访问的
>  
>       13. c.get_x()
>  
>       14. c.set_x(520)
>  
>       15. c.get_x()      
>  
>       16. print(c.__dict__)      #__dict__ 是一个特殊的内置属性,它返回对象的属性字典
>  
>       17. print(c._C__x)
>  
>  
>
复制代码
复制代码

例02 单个下横线开头的变量 单个下横线结尾的变量分别代表什么

以单一下划线作为起始字符的标识符:此类符号仅限于内部环境使用(禁止外部调用)。以单一下划线作为末尾字符的标识符:如class。

关键技术优化实现效率突破

python由于灵活性有时候会抛弃很多内存空间

复制代码
复制代码

slots(副作用,没有动态添加属性的能力) 注:继承自父类的slots 属性是不会在子类中生效的

复制代码
 class C:

    
     __slots__ = ["x","y"]
    
     def __init__(self, x):
    
         self.x = x
    
 c = C(250)
    
 c.y = 520
    
 print(c.y)
    
 # c.z = 666       #AttributeError: 'C' object has no attribute 'z'
复制代码
 class D:

    
     __slots__ = ['x','y']
    
     def __init__(self,x,y,z):
    
         self.x = x
    
         self.y = y
    
         self.z = z
    
 # AttributeError: 'D' object has no attribute 'z'
    
 # d = D(3,4,5)

六、魔法方法

程序设计中不变量变异实现路径

init(self[,..])方法不需要调用也会执行

复制代码

例02 del 方法(垃圾回收机制,只有当对象没有任何引用的时候才会被执行)

总结:虽然__del__方法在这个类中被定义了,但你不能直接控制它何时被调用。它的调用是由Python的垃圾回收机制管理的,并且这个机制通常是在需要回收内存时才会运行的。

复制代码

例03 对象重生

在图像识别这一研究领域中...

复制代码
复制代码

七、运算相关的魔法方法

Python--魔法方法汇总 - 知乎 (zhihu.com)

例01 重写add方法 注意(self,other)

复制代码
 # 重写add方法

    
 # 注意(self,other)
    
 class S(str):
    
     def __add__(self, other):
    
         return len(self) + len(other)
    
 s1 = S('python')
    
 s2 = S('hhhhh')
    
 print(s1+s2)            #11
    
 print(s1 +'python')     #12
    
 print('FichC'+s2)           #FichChhhhh

例02 radd ()方法调用前提

在执行两个对象之间的加法运算过程中,若左操作数与右操作数的数据类型存在差异,并且左操作数未实现 add() 方法或其 add() 方法返回 Notlmplemented,则 Python 解释器将尝试在右操作数中寻找是否存在 radd() 方法的实现

复制代码
 能实现的前提是左侧的方法中一定返回值是NotImplemented或者没有返回值

    
 class S1(str):
    
     def __add__(self, other):
    
         return NotImplemented #表示该方法未实现
    
 class S2(str):
    
     def __radd__(self, other):
    
         return len(self)+len(other)
    
 s1 = S1("Apple")
    
 s2 = S2("Banana")
    
 print(s1+s2)

说明:此处为何最终生成的结果s2呈现为两段字符序列相连的形式?由于radd()功能的应用需满足特定前提条件,并且必须依托于不同类别实例间的交互机制。当执行s2+=s2操作时若其所属类别保持一致,则会激活承袭自基类str的相关处理流程,在这种情况下,默认会触发父类str中定义的基本加法运算逻辑,并最终形成双倍长度的新字符串。

复制代码
 class S2(str):

    
     def __radd__(self, other):
    
         return len(self)+len(other)
    
 # s1 = S1("Apple")
    
 s2 = S2("Banana")
    
 # print(s1+s2)
    
 ​
    
 class S1(str):
    
     def __iadd__(self, other):
    
         return len(self) + len(other)
    
 s1 = S1("Apple")
    
 s1 += s2
    
 print(s1)               #11
    
 print(type(s1))         #<class 'int'>
    
 s2 += s2
    
 print(s2)               #BananaBanana
    
 print(type(s2))         #<class 'str'>

例03 将一个对象转换成整数类型

复制代码
 class ZH_INT:

    
     def __init__(self,num):
    
         self.num = num
    
     def __int__(self):
    
         try:
    
             return int(self.num)
    
         except ValueError:
    
             zh = {"零":0,"一":1,'六':6,"七":7,"八":8,"三":3,'四':4,"壹":1}
    
             result = 0
    
 ​
    
             for each in self.num:
    
                 if each in zh:
    
                     result += zh[each]
    
                 else:
    
                     result += int(each)
    
                 result *= 10
    
             return result
    
 n = ZH_INT("520")
    
 print(int(n))
    
 n = ZH_INT("一一零")
    
 print(int(n))
复制代码

例04 & | ~ ^(异或) << >>

复制代码
复制代码

八、 index 魔法方法 ,与属性相关的函数和魔法方法

例01 当对象作为索引值被调用的时候才会被调用

复制代码
    **# __index__魔法方法
    # 当对象作为索引值被调用的时候才会被调用**
复制代码
 class C:

    
     def __index__(self):
    
         print("被拦截了")
    
         return 3
    
 c = C()
    
 # c[2]            #TypeError: 'C' object is not subscriptable
    
 s = "FishC"
    
 print(s[c])            #被拦截了    h
    
 print(bin(c))           #0b11

例02 属性访问(与属性相关的函数和魔法方法)

复制代码
复制代码
 class C:

    
     def __init__(self,name,age):
    
         self.name = name
    
         self.__age = age
    
 ​
    
 c = C('小甲鱼',18)
    
 print(hasattr(c,"name"))            #True
    
 print(getattr(c,"_C__age"))         #18  私有变量
    
 (setattr(c,"_C__age",19))
    
 print(getattr(c,"_C__age"))            #19
    
 delattr(c,"_C__age")

例03 getattr

复制代码
 class C:

    
     def __init__(self,name,age):
    
         self.name = name
    
         self.__age = age
    
     def __getattribute__(self, attrname):
    
         print("拿来吧你~")
    
         return super().__getattribute__(attrname)
    
 c = C("小甲鱼",18)
    
 print(getattr(c,"name"))
    
 print(c._C__age)
复制代码

Python setattr动态属性设置实例

复制代码
 class D:

    
     def __setattr__(self, name, value):
    
         self.__dict__[name] = value
    
 ​
    
 d = D()
    
 d.name = "小甲鱼"
    
 print(d.name)
    
 ​
    
 __setattr__例2
    
 ​
    
 class D:
    
     def __setattr__(self, name, value):
    
         self.__dict__[name] = value
    
     def __delattr__(self, name):
    
         del self.__dict__[name]
    
 ​
    
 d = D()
    
 d.name = "小甲鱼"
    
 print(d.__dict__)
    
 ​
    
 # print(d.name)           #小甲鱼
    
 ​
    
 del d.name
    
 print(d.__dict__)
    
 ​
    
 # {'name': '小甲鱼'}
    
 # {}

九、索引切片与迭代协议的数据操作机制

例01 切片

复制代码

注:当数据序列为"123456"并执行[:-2]切片操作时,末尾两位数值将无法获取,最终输出内容为1234

若采用[-2:]切片方式,则所呈现的数值结果为56

例02 迭代协议

全部评论 (0)

还没有任何评论哟~