在Python中,函数是一等对象。
一等对象
在运行时创建
能赋值给变量或数据结构中的元素
能作为参数传给函数
能作为函数的返回结果
第二点和第三点在实际编写代码的时候经常用到!
高阶函数
接受函数为参数,或者把函数作为结果返回的函数就是高阶函数。
常见的高阶函数:
map
filter
reduce
函数式语言通常会提供这三个高阶函数
在Python中可以使用列表推导式来替代实现
def fact(n):
return 1 if n < 2 else n * fact(n - 1)
print(list(map(fact, range(6))))
print([fact(n) for n in range(6)])
匿名函数
使用lambda
关键字可以创建匿名函数
除了作为参数传递给高阶函数之外,不建议使用匿名函数。
Lundh提出的匿名函数重构秘籍:
编写注释,说明lambda表达式的作用
研究注释,找出一个名称来概括注释
把lambda表达式转换成def语句,使用那个名称来定义函数
删除注释
一般的lambda表达式要么难以阅读,要么无法写出。
可调用对象
使用callable()
方法查看对象是否是可调用对象
只要实现__call__
方法,任何Python对象都可以调用
class A():
def __init__(self, a, b):
self.a = a
self.b = b
def add(self):
return self.a + self.b
def __call__(self, *args, **kwargs):
return self.a + self.b
if __name__ == '__main__':
a = A(1, 2)
print(a.add())
print(a())
关于参数的信息
from inspect import signature
def clip(text, max_len=80):
end = None
if len(text) > max_len:
space_before = text.rfind(" ", 0, max_len)
if space_before >= 0:
end = space_before
else:
space_before = text.rfind(" ", max_len)
if space_before >= 0:
end = space_before
if end is None:
end = len(text)
return text[:end].rstrip()
if __name__ == '__main__':
print(clip.__defaults__) # (80,) 默认值
print(clip.__code__)
print(clip.__code__.co_varnames) # ('text', 'max_len', 'end', 'space_before') 全部变量 包含局部变量
print(clip.__code__.co_argcount) # 2 入参个数
sig = signature(clip)
print(sig) # (text, max_len=80)
for name, param in sig.parameters.items():
print(f"{param.kind}:{name}={param.default}")
# 1:text=<class 'inspect._empty'>
# 1:max_len=80
函数注解
为函数声明中参数和返回值附加元数据
def clip(text: str, max_len: 'int >0' = 80) -> str:
注解不会做任何处理,知识存储在函数的__annotations__
属性中
使用inspect.signature()
函数可以提取注解。
注解的最大作用是:为IDE和lint程序的静态检查功能提供额外的类型信息
itemgetter
返回一个根据索引提取元素的函数
from operator import itemgetter
class itemgetter:
"""
Return a callable object that fetches the given item(s) from its operand.
After f = itemgetter(2), the call f(r) returns r[2].
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])
"""
__slots__ = ('_items', '_call')
def __init__(self, item, *items):
if not items:
self._items = (item,)
def func(obj):
return obj[item]
self._call = func
else:
self._items = items = (item,) + items
def func(obj):
return tuple(obj[i] for i in items)
self._call = func
def __call__(self, obj):
return self._call(obj)
def __repr__(self):
return '%s.%s(%s)' % (self.__class__.__module__,
self.__class__.__name__,
', '.join(map(repr, self._items)))
def __reduce__(self):
return self.__class__, self._items
等价于
def itemgetter(*items):
if len(items) == 1:
item = items[0]
def g(obj):
return obj[item]
else:
def g(obj):
return tuple(obj[item] for item in items)
return g
实现取出对象中的一个元素的功能
from operator import itemgetter
a = [0, 1, 2, 3, 4]
x = itemgetter(1)
print(x(a)) # 1
x = itemgetter(1, 2)
print(x(a)) # (1, 2)
x = itemgetter(1, 2, 3)
print(x(a)) # (1, 2, 3)
使用lambda实现
x = lambda x: x[1]
print(x(a))
attrgetter
返回一个根据名称提取对象属性的函数
class attrgetter:
"""
Return a callable object that fetches the given attribute(s) from its operand.
After f = attrgetter('name'), the call f(r) returns r.name.
After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).
After h = attrgetter('name.first', 'name.last'), the call h(r) returns
(r.name.first, r.name.last).
"""
__slots__ = ('_attrs', '_call')
def __init__(self, attr, *attrs):
if not attrs:
if not isinstance(attr, str):
raise TypeError('attribute name must be a string')
self._attrs = (attr,)
names = attr.split('.')
def func(obj):
for name in names:
obj = getattr(obj, name)
return obj
self._call = func
else:
self._attrs = (attr,) + attrs
getters = tuple(map(attrgetter, self._attrs))
def func(obj):
return tuple(getter(obj) for getter in getters)
self._call = func
def __call__(self, obj):
return self._call(obj)
def __repr__(self):
return '%s.%s(%s)' % (self.__class__.__module__,
self.__class__.__qualname__,
', '.join(map(repr, self._attrs)))
def __reduce__(self):
return self.__class__, self._attrs
等价于
def attrgetter(*items):
if any(not isinstance(item, str) for item in items):
raise TypeError('attribute name must be a string')
if len(items) == 1:
attr = items[0]
def g(obj):
return resolve_attr(obj, attr)
else:
def g(obj):
return tuple(resolve_attr(obj, attr) for attr in items)
return g
def resolve_attr(obj, attr):
for name in attr.split("."):
obj = getattr(obj, name)
return obj
methodcaller
返回调用对象方法的一个函数
class methodcaller:
"""
Return a callable object that calls the given method on its operand.
After f = methodcaller('name'), the call f(r) returns r.name().
After g = methodcaller('name', 'date', foo=1), the call g(r) returns
r.name('date', foo=1).
"""
__slots__ = ('_name', '_args', '_kwargs')
def __init__(*args, **kwargs):
if len(args) < 2:
msg = "methodcaller needs at least one argument, the method name"
raise TypeError(msg)
self = args[0]
self._name = args[1]
if not isinstance(self._name, str):
raise TypeError('method name must be a string')
self._args = args[2:]
self._kwargs = kwargs
def __call__(self, obj):
return getattr(obj, self._name)(*self._args, **self._kwargs)
def __repr__(self):
args = [repr(self._name)]
args.extend(map(repr, self._args))
args.extend('%s=%r' % (k, v) for k, v in self._kwargs.items())
return '%s.%s(%s)' % (self.__class__.__module__,
self.__class__.__name__,
', '.join(args))
def __reduce__(self):
if not self._kwargs:
return self.__class__, (self._name,) + self._args
else:
from functools import partial
return partial(self.__class__, self._name, **self._kwargs), self._args
等价于
def methodcaller(name, /, *args, **kwargs):
def caller(obj):
return getattr(obj, name)(*args, **kwargs)
return caller
比如我要将字符串中的空格替换为-
s = 'Hello World'
change_s = methodcaller('replace', ' ', '-')
print(change_s(s)) # Hello-World
partial
冻结参数
from functools import partial
def add(a, b):
return a + b
add1 = partial(add, b=3)
print(add1(1))
print(add1(2))
一个计算a+b的函数,我们把它其中的一个入参固定为3,这样我们只需要传入一个参数就可以计算了
不指定冻结的形参的话,默认是冻结左侧的形参,该函数中的a