Python的一些基础知识(1)
网站上一般只会提供一些最简单的有关Python的知识,在实践中,会遇到各种新的问题,为了能够提升对Python基础知识的掌握。这里总结了一些Python相关的基础知识。
Python中的抽象类
类是对一堆对象共同内容的抽取,那么抽象类就是对一堆类共同内容的抽取,包括属性和方法。
在Python中,可以使用abc模块来定义抽象类(Abstract Class)和抽象方法(Abstract Method)。抽象类是一种不能被实例化的类,它主要用于定义接口和提供基础的实现逻辑,而抽象方法是在抽象类中声明但没有具体实现的方法,需要在子类中进行实现。下面是一个简单的示例代码:
下面展示一个 示例代码
。
from abc import ABC, abstractmethod
class AbstractClassExample(ABC):
@abstractmethod
def abstract_method(self):
pass
def concrete_method(self):
print("This is a concrete method.")
class ConcreteClassExample(AbstractClassExample):
def abstract_method(self):
print("Implementation of abstract_method.")
# 无法实例化抽象类
# example = AbstractClassExample()
# 可以实例化具体类
example = ConcreteClassExample()
# 调用抽象方法和具体方法
example.abstract_method()
example.concrete_method()
由此,我们可以得出抽象类的特点。
- 抽象类必须包含一个或多个抽象方法,也可以包含普通方法。
- 抽象类的抽象方法,在抽象类中并不作实现。
- 抽象类不能被实例化。
- 抽象类的子类要想进行实例化,必须先实现抽象父类中的所有抽象方法。
主要用途:
-
定义接口:抽象类可以用于定义一组接口或契约,规定了子类需要实现的方法。通过继承抽象类并实现其中的抽象方法,可以确保子类具有相同的接口,从而达到一致性和可替换性的目的。
-
强制子类实现方法:抽象类中的抽象方法必须在子类中进行实现。通过定义抽象方法,抽象类可以强制子类提供特定的行为或具体实现。这有助于确保子类的一致性,并使代码更易于维护和扩展。
-
提供默认实现:抽象类可以包含具体的方法实现,这些方法在子类中可直接使用。这样,子类只需要实现抽象方法或覆盖需要定制的方法,而不需要重新实现所有方法。抽象类可以提供一些通用的功能,以减少重复代码。
-
类型检查和文档提示:抽象类可以用于对代码进行类型检查和提供文档提示。通过声明抽象类作为参数、返回值或变量类型,可以在静态类型检查工具(如mypy)或IDE中获得更好的代码检查和自动完成功能。
总而言之,抽象类提供了一种结构化和规范化的方式来定义类的接口和行为。它们鼓励代码的模块化、可维护性和可扩展性,并提供了一些便利的功能,如强制实现、默认实现和类型检查。通过使用抽象类,可以更好地组织和设计代码,并使代码更具可读性和可重用性。
闭包
闭包是指一个函数对象,它可以访问该函数定义所在的环境中的变量,即使在函数被调用并返回之后,这些变量仍然存在于内存中。闭包可以看作是函数和其相关的引用环境组成的一个整体,它可以“记住”函数定义时的环境,以便在函数调用时使用。
特点
-
闭包是一个函数对象,可以像其他函数一样进行调用和传递参数。
-
闭包可以访问外部函数中定义的变量,即使在外部函数调用结束后,这些变量仍然存在于内存中。
-
闭包可以“记住”函数定义时的环境,以便在函数调用时使用。
实现方式
def square(x):
def inner():
return x ** 2
return inner
s = square(2) # 返回一个闭包
print(s()) # 输出4
应用场景
-
延迟计算:闭包可以在函数调用时“记住”函数定义时的环境,可以用来实现延迟计算,即在需要计算结果时再进行计算。例如,可以定义一个计算平方的函数,但不立即进行计算,而是返回一个闭包,当闭包被调用时再进行计算。
-
缓存数据:闭包可以将外部函数中的变量保存在内存中,可以用来实现缓存数据的功能。例如,可以定义一个函数,每次调用时返回一个闭包,闭包可以缓存之前的计算结果,避免重复计算。
-
实现装饰器:装饰器是Python中常用的一种编程技巧,可以用来动态修改函数的行为。闭包可以用来实现装饰器,即将一个函数作为参数传递给另一个函数,返回一个闭包,闭包可以在调用原函数之前或之后进行一些额外的操作。
装饰器
装饰器本身是一个函数,它可以接受函数作为参数,并返回一个新的函数,被称为修饰过的函数。例如在函数执行前、执行中、执行后扩展原函数的功能;它还可以用于检查函数的参数,或者对函数的返回值进行修改等。
使用装饰器的好处:
- 装饰器允许在不改变函数本身的情况下扩展函数的功能。
- 使用装饰器可以让函数更简洁、复用率更好,减少重复造轮子。
下面用一些示例代码
来进一步理解和分析装饰器的作用:
无参数传入装饰
// A code block
def my_decorator(func):
def wrapper():
print("执行函数前")
func()
print("执行函数后")
return wrapper
@my_decorator
def say_hello():
print("Hello world!")
say_hello()
# 打印结果
'''
执行函数前
Hello world!
执行函数后
'''
上述代码在函数执行前和执行后增加了一些附加操作,相当于扩展了函数的功能。
另一个示例代码
参数传入装饰
// A code block
def my_decorator(arg1, arg2):
def inner_decorator(func):
def wrapper(a, b):
if isinstance(arg1,(float,int)):
a = a + arg1
print(f'{arg1} participated in the calculation process.')
else:
print(f'{arg1} did not participate in the calculation process')
if isinstance(arg2, (float,int)):
b = b + arg2
print(f'{arg2} participated in the calculation process.')
else:
print(f'{arg2} did not participate in the calculation process')
print("Before function call")
result = func(a, b)
print("Finished the calculation process.")
return result
return wrapper
return inner_decorator
@my_decorator("hello", "world")
def add_function(x1,y1):
print(x1+y1)
print("Finished an addition operation ")
add_function(1,2)
# 打印结果
'''
hello did not participate in the calculation process
world did not participate in the calculation process
Before function call
3
Finished an addition operation
Finished the calculation process.
'''
这段代码中首先定义了一个嵌套的装饰器函数my_decorator。装饰器函数需要两个参数。定义了一个被装饰的加法函数add_function,用于计算两个数字的和。
装饰器函数的两个参数,首先判断是否是浮点数或者整数,如果是,则对函数wrapper的两个参数a和b重新分别赋值。然后将赋值后的参数传入add_function函数进行加法运算。
多个装饰器的示例代码
def my_decorator1(func):
def wrapper():
print("执行装饰器1前")
func()
print("执行装饰器1后")
return wrapper
def my_decorator2(func):
def wrapper():
print("执行装饰器2前")
func()
print("执行装饰器2后")
return wrapper
@my_decorator1
@my_decorator2
def say_hello():
print("Hello world!")
say_hello()
# 打印结果
'''
执行装饰器1前
执行装饰器2前
Hello world!
执行装饰器2后
执行装饰器1后
'''
上面的代码中,定义了两个装饰器my_decorator1和my_decorator2。
say_hello函数首先被my_decorator2装饰器修饰,然后再用my_decorator1修饰。在执行过程中,装饰器会按顺序执行。
除了函数装饰器,Python还支持类装饰器,它接受一个函数,并返回一个修饰后的函数。这与函数装饰器非常相似,只不过是使用类而不是函数。
下面是一个类装饰器的示例代码
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("执行函数前")
self.func(*args, **kwargs)
print("执行函数后")
@MyDecorator
def say_hello():
print("Hello world")
say_hello()
上面的代码中,我们用类定义了一个装饰器MyDecorator,它有一个__init__ 方法和一个__call__方法。其中,__init__方法接收一个函数作为参数,并存储在self.func变量中。__call__方法调用函数前后打印一些信息,然后调用self.func函数本身。最后,我们用@MyDecorator将函数say_hello()用MyDecorator装饰器修饰。
装饰器的应用场景
-
日志记录:使用装饰器来记录函数的调用过程,包括函数名称、参数和返回值等。
-
缓存数据:使用装饰器来缓存函数的计算结果,以加快函数的执行速度。
-
输入检查:使用装饰器来检查函数的输入参数是否符合要求。
-
认证授权:使用装饰器来检查用户的权限,以确保只有授权用户才能调用函数。
回调函数(Callback Function)
回调函数是指将一个函数作为参数传递给另一个函数,并在需要时被调用的函数。
特点
- 通过函数地址调用函数,如果函数的指针(地址)作为参数传递给另外一个函数
- 函数的入参为函数类型
- 在特定的事件或者条件发生时由另外一方调用,用于对该事件或者条件进行响应
- 在参数位置,「使用函数进行传参时,尾部不需要添加()」
回调函数的实现 示例代码
def calculator(v1,v2,fn):
result = fn(v1,v2)
return result
def add(v1,v2):
return v1 + v2
# 调用calculator,计算1+1
print(calculator(1,1,add))
回调函数和递归函数的区别
回调函数是在一个函数中“回调函数”以参数的形式传入,并在该函数内部被调用。而递归函数是在一个函数中,调用了自己。
使用场景
- 事件处理。在事件驱动的程序中,回调函数经常用于处理特定的事件;比如进行错误处理,对异常结果进行记录,发送警报或者执行数据恢复工作。
示例代码片
。
# 比如记录错误日志、发送警报、执行恢复操作等。
def auto_task(callback):
try:
# 执行自动化任务的代码
# ...
# 如果出现错误,抛出异常
print(1/0)
except Exception as e:
# 调用错误处理的回调函数
callback(e)
def error_callback(error):
print(f'开始执行错误数据处理:{error}')
auto_task(error_callback)
- 迭代器和生成器。回调函数可以用于实现自定义的迭代器和生成器。例如,在读取大型文件时,可以定义一个回调函数,在每次读取到一行文本时被调用。这种方式可以有效地处理大量数据,而不需要一次性将整个文件加载到内存中。
示例代码
。
def read_large_file(file_path, callback):
with open(file_path, 'r') as file:
for line in file:
# 调用回调函数处理每一行文本
callback(line)
# 定义回调函数来处理每一行文本
def process_line(line):
print("Processing line:", line.strip())
# 使用迭代器按行读取大型文件
# 未对数据进行处理
with open('静夜思.txt','r',encoding='utf-8') as f:
for i in f:
print(i)
# 使用回调函数对数据进行处理
read_large_file('静夜思.txt',process_line)
- 定时器和事件循环。回调函数可以用于定时器和事件循环的编程。设置一个定时器,在指定的时间间隔后调用回调函数。这对于周期性任务、定时任务和事件循环非常有用。
下面是一个示例代码
。
import time
def timer_callback(i):
print(f'定时器启动,执行了第{i}次'.center(20,'*'))
def set_time(timer,callback):
i = 0
while True:
time.sleep(timer)
i +=1
# 使用回调函数对定时器进行处理
callback(i)
set_time(5,timer_callback)
-
钩子函数。
回调函数也可以用作钩子函数,用于在特定的代码点执行自定义的操作。- 允许开发人员在代码的特定位置注入自己的逻辑,以便在关键时刻执行自定义操作。提供了一种灵活的扩展机制,使应用程序可以通过插件或扩展点来自定义行为,而无需修改核心代码。
- 可以定义一个回调函数,用于在启动时加载配置。这样,当框架或库初始化时,回调函数会被触发,并且您可以在其中加载和应用定义好的自定义配置。
- 在case执行完毕后,需要关闭或终止时清理资源。可以定义回调函数在应用程序关闭之前执行一些必要的清理操作,如释放内存、关闭文件、断开数据库连接等。
参考
Python中装饰器的基础使用
10 个简单但超级有用的 Python 装饰器,事半功倍
Python 第十六讲:回调函数