admin 管理员组文章数量: 1184232
一、函数式编程
Python的函数式编程(Functional Programming, FP)是一种编程范式。
1. 函数作为参数
-
将核心逻辑传入方法体,使该方法的适用性更广。
示例1:
def func01():
print("func01执行")
def func02():
print("func02执行")
# 通用
def func03(func):
print("func03执行")
func()
func03(func02)
func03(func01)
2. 函数作为返回值
我们可以通过闭包思想完成这一特性。
闭包是指引用了此函数外部嵌套函数的变量的函数,并把该函数作为返回值,是一种思想。
2.1 闭包定义
闭包必须满足以下三个条件:
-
必须有一个内嵌函数
-
内嵌函数必须引用外部函数中变量
-
外部函数返回值必须是内嵌函数
2.2 闭包优缺点
优点
-
逻辑连续,当闭包作为另一个函数调用参数时,避免脱离当前逻辑而单独编写额外逻辑。
-
方便调用上下文的局部变量。
-
加强封装性,是第2点的延伸,可以达到对变量的保护作用。
缺点
引用在,空间不灭:闭包使得函数中的变量保存在内存中,内存消耗很大
示例1
def give_yasuiqian(money):
def child_buy(obj, m):
nonlocal money
if money > m:
money -= m
print('买', obj, '花了', m, '元, 剩余', money, '元')
else:
print("买", obj, '失败')
return child_buy
cb = give_yashuqian(1000)
cb('变形金刚', 200)
cb('漫画三国', 100)
cb('手机', 1300)
示例2
# file : closure.py
def make_power(y):
def fn(x):
return x ** y
return fn
pow2 = make_power(2)
print("5的平方是:", pow2(5))
pow3 = make_power(3)
print("6的立方是:", pow3(6))
3. 装饰器
装饰器是Python对闭包思想的具体语法实现,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能。
-
日志记录:可以使用装饰器来记录函数的输入、输出或执行时间。
-
认证和授权:装饰器可以用于检查用户是否有权限执行特定操作。
-
缓存:装饰器可以缓存函数的结果,从而提高执行效率。
-
参数验证:可以使用装饰器来验证函数的输入参数是否符合预期。
-
代码注入:装饰器可以在函数的执行前后注入额外的代码。
3.1 基本装饰器
def my_decorator(func):
print("I am decorator")
def wrapper():
print("Something is happening before the function is called.")
func() # 调用传入的函数
print("Something is happening after the function is called.")
return wrapper
@my_decorator # 应用装饰器
def say_hello():
print("Hello!")
print("say_hello is:", say_hello) # 装饰器装饰之后的函数
say_hello() # 调用经过装饰器之后的函数
-
my_decorator 是一个接受一个函数 $func$ 作为参数的装饰器。
-
wrapper函数在被装饰函数前后添加了额外的操作。
-
使用
my_decorator将say_hello函数装饰,使其在调用前后执行wrapper中的代码。
3.2 带参装饰器
def repeat(num):
print('...函数名...()...函数执行...')
def decorator(func):
print('...装饰器...()...装饰器执行...')
def wrapper(*args, **kwargs):
for _ in range(num):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) # 应用装饰器,重复执行下面的函数3次
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # 调用被装饰的函数
-
repeat 是一个接受参数的装饰器工厂函数,它返回一个装饰器。
-
decorator 是真正的装饰器,它接受一个函数 $func$ 作为参数。
-
wrapper函数重复执行被装饰的函数
num次。
3.3 装饰器链
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def exclamation(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result + "!"
return wrapper
@exclamation
@uppercase
def say_hello(name):
return f"Hello, {name}"
greeting = say_hello("Bob")
print(greeting) # 输出 "HELLO, BOB!"
-
uppercase和 exclamation 是两个装饰器,分别将文本转换为大写和添加感叹号。
-
使用
exclamation和uppercase创建装饰器链,它们按照声明的顺序依次应用。
3.4 类装饰器
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Something is happening before the function is called.")
result = self.func(*args, **kwargs)
print("Something is happening after the function is called.")
return result
@MyDecorator # 应用类装饰器
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Charlie") # 调用被装饰的函数
-
MyDecorator 是一个类装饰器,它接受一个函数 func 作为参数并在 __call__ 方法中执行额外操作。
3.5 应用实例
性能计时器
import time
def performance_timer(func):
def wrapper(*args, **kwargs):
start_time = time.time() # 记录开始时间
result = func(*args, **kwargs) # 执行被装饰的函数
end_time = time.time() # 记录结束时间
print(f"{func.__name__} took {end_time - start_time} seconds to execute.")
return result
return wrapper
@performance_timer # 应用性能计时器装饰器
def time_consuming_function():
# 模拟一个耗时操作
time.sleep(2)
time_consuming_function() # 调用被装饰的函数并测量执行时间
-
$performance_timer$ 是一个装饰器,它用于测量被装饰函数的执行时间。
-
$wrapper$ 函数 $记录开始时间、执行被装饰函数、记录结束时间$,最后输出执行时间。
二、面向对象编程
面向对象编程(Object-Oriented Programming,简称OOP)是一种通过组织对象来设计程序的编程方法。
Python天生就是面向对象的模块化编程。
1. 初识类和对象
示意图:
/-------> BYD E6(京A.88888) 实例,对象
车(类)
\-------> BMW X5(京B.00000) 实例(对象)
/-------> 小京巴(户籍号:000001)
狗(类)
\-------> 导盲犬(户籍号:000002)
/-------> 100 (对象)
int(类)
\-------> 200 (对象)
1.1 类→Class
物以类聚
1.1.1 概念
类是对一类对象的抽象,是对象的模板或蓝图。它定义了对象的属性(特征)和方法(功能)。
1.1.2 创建
-
数据成员:表明事物的特征。 相当于变量
-
方法成员:表明事物的功能。 相当于函数
-
通过
class关键字定义类。 -
类的创建语句语法:
class 类名 (继承列表):
实例属性(类内的变量) 定义
实例方法(类内的函数method) 定义
类变量(class variable) 定义
类方法(@classmethod) 定义
静态方法(@staticmethod) 定义 -
参考代码:
class Dog: def __init__(self, name, age): self.name = name self.age = age def bark(self): print(f"{self.name} says Woof!")-
类名就是标识符,建议(有点强烈)首字母大写
-
类名实质上就是变量,它绑定一个类
-
self代表类实例化的对象本身
-
1.2 对象→Object
人以群分,每个人就是一个对象。
1.2.1 概念
对象是类的实例化,是类的实际数据存储,具有类所定义的属性和方法。
1.2.2 创建
-
构造函数调用表达式
变量 = 类名([参数])
-
说明
-
变量存储的是实例化后的对象地址
-
类参数按照初始化方法的形参传递
-
对象是类的实例,具有类定义的属性和方法。
-
通过调用类的构造函数来创建对象。
-
每个对象有自己的状态,但共享方法。
-
-
-
示例代码
class Dog: pass # 创建第一个实例: dog1 = Dog() print(id(dog1)) # 打印这个对象的ID # 创建第二个实例对象 dog2 = Dog() # dog2 绑定一个Dog类型的对象 print(id(dog2)) class Person: def __init__(self, name, age): self.name = name self.age = age def introduce(self): print(f"My name is {self.name} and I am {self.age} years old.") person1 = Person("Alice", 25) person2 = Person("Bob", 30)
2. 属性和方法
类的属性和方法是类的核心组成部分,它们用于定义类的状态和行为。
2.1 实例属性
-
每个实例有自己的变量,称为实例变量(也叫属性)
-
属性的使用语法
实例.属性名
-
属性使用
class Dog: def eat(self, food): print(self.color, '的', self.kinds, '正在吃', food) # 创建一个实例: dog1 = Dog() dog1.kinds = "牧羊犬" # 添加属性 dog1.color = "白色" dog1.color = "黄色" # 修改属性 print(dog1.color, '的', dog1.kinds) dog2 = Dog() dog2.kinds = "藏獒" dog2.color = "棕色" print(dog2.color, '的', dog2.kinds) -
实例方法和实例属性(实例变量)结合在一起用
class Dog: def eat(self, food): print(self.color, '的', self.kinds, '正在吃', food) # 创建第一个对象 dog1 = Dog() dog1.kinds = '京巴' # 添加属性kinds dog1.color = '白色' # 添加属性color dog1.eat("骨头") dog2 = Dog() dog2.kinds = '牧羊犬' dog2.color = '灰色' dog2.eat('包子')
2.2 实例方法
class 类名(继承列表):
def 实例方法名(self, 参数1, 参数2, ...):
"文档字符串"
语句块
-
实例方法就是函数,至少有一个指向实例对象的形参self
-
调用
实例.实例方法名(调用传参) # 或 类名.实例方法名(实例, 调用传参)
-
带有实例方法的简单的Dog类
class Dog: """这是一个种小动物的定义 这种动物是狗(犬)类,用于创建各种各样的小狗 """ def eat(self, food): """此方法用来描述小狗吃东西的行为""" print("小狗正在吃", food) def sleep(self, hour): print("小狗睡了", hour, "小时!") def play(self, obj): print("小狗正在玩", obj) dog1 = Dog() dog1.eat("骨头") dog1.sleep(1) dog1.play('球') help(Dog) # 可以看到Dog类的文档信息
2.3 类属性
-
类属性是类的属性,此属性属于类,不属于此类的实例
-
作用:
-
通常用来存储该类创建的对象的共有属性
-
-
类属性说明
-
类属性,可以通过该类直接访问
-
类属性,可以通过类的实例直接访问
-
-
类属性示例
class Human: total_count = 0 # 创建类属性 self.name = name def __init__(self, name): self.name = name print(Human.total_count) h1 = Human("小张") print(h1.total_count)
2.4 类方法
-
类方法是用于描述类的行为的方法,类方法属于类,不属于该类创建的对象
-
说明
-
类方法需要使用classmethod装饰器定义
-
类方法至少有一个形参用于绑定类,约定为 cls
-
类和该类的实例都可以调用类方法
-
类方法不能访问此类创建的对象的实例属性
-
-
类方法示例1
class A: v = 0 @classmethod def set_v(cls, value): cls.v = value @classmethod def get_v(cls): return cls.v print(A.get_v()) A.set_v(100) print(A.get_v()) a = A() print(a.get_v()) -
类方法示例2
class MyClass: class_attr = 0 # 类属性 def __init__(self, value): self.instance_attr = value # 实例属性 @classmethod def modify_class_attr(cls, new_value): cls.class_attr = new_value print(f"类属性已修改为: {cls.class_attr}") @classmethod def try_modify_instance_attr(cls): try: cls.instance_attr = 10 # 事出反常必有妖 except AttributeError as e: print(f"错误: {e}") # 创建类的实例 obj = MyClass(5) # 调用类方法修改类属性 MyClass.modify_class_attr(20) # 输出: 类属性已修改为: 20 MyClass.try_modify_instance_attr()
2.5 静态方法
-
静态方法定义在类的内部,作用域是类内部
-
说明
-
使用@staticmethod装饰器定义
-
不需要self和cls参数
-
通过类或类实例调用
-
可以访问类属性,不能访问实例属性
-
-
静态方法示例
class A: class_attr = 42 # 类属性 def __init__(self, value): self.instance_attr = value # 实例属性 @staticmethod def myadd(a, b): # 只能访问传递的参数,不能访问实例属性 return a + b # 创建类实例 a = A(10) # 调用静态方法 print(A.myadd(100, 200)) # 输出: 300 print(a.myadd(300, 400)) # 输出: 700
2.6 构造方法
构造方法__new__():
-
负责对象的 创建 和内存分配的。
-
在对象实例化时被调用,负责返回一个新的对象实例。
-
通常不需要显式地定义
__new__()方法,Python会调用基类 $object$ 的__new__()方法。
class MyClass:
def __new__(cls, *args, **kwargs):
print("调用 __new__ 方法,创建对象")
return super().__new__(cls)
def __init__(self, value):
print("调用 __init__ 方法,初始化对象")
self.value = value
# 创建对象
obj = MyClass(10)
2.7 初始化方法
-
一旦对象被创建,Python会调用
__init__()来初始化对象的属性。 -
语法格式:
class 类名(继承列表): def __init__(self[, 形参列表]): 语句块 # [] 代表其中的内容可省略接收实参到
__init__方法中 -
代码示例:
class MyClass: def __new__(cls, *args, **kwargs): print("调用 __new__ 方法,创建对象") return super().__new__(cls) def __init__(self, value): print("调用 __init__ 方法,初始化对象") self.value = value # 创建对象 obj = MyClass(10) -
输出:
调用 __new__ 方法,创建对象
调用 __init__ 方法,初始化对象
2.8 魔术方法
魔术方法是一种特殊的方法,用双下划线包裹,例如__init__,__str__,__add__等。这些方法允许您自定义类的行为,以便与内置Python功能(如+运算符、迭代、字符串表示等)交互。
2.8.1 常用方法
-
__init__(self, ...): 初始化对象,通常用于设置对象的属性。 -
__str__(self): 定义对象的字符串表示形式,可通过str(object)或print(object)调用。例如,您可以返回一个字符串,描述对象的属性。 -
__repr__(self): 定义对象的“官方”字符串表示形式,通常用于调试。可通过repr(object)调用。 -
__len__(self): 定义对象的长度,可通过len(object)调用。通常在自定义容器类中使用。 -
__getitem__(self, key): 定义对象的索引操作,使对象可被像列表或字典一样索引。例如,object[key]。 -
__setitem__(self, key, value): 定义对象的赋值操作,使对象可像列表或字典一样赋值。例如,object[key] = value。 -
__delitem__(self, key): 定义对象的删除操作,使对象可像列表或字典一样删除元素。例如,del object[key]。 -
__iter__(self): 定义迭代器,使对象可迭代,可用于for循环。 -
__next__(self): 定义迭代器的下一个元素,通常与__iter__一起使用。 -
__add__(self, other): 定义对象相加的行为,使对象可以使用+运算符相加。例如,object1 + object2。 -
__sub__(self, other): 定义对象相减的行为,使对象可以使用-运算符相减。 -
__eq__(self, other): 定义对象相等性的行为,使对象可以使用==运算符比较。 -
__lt__(self, other): 定义对象小于其他对象的行为,使对象可以使用<运算符比较。 -
__gt__(self, other): 定义对象大于其他对象的行为,使对象可以使用>运算符比较。 -
__call__(self, other)是一个特殊的方法(也称为“魔法方法”),它允许一个对象像函数一样被调用。
2.8.2 案例参考
-
__str__():定义print()或str()函数调用时的输出字符串表示。-
__str__()方法用来定义当你调用print()或str()时对象应该返回的字符串。 -
该方法必须返回一个字符串,通常用于给用户可读的对象描述。
示例:
class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f"Person: {self.name}, Age: {self.age}" p = Person("Alice", 30) print(p) # 输出: Person: Alice, Age: 30作用:
-
使得你的对象在打印时更加友好和可读。
-
提供更好的调试输出。
-
-
__repr__():定义repr()函数的输出,通常用于开发和调试,给出对象的正式字符串表示。-
__repr__()方法用于返回一个可以用来重新创建对象的字符串,理想情况下,返回的字符串应当是合法的 Python 表达式。 -
如果你没有定义
__str__(),那么__repr__()会被用来替代str()和print()。
示例:
class Person: def __init__(self, name, age): self.name = name self.age = age def __repr__(self): return f"Person('{self.name}', {self.age})" p = Person("Alice", 30) print(repr(p)) # 输出: Person('Alice', 30)作用:
-
__repr__()是供开发人员使用的,输出的字符串应该尽可能接近于可以创建该对象的代码。 -
在调试时使用
repr()更加方便,它提供了一个清晰的对象表示。
-
-
__add__():定义 $+$ 运算符的行为。-
该方法允许你重载加法操作符
+,使其在两个对象之间执行加法时能够自定义行为。
示例:
class Point: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __repr__(self): return f"Point({self.x}, {self.y})" p1 = Point(1, 2) p2 = Point(3, 4) p3 = p1 + p2 print(p3) # 输出: Point(4, 6)作用:
-
允许你自定义 $+$ 运算符的行为。
-
-
__len__():定义len()函数的行为。-
__len__()方法允许你自定义len()函数的行为,返回对象的长度。
示例:
class MyList: def __init__(self, items): self.items = items def __len__(self): return len(self.items) my_list = MyList([1, 2, 3]) print(len(my_list)) # 输出: 3作用:
-
使得你的对象能够与
len()函数兼容,返回对象的长度。
-
-
__getitem__():定义对象支持索引([])操作。-
__getitem__()方法使得对象能够支持类似列表、元组那样的索引操作。
示例:
class MyList: def __init__(self, items): self.items = items def __getitem__(self, index): return self.items[index] my_list = MyList([1, 2, 3, 4]) print(my_list[2]) # 输出: 3作用:
-
使对象能够支持索引操作,类似于内置的数据结构(如列表、字典)。
-
-
__setitem__():定义对象支持索引赋值操作([] =)。-
__setitem__()方法允许你定义如何通过索引给对象赋值。
示例:
class MyList: def __init__(self, items): self.items = items def __setitem__(self, index, value): self.items[index] = value my_list = MyList([1, 2, 3]) my_list[1] = 10 print(my_list.items) # 输出: [1, 10, 3]作用:
-
使对象能够支持索引赋值操作。
-
-
__del__():定义对象的析构方法,通常用于资源清理。-
这个方法在对象销毁时调用,通常用于清理资源(如关闭文件、数据库连接等)。
示例:
class MyClass: def __init__(self, name): self.name = name print(f"对象 {name} 创建") def __del__(self): print(f"对象 {self.name} 被销毁") obj = MyClass("Test") del obj # 输出: 对象 Test 被销毁作用:
-
用于对象销毁时进行资源清理。
-
-
__eq__():定义 $==$ 运算符的行为。-
该方法允许你自定义对象的相等比较行为,默认情况下,Python 会比较对象的内存地址。
示例:
class Point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): return self.x == other.x and self.y == other.y p1 = Point(1, 2) p2 = Point(1, 2) print(p1 == p2) # 输出: True作用:
-
使你能够自定义如何比较对象的相等性。
-
3. OOP基本特性
OOP的四大基本特性是封装、继承、多态和抽象。
3.1 封装
-
封装是指将对象的属性和方法包装在一起,对外隐藏实现细节,只提供必要的接口给外部访问。
-
在Python中,通过
__init__方法初始化属性,并通过方法来操作这些属性。 -
以
__开头的属性或方法是私有的,在子类和类外部无法直接使用 -
可使用“私有”属性和“公有”方法控制外部访问。
class Dog:
def __init__(self, name, age):
self.__name = name # 私有属性
self.age = age
def get_name(self):
return self.__name
def set_name(self, name):
self.__name = name
dog = Dog('泰迪', 20)
print(dog.get_name())
dog.set_name('哈士奇')
print(dog._Dog__name)
3.2 继承/派生
儿子继承了父亲,父亲派生了儿子~
Python中所有的类最终都继承自内置的object类。
3.2.1 基础概念
-
继承/派生
-
继承是从已有的类中派生出新的类,新类具有原类的数据属性和行为,并能扩展新的能力。
-
派生类就是从一个已有类中衍生出新类,在新的类上可以添加新的属性和行为
-
-
继承/派生的作用
-
用继承派生机制,可以将一些共有功能加在基类中。实现代码的共享。
-
在不改变基类的代码的基础上改变原有类的功能
-
-
继承/派生名词:
-
基类(base class)/超类(super class)/父类(father class)
-
派生类(derived class)/子类(child class)
-
3.2.2 继承的实现
继承语法:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
只有一个基类是单继承,有多个基类是多继承。
class Animal:
def speak(self):
print("Animal is speaking")
class Dog(Animal):
def speak(self):
print("Woof!")
class Cat(Animal):
def speak(self):
print("Meow!")
dog = Dog()
dog.speak() # 输出 "Woof!"
cat = Cat()
cat.speak() # 输出 "Meow!"
3.2.3 覆盖
-
在子类中实现与基类同名的方法,我们叫覆盖
-
作用:
-
实现和父类同名,但功能不同的方法
-
-
覆盖示例
class A: def work(self): print("A.work 被调用!") class B(A): '''B类继承自A类''' def work(self): print("B.work 被调用!!!") pass b = B() b.work() # 请问调用谁? a = A() a.work() # 请问调用谁?
写一个类Bicycle类, 有run方法,调用时显示骑行里程km
class Bicycle:
def run(self, km):
print("自行车骑行了", km, "公里")
再写一个类EBicycle,在Bicycle类的基础上,添加电池电量volume属性,有两个方法:
1. fill_charge(vol) 用来充电, vol 为电量
2. run(km)方法每骑行10km消耗电量1度,同时显示当前电量,当电量耗尽则,则调用Bicycle的run方法
class EBicyle(Bicycle):
...
参考:
class Bicycle:
def run(self, km):
print("自行车骑行了", km, "公里")
class EBicycle(Bicycle):
def __init__(self, vol):
self.cur_volume = vol # 当前电量
def run(self, km):
e_km = min(km, self.cur_volume * 10) # 求km和 乘余电量能行走的最小里程
self.cur_volume -= e_km / 10
if e_km > 0:
print("电动车骑行了 %d km" % e_km,
"剩余电量:", self.cur_volume)
if km > e_km:
super().run(km - e_km)
def fill_charge(self, vol):
print("电动自行车充电", vol, "度")
self.cur_volume += vol
b = EBicycle(5) # 新买的电动车内有5度电
b.run(10) # 电动骑行了10km 还剩 4度电
b.run(100) # 电动骑行了 40 km ,还剩 0 度电, 用脚登骑行了60km
b.fill_charge(10) # 电动自行车充电 10 度
b.run(50) # 骑行了50公里剩余 5度电
3.3 多态
-
多态是指同一个方法在不同对象上具有不同的行为。
-
通过多态,可以使得不同类型的对象以相同的接口表现出不同的行为。
-
多态的实现通常通过继承和方法重写来实现。
class Animal:
def speak(self):
print("Animal is speaking")
class Dog(Animal):
def speak(self):
print("Woof!")
class Cat(Animal):
def speak(self):
print("Meow!")
def animal_speak(animal):
animal.speak()
dog = Dog()
cat = Cat()
animal_speak(dog) # 输出 "Woof!"
animal_speak(cat) # 输出 "Meow!"
3.4 重写
如果父类方法的功能不能满足需求,可以在子类重写父类的方法
3.4.1 对象转字符串重写
-
对象转字符串函数重写方法
-
str() 函数的重载方法:
-
def __str__(self)-
如果没有
__str__(self)方法,则返回repr(obj)函数结果代替
-
-
-
-
str/repr函数重写示例
class MyNumber: """此类用于定义一个自定义的类,用于演示str/repr函数重写""" def __init__(self, value): """构造函数,初始化MyNumber对象""" self.data = value def __str__(self): """转换为普通字符串""" return "%s" % self.data n1 = MyNumber("一只猫") n2 = MyNumber("一只狗") print("str(n2) ===>", str(n2))
3.4.2 内建函数重写
-
__abs__abs(obj) 函数调用 -
__len__len(obj) 函数调用 -
__reversed__reversed(obj) 函数调用 -
__round__round(obj) 函数调用 -
内建函数 重写示例
# file : len_overwrite.py class MyList: def __init__(self, iterable=()): self.data = [x for x in iterable] def __repr_(self): return "MyList(%s)" % self.data def __len__(self): print("__len__(self) 被调用!") return len(self.data) def __abs__(self): print("__len__(self) 被调用!") return MyList((abs(x) for x in self.data)) myl = MyList([1, -2, 3, -4]) print(myl.data) print(len(myl)) print(abs(myl).data)
3.4.2 运算符重载
-
运算符重载是指让自定义的类生成的对象(实例)能够使用运算符进行操作
-
运算符重载的作用
-
让自定义类的实例像内建对象一样进行运算符操作
-
让程序简洁易读
-
对自定义对象将运算符赋予新的运算规则
-
-
运算符重载说明:
-
运算符重载方法的参数已经有固定的含义,不建议改变原有的意义
-
| 方法名 | 运算符和表达式 | 说明 |
|---|---|---|
__add__(self, rhs) | self + rhs | 加法 |
__sub__(self, rhs) | self - rhs | 减法 |
__mul__(self, rhs) | self * rhs | 乘法 |
__truediv__(self, rhs) | self / rhs | 除法 |
__floordiv__(self, rhs) | self // rhs | 地板除 |
__mod__(self, rhs) | self % rhs | 取模(求余) |
__pow__(self, rhs) | self ** rhs | 幂 |
rhs (right hand side) 右手边
-
二元运算符重载方法格式:
def __xxx__(self, other):
.... -
算术运算符重载示例
class MyNumber: """此类用于定义一个自定义的类,用于演示运算符重载""" def __init__(self, value): """构造函数,初始化MyNumber对象""" self.data = value def __str__(self): """转换为表达式字符串""" return "MyNumber(%d)" % self.data def __add__(self, rhs): """加号运算符重载""" print("__add__ is called") return MyNumber(self.data + rhs.data) def __sub__(self, rhs): """减号运算符重载""" print("__sub__ is called") return MyNumber(self.data - rhs.data) n1 = MyNumber(100) n2 = MyNumber(200) print(n1 + n2) n = n1 - n2 print(n.data)
4. super函数
super() 函数是用于调用父类(超类)的一个方法。
4.1 基本使用
-
在子类方法中使用 super().add() 调用父类中已被覆盖的方法
-
使用 super(Child, obj).myMethod() 用于子类对象调用父类已被覆盖的方法
class A:
def add(self, x):
y = x+1
print(y)
class B(A):
def add(self, x):
print("子类方法")
super().add(x)
b = B()
b.add(2) # 3
class Parent: # 定义父类
def myMethod(self):
print('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child, c).myMethod() # 用子类对象调用父类已被覆盖的方法
4.2 super().__init__()
通过 super().__init__() 调用父类构造函数,以确保父类的构造函数被正确调用和初始化。
class Parent:
def __init__(self):
print("Parent class constructor called")
self.parent_attribute = "I am a parent attribute"
class Child(Parent):
def __init__(self):
super().__init__()
print("Child class constructor called")
self.child_attribute = "I am a child attribute"
# 创建一个 Child 类的实例
child_instance = Child()
print(child_instance.parent_attribute)
# 输出
# Parent class constructor called
# Child class constructor called
为什么使用 super().__init__()?
-
代码重用:避免在子类中重复父类的初始化代码。
-
正确初始化:确保父类的初始化逻辑(如设置属性、分配资源等)被执行。
三、迭代器和生成器
1. 迭代器
Iterator
迭代器是一种对象,实现了Python的迭代协议(__iter__() 和 __next__() 方法)。通过迭代器,可以逐个访问容器中的元素。
1.1 特点
-
惰性计算:按需生成数据,节省内存。
-
实现协议:
-
__iter__():返回自身。 -
__next__():返回下一个元素;如果没有更多元素,则抛出StopIteration异常。
-
-
可迭代对象(Iterable)与迭代器不同:
-
可迭代对象实现
__iter__()方法,返回一个迭代器。 -
迭代器既实现
__iter__()又实现__next__()。
-
1.2 迭代器的创建
-
迭代器只能往前取值,不会后退
-
用iter函数可以返回一个可迭代对象的迭代器
# 示例 可迭代对象
L = [1, 3, 5, 7]
it = iter(L) # 从L对象中获取迭代器
next(it) # 1 从迭代器中提取一个数据
next(it) # 3
print(next(it)) # 5
next(it) # 7
# 示例2 生成器函数
It = iter(range(1, 10, 3))
next(It) # 1
print(next(It)) # 4
next(It) # 7
1.3 自定义迭代器
# 自定义迭代器类
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self # 迭代器返回自身
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration # 数据迭代结束
# 使用自定义迭代器
my_iter = MyIterator([1, 2, 3])
for item in my_iter:
print(item)
2. 生成器
Generator
生成器是一种特殊的迭代器,通过函数定义,用 yield 语句生成值。生成器可以自动实现迭代协议,无需手动实现 __iter__() 和 __next__()。
2.1 特点
-
简洁:比手动实现迭代器更易写。
-
惰性计算:生成器在每次调用 next() 时生成一个值,而不是一次性生成所有值。
-
yield:暂停函数执行并返回值,保留函数的状态,以便下一次继续执行。
示例代码:
# 生成器函数
def my_generator():
print("Start")
yield 1
print("Continue")
yield 2
print("End")
yield 3
# 使用生成器
gen = my_generator()
for val in gen:
print(val)
输出:
Start
1
Continue
2
End
3
案例参考:
def Descendorder(n):
while n > 0:
yield n
n -= 1
# 创建生成器对象
generator = Descendorder(5)
# 通过迭代生成器获取值
print(next(generator)) #5
print(next(generator)) #4
# 使用 for 循环迭代生成器
for i in generator:
print('for循环:', i) #3 2 1
2.2 生成器表达式
生成器可以用表达式形式定义,类似列表推导式,但使用小括号 ()。
-
语法
(表达式 for 变量 in 可迭代对象 [if 真值表达式])
[] 内容代表可以省略
# 生成器表达式 gen_expr = (x**2 for x in range(5)) print(next(gen_expr)) # 0 print(next(gen_expr)) # 1
2.3 课堂练习
代码实现斐波那契数列(最少十个数)
参考代码:
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield b
a, b = b, a + b
fib_seq = fibonacci(10)
for i in fib_seq:
print(i, end=" ")
# 运行结果
# 1 1 2 3 5 8 13 21 34 55
2.4 应用场景
-
数据流处理:处理大文件或流式数据,避免内存耗尽。
-
无限序列生成:如斐波那契数列、素数序列。
-
管道化数据处理:与
itertools模块结合使用。
参考代码:
def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line.strip()
for line in read_large_file('large_file.txt'):
print(line)
3. 区别对比
| 特性 | 迭代器 | 生成器 |
|---|---|---|
| 实现 | 通过类实现,手动定义方法 | 使用函数和 yield 定义,自动实现迭代协议 |
| 代码简洁性 | 代码较复杂 | 代码简单 |
| 状态管理 | 手动管理状态 | 自动保存函数的运行状态 |
| 惰性计算 | 支持 | 支持 |
| 示例应用 | 自定义复杂的迭代逻辑 | 简单的数据流生成 |
四、异常处理
用作信号通知,通知上层调用者有错误产生需要处理
1. try 语句
-
语法
try:
可能发生异常的语句块
except 错误类型1 [as 变量名1]:
异常处理语句块1
except 错误类型2 [as 变量名2]:
异常处理语句块2
...
except 错误类型n [as 变量名n]:
异常处理语句块n
except:
异常处理语句块other
else:
未发生异常的语句
finally:
最终的处理语句
-
作用
尝试捕获异常,得到异常通知,将程序由异常状态变为正常状态
-
说明
-
except 子句可以有 1个或多个
-
-
except: 不给错误类型,可以匹配全部的错误类型
-
else 子句在没有错误发生时执行,当处于异常时不执行
-
finally 子句里的语句,无论何时都执行
-
示例
try:
x = int(input("请输入一个整数:"))
print('x=', x)
except ValueError:
print('您的输入不能转成整数')
print("程序结束")
2. raise 语句
-
问题
# 写一个函数, get_score 函数,读取用户输入的整数成绩, # 成绩的正常值是0~100 之间, 要求, 如果不在0~100 之间 # 报 ValueError类型的错误 def get_score(): x = int(input('请输入成绩:')) if 0 <= x <= 100: return x raise ValueError -
语法
raise 异常类型 或 raise 异常对象
-
作用
-
抛出一个错误,让程序进入异常状态
-
发送错误通知给调用者
-
-
示例:
# 写一个函数, get_score 函数,读取用户输入的整数成绩,
# 成绩的正常值是0~100 之间,
# 如果不在0~100之间报ValueError类型的错误
def get_score():
x = int(input('请输入成绩:'))
if 0 <= x <= 100:
return x
# raise ValueError
raise ValueError('用户输入的成绩不在 0~100 之间')
try:
score = get_score()
print(score)
except ValueError as err:
print("成绩输入有误 err=", err)
err的作用就是接收raise ValueError('用户输入的成绩不在 0~100 之间')给出的提示信息
-
异常类型的可选种类
写一个猜拳游戏: 石头,剪刀,布, 让电脑随机生成一个, 你的输入如下: (0) 石头 (1) 剪刀 (2) 布 (q) 退出 请选择: 0 电脑出的是 布 ,你输了 循环输入,知道输入q 为止 -
参考答案1
import random import time signal = ['石头', '剪刀', '布'] def show_menu(): print(" 0) 石头 ") print(" 1) 剪刀 ") print(" 2) 布 ") print(" q) 退出 ") def begin_compare(computer, your): comp_s = signal[computer] # 电脑的字符串 your_s = signal[your] print('电脑出的是', comp_s, '你出的是', your_s) if comp_s == your_s: print('平局!') elif comp_s == '石头': if your_s == '剪刀': print('你输了!') elif your_s == '布': print('你赢了!') elif comp_s == '剪刀': if your_s == '布': print('你输了!') elif your_s == '石头': print('你赢了!') elif comp_s == '布': if your_s == '石头': print('你输了!') elif your_s == '剪刀': print('你赢了!') # time.sleep(5) input('请输入回车键,继续下一次猜拳:') def run(): '''开始猜拳游戏''' while True: show_menu() s = input('请选择:') if s == 'q': break your = int(s) # 你的选项 computer = random.randint(0, 2) begin_compare(computer, your) if __name__ == '__main__': run()参考答案2
import random import time signal = ['石头', '剪刀', '布'] result = ['平局!', '你赢了!', '你输了!'] # 0 1 -1 # 定义一个二维列表, 行代表 电脑的选择, 列代表我的选择 map = [ # 用户: 0 1 2 [ 0, -1, 1], # 电脑出的是0---> 石头 [ 1, 0, -1], # 电脑出的是1---> 剪刀 [-1, 1, 0], # 电脑出的是2---> 布 ] def show_menu(): print(" 0) 石头 ") print(" 1) 剪刀 ") print(" 2) 布 ") print(" q) 退出 ") def begin_compare(computer, your): comp_s = signal[computer] # 电脑的字符串 your_s = signal[your] print('电脑出的是', comp_s, '你出的是', your_s) result_index = map[computer][your] r = result[result_index] print(r) # time.sleep(5) input('请输入回车键,继续下一次猜拳:') def run(): '''开始猜拳游戏''' while True: show_menu() s = input('请选择:') if s == 'q': break your = int(s) # 你的选项 computer = random.randint(0, 2) begin_compare(computer, your) if __name__ == '__main__': run() -
课后练习2
写一个猜数字游戏 让电脑随机生成一个 0 ~ 100 的整数让用来猜
如果 您输入的数大于电脑生产的数,提示:“您猜大了”, 继续猜
如果 您输入的数小于电脑生产的数,提示:“您猜小了”, 继续猜
当 您输入的数等于电脑生产的数,提示:"恭喜您猜对了" 打印猜的次数后退出程序参考答案
import random def run(): # 1. 让电脑生成一个整数,用 x 变量绑定 x = random.randint(0, 100) count = 0 # 记次数 while True: y = int(input('请输入: ')) count += 1 if y > x: print('您猜大了!') elif y < x: print('您猜小了!') else: print('恭喜您猜对了!') break print('您共猜了', count, '次') if __name__ == '__main__': run()
3. 错误类型
| 错误类型 | 说明 |
|---|---|
| ZeroDivisionError | 除(或取模)零 (所有数据类型) |
| ValueError | 传入无效的参数 |
| AssertionError | 断言语句失败 |
| StopIteration | 迭代器没有更多的值 |
| IndexError | 序列中没有此索引(index) |
| IndentationError | 缩进错误 |
| OSError | 输入/输出操作失败 |
| ImportError | 导入模块/对象失败 |
| NameError | 未声明/初始化对象 (没有属性) |
| AttributeError | 对象没有这个属性 |
| <!-- 以下不常用 --> | |
| GeneratorExit | 生成器(generator)发生异常来通知退出 |
| TypeError | 对类型无效的操作 |
| KeyboardInterrupt | 用户中断执行(通常是输入^C) |
| OverflowError | 数值运算超出最大限制 |
| FloatingPointError | 浮点计算错误 |
| BaseException | 所有异常的基类 |
| SystemExit | 解释器请求退出 |
| Exception | 常规错误的基类 |
| StandardError | 所有的内建标准异常的基类 |
| ArithmeticError | 所有数值计算错误的基类 |
| EOFError | 没有内建输入,到达EOF 标记 |
| EnvironmentError | 操作系统错误的基类 |
| WindowsError | 系统调用失败 |
| LookupError | 无效数据查询的基类 |
| KeyError | 映射中没有这个键 |
| MemoryError | 内存溢出错误(对于Python 解释器不是致命的) |
| UnboundLocalError | 访问未初始化的本地变量 |
| ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
| RuntimeError | 一般的运行时错误 |
| NotImplementedError | 尚未实现的方法 |
| SyntaxError Python | 语法错误 |
| TabError | Tab 和空格混用 |
| SystemError | 一般的解释器系统错误 |
| UnicodeError | Unicode 相关的错误 |
| UnicodeDecodeError | Unicode 解码时的错误 |
| UnicodeEncodeError | Unicode 编码时错误 |
| UnicodeTranslateError | Unicode 转换时错误 |
| 以下为警告类型 | |
| Warning | 警告的基类 |
| DeprecationWarning | 关于被弃用的特征的警告 |
| FutureWarning | 关于构造将来语义会有改变的警告 |
| OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
| PendingDeprecationWarning | 关于特性将会被废弃的警告 |
| RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
| SyntaxWarning | 可疑的语法的警告 |
| UserWarning | 用户代码生成的警告 |
版权声明:本文标题:Python学习笔记3 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1766533306a3467466.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论