Python编程
Completion requirements
重复代码被认为是软件开发中的一种不良实践,原因有很多,其中之一是它需要更多的工作来维护。如果你有相同的算法作用于不同的数据集,你可以将算法放入一个函数中,并传入数据,避免代码的重复。然而,有时你会发现,代码本身发生了变化,但两个或多个地方仍然有大量重复的模板代码。
一个典型的例子可能是日志记录:
def multiply(a, b):
result = a * b
log("multiply has been called")
return result
def add(a, b):
result = a + b
log("add has been called")
return result
在这种情况下,不容易找出如何提取出重复的代码。我们可以遵循之前的模式,将公共代码移到一个函数中,但仅仅用不同的数据调用这个函数,并不足以产生我们想要的不同行为(加法或乘法)。相反,我们需要传递一个函数给公共函数。这就涉及到一个操作函数的函数,称为高阶函数。
在 Python 中,装饰器是一种用于高级函数的语法糖。
属性装饰器的最小示例:
class Foo(object):
@property
def bar(self):
return 'baz'
F = Foo()
print(F.bar) # 输出 'baz'
上面的例子其实就是以下代码的语法糖:
class Foo(object):
def bar(self):
return 'baz'
bar = property(bar)
F = Foo()
print(F.bar) # 输出 'baz'
通用装饰器的最小示例:
def decorator(f):
def called(*args, **kargs):
print('A function is called somewhere')
return f(*args, **kargs)
return called
class Foo(object):
@decorator
def bar(self):
return 'baz'
F = Foo()
print(F.bar()) # 输出 'A function is called somewhere' 和 'baz'
装饰器的一个好用场景是让你重构代码,将公共特性移动到装饰器中。例如,假设你想追踪所有函数调用,并打印每次调用的所有参数的值。那么你可以像下面这样在装饰器中实现:
# 定义一个 Trace 类,用于装饰器
class Trace(object):
def __init__(self, f):
self.f = f
def __call__(self, *args, **kwargs):
print("entering function " + self.f.__name__)
i = 0
for arg in args:
print("arg {0}: {1}".format(i, arg))
i += 1
return self.f(*args, **kwargs)
然后你可以在任何你定义的函数上使用这个装饰器:
@Trace
def sum(a, b):
print("inside sum")
return a + b
运行这段代码时,你会看到类似如下的输出:
sum(3, 2)
# 输出:
# entering function sum
# arg 0: 3
# arg 1: 2
# inside sum
def Trace(f):
def my_f(*args, **kwargs):
print("entering " + f.__name__)
result = f(*args, **kwargs)
print("exiting " + f.__name__)
return result
my_f.__name = f.__name__
my_f.__doc__ = f.__doc__
return my_f
# 使用 Trace 装饰器的示例
@Trace
def sum(a, b):
print("inside sum")
return a + b
# 运行时应该看到:
sum(3, 2)
# 输出:
# entering sum
# inside sum
# exiting sum
# 5
Last modified: Friday, 31 January 2025, 1:02 AM