1 面向对象
Python 是一种面向对象的编程语言。
语言的发展:机器语言(0 1) → 汇编语言 → 高级语言(C 面向过程)→ 面向对象(python)
1.1面向过程和面向对象
面向过程:核心思想:程序 = 算法 + 数据。关注点是"怎么做"(执行步骤)
分析解决问题的步骤,然后逐步实现
例:小白买电脑
1.网上查资料
2.根据自己预算和需求定电脑型号 华硕天选
3.去线下门店实地考察
4.找业务员砍价,要赠品, 付款成交
面向对象:核心思想:程序 = 对象 + 消息。关注点是"谁来做"(责任分配)
找出解决问题的对象,然后分配任务
例:小白买电脑
1.找一个靠谱的电脑高手
2.给钱交易
1.2 面向对象的技术点:
|
类 (Class) |
具有相同属性和方法的对象的集合 |
class Car: ... |
|
方法 |
类中定义的函数 |
def start_engine(): |
|
类变量 |
类中定义的共享变量 |
wheels = 4 |
|
数据成员 |
类变量与实例变量的统称 |
brand, price |
|
方法重写 |
子类重新定义父类方法 |
def start_engine(): ... |
|
局部变量 |
方法内部定义的临时变量 |
temp = 0 |
|
实例变量 |
对象特有的属性变量 |
self.color = "red" |
|
继承 |
子类获取父类特性的机制 |
class SUV(Car): |
|
实例化 |
根据类创建对象的过程 |
car = Car() |
|
对象(Object) |
类的具体实例 |
my_car = Car() |
1.3 类(Class)
用来描述具有相同的属性和方法的对象的集合。类定义该集合中每个对象所共有的属性和方法。
对象是类的实例。
1.3.1 创建类
关键字 class 后边跟类名以冒号结束 (类名尽量所有的单词首字母大小)
class q:
x = 5
类由3部分组成:类名、属性、行为
class Car: #定义一个名为 Car 的类
"""
记录车
"""
num = 0 # 类属性:记录创建的汽车总数
def __init__(self, color, price, model):
self.color = color # 实例属性:汽车颜色 设置当前汽车的 color 属性
self.price = price # 实例属性:汽车价格 设置当前汽车的 price 属性
self.model = model # 实例属性:汽车型号
Car.num += 1 # 每创建一辆车,计数器加1
num变量是一个类变量,他的值会在类的所有实例之间共享,使用Car.num访问
__init__函数也叫类的构造函数,当创建了这个类的实例时,会自动调用该方法
self:是一个参数,表示实例化对象,里边存放对象自身的地址,
定义类时self必须有,但是调用时不用传递对应的参数
1.3.2 实例化对象
格式:变量名 =类名(参数)
class Car:
"""
记录车
"""
num = 0 # 类属性:记录创建的汽车总数
def __init__(self, color, price, model):
self.color = color # 实例属性:汽车颜色
self.price = price # 实例属性:汽车价格
self.model = model # 实例属性:汽车型号
Car.num += 1 # 每创建一辆车,计数器加1
# 实例化对象
car1 = Car("红色", 150000, "Model S") # 创建了Car类的第一个对象
car2 = Car("蓝色", 200000, "Model X") # 创建了Car类的第二个对象
print(f"已创建 {Car.num} 辆车") # 输出:已创建 2 辆车
print(car1.model) # 输出:Model S
1.3.3 访问方法
class Car:
"""
记录车
"""
num = 0 # 类属性:记录创建的汽车总数
def __init__(self, color, price, model):
self.color = color # 实例属性:汽车颜色
self.price = price # 实例属性:汽车价格
self.model = model # 实例属性:汽车型号
Car.num += 1 # 每创建一辆车,计数器加1
def its(self): # 普通方法
print(f"{self.color}色的小米汽车很漂亮,售价为{self.price}元,车型为{self.model}")
# 实例化对象
car1 = Car("红色", 150000, "model S")
# 调用类中的方法
car1.its()
car2 = Car("蓝色", 200000, "model X")
# 调用类中的方法
car2.its()
可以增加、删除、修改类的属性:
添加: 直接添加
hasattr: 判断属性是否存在
getattr: 获取属性值
setattr: 修改属性值;如果属性不存在,会创建新属性
delattr: 删除属性
class Car:
"""
记录车
"""
num = 0 # 类属性:记录创建的汽车总数
def __init__(self, color, price, model):
self.color = color # 实例属性:汽车颜色
self.price = price # 实例属性:汽车价格
self.model = model # 实例属性:汽车型号
Car.num += 1 # 每创建一辆车,计数器加1
def its(self): # 普通方法
print(f"{self.color}色系的小米汽车很漂亮,售价为{self.price}元,车型为{self.model}")
# 实例化对象
car1 = Car("红色", 150000, "model S")
# 1. 添加 typ 属性
car1.typ = "新能源" # 动态添加实例属性
# 验证属性添加
print(f"类型: {car1.typ}") # 该属性仅属于 car1 实例
# 输出: 类型: 新能源
# 2. 添加 colors 属性 (注意:不同于已有的 color 属性)
car1.colors = "渐变青" # 添加新属性 colors
print(f"颜色新增: {car1.colors}") # 该属性仅属于 car1 实例
# 3. 删除 price 属性 (被注释,实际不执行)
# del car1.price # 取消注释将删除 price 属性
# 4. 使用 hasattr() 判断属性是否存在
print(hasattr(car1, "typ")) # 输出: True (存在)
print(hasattr(car1, "engine")) # 输出: False (不存在)
# 5. 使用 getattr() 获取属性值
print(getattr(car1, "color")) # 输出: 红色
print(getattr(car1, "colors")) # 输出: 渐变青
# 6. 使用 setattr() 修改/设置属性值
# 修改已存在的属性
setattr(car1, "color", "黄色") # 修改 color 属性值
print(car1.color) # 输出: 黄色
# 7. 创建新属性
setattr(car1, "battery", "100kWh") # 添加新属性 如果属性不存在,会创建新属性
print(car1.battery) # 输出: 100kWh
# 调用类中的方法
car1.its()
1.4 python内置类属性
Python 为每个类提供了一系列内置属性,用于访问类的元信息。这些属性在类定义时自动创建,无需手动声明。
__doc__:类的文档字符串
__name__:类名
__dict__:类的属性(字典,数据:类的属性)
__module__:类定义所在模块(类的全名__main__ClassName)/(定义类的模块名)
__bases__:类的所有父类构成的元素(父类元组)
__class__:实例所属的类
__mro__:方法解析顺序
__subclasses__():子类列表
python 3.n,中所有的类都有一个共同父类,叫object类(顶级父类)
print("\n===== 类内置属性 =====")
print(f"1. __name__: {Car.__name__}") # 输出:Car
print(f"2. __doc__: {Car.__doc__}") # 输出:车辆信息记录类
print(f"3. __module__: {Car.__module__}") # 输出:__main__(当前模块)
print(f"4. __bases__: {Car.__bases__}") # 输出:(<class 'object'>,)
print(f"5. __dict__ keys: {list(Car.__dict__.keys())}") # 包含类命名空间的所有成员
print(f"6. __mro__: {Car.__mro__}")
print(f"7. __subclasses__: {Car.__subclasses__()}") # 输出:[<class '__main__.ElectricCar'>]
# 实例的 __dict__:包含实例的所有属性
print(car1.__dict__)
# 输出:{'color': '红', 'price': 150000, 'model': 'Model S'}
1.5 类的继承
继承是面向对象编程的核心概念,允许新类(子类)获取现有类(父类)的属性和方法,并添加新的功能或修改现有行为。类可以被继承,也可以继承别的类,被继承的类为父类,继承的类叫子类;继承过程中,子类会继承父类所有的属性和行为,一个父类可以有多个子类,一个子类可以有多个父类。
1.5.1 单继承
一个类只有一个父类,当子类中存在和父类相同的属性和方法时,会优先调用子类
格式:class 子类名(父类名): # 子类特有的属性和方法
class Parent: # 父类(基类)
def __init__(self):
print("调用父类构造函数")
def houseNum(self):
print("父亲有两个房子")
class Child(Parent): # 子类(派生类)
def __init__(self):
print("调用子类构造函数")
def CarNum(self):
print("字类有3辆车")
c = Child() # 实例化子类
c.houseNum()
1.5.2 多继承
一个类可以继承多个类(容易代码混乱)
class Parent1: # 父类(基类)
def __init__(self):
print("调用父类构造函数")
def houseNum(self):
print("父亲有1个房子")
class Parent2: # 父类(基类)
def __init__(self):
print("调用父类构造函数")
def houseNum(self):
print("父亲有2个房子")
class Parent3: # 父类(基类)
def __init__(self):
print("调用父类构造函数")
def houseNum(self):
print("父亲有3个房子")
class Child(Parent1,Parent2,Parent3): # 子类(派生类)
def __init__(self):
print("调用子类构造函数")
def CarNum(self):
print("字类有3辆车")
c = Child() # 实例化子类
c.houseNum()
# issubclass:判断一个类是否是另一个类的子类或者子孙类
# isinstance: 判断对象名是否是某个类的实例化对象
#基于上述代码命令,在上述代码后面进行判断
# issubclass:判断一个类是否是另一个类的子类或者子孙类
print(issubclass(Child, Parent1))
#----True
# isinstance: 判断对象名是否是某个类的实例化对象
print(isinstance(c, Child))
print(isinstance(c, Parent2)) #----因为字类继承了父类Parent2
#----True
#----True
1.6 封装
核心:把“数据”和“操作数据的函数”绑在一起,对外只暴露“该暴露的”,隐藏“不该碰的”。隐藏内部实现细节,通过方法暴露操作。
class BankAccount:
def __init__(self, balance=0): # 初始化方法,创建账户时设置初始余额
self.__balance = balance # 私有属性(双下划线开头),外部无法直接访问
def deposit(self, amount): # 存款方法,增加账户余额
self.__balance += amount # 只能通过类的方法修改私有属性
def get_balance(self): # 获取余额方法,公开接口访问私有数据
return self.__balance # 返回当前余额
# 双下划线前缀: 命名约定(非强制),表示"私有"属性
1.7 方法重写
当子类继承父类时,如果父类方法的功能不能满足需求,可以在子类重写父类的方法。如果子类定义了与父类同名的方法,则子类方法会"覆盖"父类方法
类比理解:就像你继承了父母的手机,但你把手机系统升级了 - 还是同一个手机,但功能更强了。
class A:
def __init__(self, x, y):
self.x = x # 实例属性x
self.y = y # 实例属性y
def axy(self):
return self.x + self.y # 返回x和y的和
class B(A): # B继承自A
def __init__(self, x, y, z):
# 显式调用父类A的构造方法
A.__init__(self, x, y) # 初始化x和y属性
self.z = z # 新增子类特有属性z
def axy(self):
# 重写父类方法,添加新功能
return A.axy(self) + self.z # 调用父类方法并加上z的值
# 创建B类的实例
b = B(14, 25, 36)
# 调用重写后的axy方法
print(b.axy()) # 输出结果
# B继承自A,所以B拥有A的所有属性和方法,
# B 可以:
# 添加新属性(如 z)
# 添加新方法
# 重写父类方法(如 axy)
class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
2 基础重载方法
重载方法(也称为魔术方法或特殊方法)是以双下划线开头和结尾的方法,用于自定义类的行为。这些方法允许你改变 Python 内置操作的行为,使你的类更自然地与 Python 语言集成。
2.1 构造与析构方法
class D:
def __init__(self, value): # 构造方法
self.value = value
print(f"对象已创建,值: {value}")
def __del__(self): # 析构方法
print(f"对象被销毁,值: {self.value}")
obj = D(10)
del obj
#----对象已创建,值: 10
#----对象被销毁,值: 10
2.2 字符串表示方法
class D:
def __init__(self, x, y): # 定义D类,用于表示二维坐标系中的点
# 构造方法:创建D对象时自动调用
self.x = x # 设置实例属性x,存储点的横坐标
self.y = y # 设置实例属性y,存储点的纵坐标
def __str__(self):
# 重载__str__方法:提供用户友好的字符串表示
# 当使用print()、str()或格式化输出时调用
return f"点({self.x}, {self.y})" # 返回中文格式的坐标表示
def __repr__(self):
# 重载__repr__方法:提供开发者友好的正式字符串表示
# 在交互式环境、调试或repr()函数中调用
return f"D(x={self.x}, y={self.y})" # 返回精确的类构造表示
# 创建D类的实例
p = D(3, 4) # 调用__init__方法,初始化坐标为(3, 4)
# 打印str表示
print(str(p)) # 调用__str__方法 → 输出: 点(3, 4)
# 打印repr表示
print(repr(p)) # 调用__repr__方法 → 输出: D(x=3, y=4)
#-----需要简洁易懂的信息 → __str__
#-----需要精确的技术细节 → __repr__
2.3 算术运算符重载
class E: # 新建一个类
def __init__(self, x, y): # 构造函数。
# 创建对象时自动调用,把传进来的两个数分别存到对象的属性 x 和 y 里。
self.x = x
self.y = y # 把参数保存成对象的实例变量
def __add__(self, other): # 加法运算符重载 __add__
return E(self.x + other.x, self.y + other.y)
def __sub__(self, other): # 减法运算符重载 __sub__
return E(self.x - other.x, self.y - other.y)
def __mul__(self, scalar): # 乘法运算符重载 __mul__
return E(self.x * scalar, self.y * scalar)
v1 = E(2, 3)
v2 = E(4, 5)
print((v1 + v2).__dict__) # 输出: {'x': 6, 'y': 8}
print((v1 * 3).__dict__) # 输出: {'x': 6, 'y': 9}
# __dict__ 返回实例属性的字典形式 {'x':6, 'y':8}
# __mul__ 仅支持 实例 * 标量(如 v1 * 3),
# 不支持 标量 * 实例(如 3 * v1 会报错)
# self.x:当前实例(调用加法运算符的第一个操作数)的x值。
# other.x:另一个实例(加法运算符的第二个操作数)的x值。
# self.y:当前实例的y值。
# other.y:另一个实例的y值。
# v1 = E(2, 3),那么v1.x=2, v1.y=3
# v2 = E(4, 5),那么v2.x=4, v2.y=5
# 当执行v1 + v2时,实际上调用的是v1.__add__(v2),即:self是v1,other是v2
2.4 比较运算符重载
class R:
def __init__(self, name, score):
self.name = name
self.score = score
def __eq__(self, other): # 等于 ==
return self.score == other.score
def __lt__(self, other): # 小于 <
return self.score < other.score
def __le__(self, other): # 小于等于 <=
return self.score <= other.score
b1 = R("ZX", 95)
b2 = R("LS", 89)
print(b1 > b2) # 输出: True
print(b1 == b2) # 输出: False
3 多态
核心思想:不同类的对象对同一方法调用产生不同行为。通过继承 + 方法重写实现。
在 Python 里,只要对象长得像鸭子,就能当鸭子用(“鸭子类型”)。
class Animal: # 定义动物基类
def __init__(self, name): # 构造函数:初始化动物实例
self.name = name # 设置实例属性 name(动物名字),将传入的name参数保存为实例属性
# self:表示当前实例对象,所有子类都会继承这个构造函数
def shout(self): # -定义发声方法(抽象方法))
pass # 由子类具体实现 -空操作,表示没有具体实现
class Dog(Animal): # 定义 Dog 类并继承 Animal
def shout(self): # def shout(self): 重写父类的 shout 方法,方法名与父类相同,实现不同功能
print(f"{self.name}: 汪汪!")
# 使用 f-string 格式化输出
# self.name 继承自 Animal 类
class Bird(Animal): # 定义 Bird 类(鸟),继承自 Animal
def shout(self): # 重写父类的 shout 方法
print(f"{self.name}: 啾啾~") # 实现鸟特有的叫声
# 多态实现
# 创建不同动物实例
dog = Dog("旺财")
bird = Bird("小红")
# 统一调用 shout 方法
dog.shout() # 输出: 旺财: 汪汪!
bird.shout() # 输出: 小红: 啾啾~
4 异常处理机制
|
AttributeError(属性错误) |
尝试访问对象不存在的属性或方法 |
|
ValueError(值错误) |
函数接收到类型正确但值不合适的参数 |
|
TypeError(类型错误) |
操作或函数应用到不适当类型的对象 |
|
IndexError(索引错误) |
访问序列(列表、元组、字符串)中不存在的索引 |
try: # 可能发生异常的代码
except:# 异常发生后执行的代码
else: # 没有异常,执行此代码
finally: # 不管是否捕获到异常,最后都执行此代码
s1 = "scad"
try:
print(s1[99]) # 试图访问字符串 s1 的第 100 个字符(下标 99)。
except IndexError:
print("捕获到异常,下标越界啦")
else:
print("没有异常")
finally:
print("最终执行此代码")
print("hello world")
# 获取三角形边长并验证输入
try: # 开始一个 try 块,用于捕获可能的异常
a = float(input("请输入第一条边长: "))
b = float(input("请输入第二条边长: "))
c = float(input("请输入第三条边长: "))
except ValueError: # 捕获可能发生的 ValueError 异常(当输入无法转换为数字时)
print("错误:请输入有效数字")
exit() # 退出程序
# 验证边长有效性
if a <= 0 or b <= 0 or c <= 0: # 检查任何边长是否小于或等于零
print("错误:边长必须为正数") # 如果边长不是正数,打印错误信息
exit() # 退出程序
# 检查三角形不等式定理(优化版)
sides = sorted([a, b, c]) # 创建一个包含三边的列表 [a, b, c]
# 使用 sorted() 函数对列表进行升序排序
# 将排序后的列表赋值给 sides 变量
# 排序后:sides[0] ≤ sides[1] ≤ sides[2]
if sides[0] + sides[1] <= sides[2]: # 检查最小两边之和是否小于或等于最大边(三角形不等式)
print("错误:不能构成三角形(两边之和需大于第三边)")
exit() # 退出程序
# 判断三角形类型
if a == b == c:
print("等边三角形")
elif a == b or a == c or b == c:
print("等腰三角形")
else:
# 使用排序优化直角判断(仅需检查最大边)
if abs(sides[0] ** 2 + sides[1] ** 2 - sides[2] ** 2) < 1e-6: # 处理浮点精度
print("直角三角形")
else:
print("普通三角形")
5 迭代器
迭代是python中访问集合中的元素的一种方式,迭代器迭代器是可迭代的对象,可以遍历所有值,可以记住遍历位置的对象。迭代器是一种对象,该对象包含值的可计数数字。
迭代器对象从集合的第一个元素开始访问,直到所有元素被访问完结束,迭代器只能往前不会后退
迭代器有两个基本方法:iter() next()
列表、元组、字典和集合都是可迭代的对象。它们是可迭代的容器,您可以从中获取迭代器(Iterator)。
list1 = [2.3, 3, 5.2, 6] # 创建列表
l1 = iter(list1) # 创建迭代器对象 iter(list1) 将列表转换为迭代器对象
print(next(l1)) # 获取第一个元素,迭代器位置:移动到下一个元素
print(next(l1)) # 获取第二个元素,迭代器位置:移动到下一个元素
for i in l1: # 遍历剩余的元素,for 循环从当前迭代器位置继续
print(i)
# 2.3
# 3
# 5.2
# 6
# 第一次迭代:i = 5.2 → 打印 5.2
# 第二次迭代:i = 6 → 打印 6
# 第三次迭代:迭代器耗尽,循环结束
Python面向对象编程学习笔记
298

被折叠的 条评论
为什么被折叠?



