今天将昨天关于类与对象没有完成的完成了,接着讲了一点python的函数式编程思想。
剩余的类与对象
1.封装
封装是指隐藏类的实现细节,让使用者不用关心这些细节;封装的目的是让使用者通过尽可能少的方法(或属性)操作对象,但是Python的封装是假的,所以即使是私有方法或者私有属性都是能够强行访问的。
class A:
def __init__(self):
self.__p1 = 100 # 私有属性
def __m1(self): # 私有方法
print("__m1(self) 方法被调用")
def showA(self):
self.__m1()
print("self.__p1 = ", self.__p1)
class B(A):
def __init__(self):
super().__init__()
def showB(self):
self.__m1() # 出错,不允许调用
print("self.__p1 = ", self.__p1) # 出错,不允许调用
# self._A__m1() # 正常调用
# print("self.__p1 =", self._A__p1) # 正常访问
a = A()
a.showA()
a.__m1() # 出错,不允许调用
v = self.__p1 # 出错,不允许调用
b = B()
b.showB()
# 访问私有属性
print(a._A__p1) # 输出: 100
# 调用私有方法
a._A__m1() # 输出: __m1(self) 方法被调用
# 不推荐了解就行
2.super函数
主要用于解决类似于钻石继承等类的问题,支持调用已覆盖的父类方法。支持多继承,会根据顺序执行父类中的方法。可以简化代码也避免无限循环。经常使用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
3.迭代器和生成器
1.迭代器
迭代器是访问可迭代对象的工具,迭代器函数有iter和next
| 函数 | 说明 |
|---|---|
| iter(iterable) | 从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象 |
| next(iterator) | 从迭代器iterator中获取下一个记录,如果无法获取一下条记录,则触发 StopIteration 异常 |
示例:
# 示例 可迭代对象
L = [1, 3, 5, 7]
it = iter(L) # 从L对象中获取迭代器
next(it) # 1 从迭代器中提取一个数据
next(it) # 3
next(it) # 5
next(it) # 7
next(it) # StopIteration 异常
# 示例2 生成器函数
It = iter(range(1, 10, 3))
next(It) # 1
next(It) # 4
next(It) # 7
next(It) # StopIteration
在介绍迭代器的过程中,老师给我们介绍了try except组合,此组合是用来捕捉错误的,在try下写入可能会出现错误的方法体等,在except中写入捕捉到错误之后程序指向的表达式。
# 可迭代的对象
L = list(range(10))
it = iter(L)
while True:
try:
print(next(it))
except:
print("迭代结束")
break
2.生成器
生成器只有yield一个,它通常不在内存中保留大量数据,基本是现用现生成。生成器函数是一种特殊的函数,可以在迭代过程种逐步产生值,而不是直接返回所有结果,对口的是在迭代器中返回值,与他功能相似的是return,但是return返回的是不可迭代的对象,yield返回的是可迭代的对象。
生成器函数
含有yield 语句的函数是生成器函数,此函数调用回返回一个生成器对象,生成器也是可迭代对象
yield 语句的语法
yield 表达式
生成器函数示例1:
## 定义一个生成器函数, 有 yield 的函数调用后回返回生成器对象
def myrange(stop):
i = 0
while i < stop:
yield i # 为 遍历次生产器的for 语句提供数据
i += 1
for x in myrange(5):
print('x=', x)
# 创建一个生成器对象
gen = myrange(5)
# 使用 next() 函数迭代生成器
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
以上实例中,Descendorder 函数是一个生成器函数。它使用 yield 语句逐步产生从 n 到 1 的倒序数字。在每次调用 yield 语句时,函数会返回当前的倒序数字,并在下一次调用时从上次暂停的地方继续执行。
创建生成器对象并使用 next() 函数或 for 循环迭代生成器,我们可以逐步获取生成器函数产生的值。在这个例子中,我们首先使用 next() 函数获取前两个倒序数字,然后通过 for 循环获取剩下的三个倒序数字。
生成器函数的优势是它们可以按需生成值,避免一次性生成大量数据并占用大量内存。此外,生成器还可以与其他迭代工具(如for循环)无缝配合使用,提供简洁和高效的迭代方式。
函数式编程
定义:用一系列函数解决问题。
-
函数可以赋值给变量,赋值后变量绑定函数。
-
允许将函数作为参数传入另一个函数。
-
允许函数返回一个函数。
1.函数作为参数
将核心逻辑传入方法体,使该方法的适用性更广
示例1:
def func01():
print("func01执行")
# a = func01
# # print(a)
# a()
def func02():
print("func02执行")
# 通用
def func03(func):
print("func03执行")
func()
func03(func02)
func03(func01)
将函数作为参数传入主函数,主函数传参的方法调用其他方法和实现主方法。
示例2:
list01 = [4, 54, 56, 65, 67, 7]
# 需求1:定义函数,在列表中查找所有大于50的数字
def find01():
for item in list01:
if item > 50:
yield item
# 需求2:定义函数,在列表中查找所有小于10的数字
def find02():
for item in list01:
if item < 10:
yield item
# “封装” -- 分
def condition01(item):
return item > 50
def condition02(item):
return item < 10
# 通用
# “继承” - 隔
def find(func):
for item in list01:
# if item < 10:
# if condition02(item):
if func(item):
yield item
# "多态" - 做
for item in find(condition01):
print(item)
for item in find(condition02):
print(item)
这里更可以看出函数式编程的特点了,因为两个功能的实现方法相似,直接将二者的核心逻辑融入一个函数体,再将不同的逻辑通过函数做的参的方式让主函数调用。
1.lambda表达式
之前有用过lambda语法,所以就简单的介绍这种匿名函数
语法
# 定义:
变量 = lambda 形参: 方法体
# 调用:
变量(实参)
本次介绍lambda方法主要是为了配合后面的内置高阶函数使用。因为lambda的特点是其方法体只能有一条语句,且不支持赋值语句,而内置高阶函数都有需要传入一个函数,所以简短的lambda是最佳选择
2.内置高阶函数
本次介绍的内置高阶函数一共五个,
(1)map(函数,可迭代对象)
使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。
(2)filter(函数,可迭代对象)
根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。
(3)sorted(可迭代对象, key=函数, reverse=True)
排序,返回值为排序后的列表结果。
(4)max(可迭代对象, key = 函数)
根据函数获取可迭代对象的最大值。
(5)min(可迭代对象,key = 函数)
根据函数获取可迭代对象的最小值。
简单的理解,map是用于整体查询的,filter是整体按条件查询的,sorted是整体按key=这个关键信息进行排序的,而max是min则是根据key进行比较,最后只返回可迭代对象的一个值作为max或者min函数的结果。所以max和min无法与其他的方法一样在for循环中作为可迭代对象使用。
示例:
class Girl:
def __init__(self, name="", face_score=0, age=0, height=0):
self.name = name
self.face_score = face_score
self.age = age
self.height = height
def __str__(self):
return "%s-%d-%d-%d" % (self.name, self.face_score, self.age, self.height)
list_girl = [
Girl("双儿", 96, 22, 166),
Girl("阿珂", 100, 23, 173),
Girl("小郡主", 96, 22, 161),
Girl("方怡", 86, 27, 166),
Girl("苏荃", 99, 31, 176),
Girl("建宁", 93, 24, 163),
Girl("曾柔", 88, 26, 170),
]
# 1. map 映射
# 在美女列表中获取所有名称
# 类似于:select
for element in map(lambda item: item.name, list_girl):
print(element)
# 2. filter 过滤器
# 在美女列表中获取颜值大于90的所有美女
# 类似于:find_all
for element in filter(lambda item: item.face_score > 90, list_girl):
print(element)
# 3. max/min
# 在美女列表中获取颜值最高的美女
# 类似于:get_max
print(max(list_girl,key = lambda item:item.face_score))
print(min(list_girl,key = lambda item:item.face_score))
# 4.sorted 排序
# 注意:没有改变原有列表,而是返回新的
# 升序
for item in sorted(list_girl,key = lambda item:item.height):
print(item)
# 降序
for item in sorted(list_girl,key = lambda item:item.height,reverse=True):
print(item)
2. 函数作为返回值
2.1 闭包
闭包是指用了此函数外部嵌套函数的变量的函数 闭包就是能够读取其他函数内部变量的函数。只有函数内部的嵌套函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数,同时这个函数又引用了外部的变量“。
闭包必须满足的三个条件:1,必须有一个内嵌函数 2,内嵌函数必须引用外部函数中变量 3,外部函数返回值必须是内嵌函数
示例:
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)
在其中可以将give_yasuiqian中的return作为一个接口,当give_yasuiqian完成示例创建后,该实例的实际类型为chlid_buy,而如果对使用cb(),启用该函数则激活内嵌函数chlid_buy函数,所以创建give_yasuiqian的实例对象相当于创建了child_buy的实例对象。
2.2 装饰器 decorators
装饰器的语法:
def 装饰器函数名(fn):
语句块
return 函数对象
@装饰器函数名 <换行>
def 被装饰函数名(形参列表):
语句块
用函数装饰器替换原函数myfun
def mydeco(fn):
fn()
print("装饰器函数被调用了,并返回了fx")
def fx():
print("fx被调用了")
# return fn()
return fx
@ mydeco
def myfun():
print("函数myfun被调用")
myfun()
myfun()
这里调用myfun()可以看作将myfun以参数形式传入mydeco()且激活mydeco(),而第一步就是实例化传入的函数体,所以第一个输出的“函数myfun被调用”,而第二步则是打印“装饰器函数被调用了,并返回fx,因为返回的结果为fx这个实例,所以再次调用就是直接直接调用fx这个实例方法,最后输出”fx被调用了“ 。


















