# 一等对象/一等函数
'''
1.在运行时创建
2.能赋值给变量或数据结构中的元素
3.能作为函数的参数传给函数
4.能作为函数的返回值返回结果
'''
# 函数对象本身时function对象的实例
def factorial(n):
'''return n!'''
return 1 if n < 2 else n*factorial(n-1)
"""
print(factorial(42))
print(factorial.__doc__) # 打印函数说明
print(type(factorial))
fact = factorial # 把函数赋值给变量
print(fact)
print(fact(5))
res = list(map(factorial,range(11)))
print(res)
"""
# 高阶函数 : 接受函数为参数,或者把函数作为返回的结果
# map,reduce,filter,sorted
# map,reduce,filter的现代替代者
# map和filter和列表推导式比较
"""
print(list(map(factorial,range(6))))
print([factorial(n) for n in range(6)])
print(list(map(factorial,filter(lambda n:n%2,range(6)))))
print([factorial(n) for n in range(6) if n%2])
"""
# 使用reduce和sum计算0-99的和
"""
from functools import reduce
from operator import add
print(reduce(add,range(100)))
print(sum(range(100)))
"""
# 其他内置归约函数 all any
"""
print(all([1,1,1,1]))
print(all([]))
print(any([1,0,0,0]))
print(any([]))
"""
# 使用lambda表达式反转拼写
"""
fruits = ['strawberry','fig','apple','cherry','raspberry','banana']
res = sorted(fruits,key=lambda word:word[::-1])
print(res)
"""
# 如果lambda表达式难以理解,重构的方法
# 编写注释,说明lambda表达式的作用
# 研究一会儿注释,并找出一个名称来概括注释
# 把lambda表达式转换成def语句,使用那个名称来定义函数
# 删除注释
# 可调用对象
"""
1.用户定义的函数
2.使用def或者lambda表达式创建
3.内置函数
4.使用C语言(cpython)实现的函数,如len或者time.strftime
5.内置方法
6.使用c语言实现的方法,如dict.get
7.方法
8.在类的定义中定义的函数
9.类
调用类的过程:
运行__new__创建一个实例
运行__init__初始化实例
把实例返回给调用方
10.类的实例
如果类定义了__call__方法,那么它的实例可以作为函数调用
11.生成器函数 使用yield关键字的函数或者方法,调用生成器函数返回的是生成器对象
判断是否可调用,可以实用内置函数callable()
"""
"""
print(abs)
print(str)
print([callable(n) for n in (abs,str,int,13.0)])
"""
# 用户定义的可调用类型
"""
import random
class BingoCage:
'''定义一个类,完成了__call__方法
让这个类的实例表现得像一个函数
这个类的实例由任何可迭代对象创建,
调用实例会取出一个元素'''
def __init__(self,items):
self._items = list(items)
random.shuffle(self._items)
def pick(self):
try:
return self._items.pop()
except IndexError:
raise LookupError('pick from empty BingoCage')
def __call__(self):
return self.pick()
if __name__ == '__main__':
bingo = BingoCage(range(3))
print(bingo.pick())
print(bingo())
print(callable(bingo))
"""
# 函数内省
# print(dir(factorial))
# __dict__ : 函数用来存储赋予它的用户属性
# 常规对象没有而函数有的属性
"""
class C:pass
c = C()
def func():pass
print(sorted(set(dir(func)) - set(dir(c))))
# ['__annotations__',:参数和返回值的注解
# '__call__', :实现()运算符,即可调用对象协议
# '__closure__', :函数闭包,即自由变量的绑定,通常为None
# '__code__',:编译成字节码的函数元数据和函数定义体
# '__defaults__',:形式参数的默认值
# '__get__', :实现只读描述符协议
# '__globals__', :函数所在模块中的全局变量
# '__kwdefaults__',: 仅限关键字形式参数的默认值
# '__name__',:函数名称
# '__qualname__':函数的限定名称,如random.choice]
"""
# 从定位参数到仅限关键字参数
# tag函数用于生成html标签,使用名为cls的关键字传入"class"属性,这是一种变通的方法,\
# 因为class是python的关键字
def tag(name,*content,cls = None,**attrs): # cls是一个仅限关键字参数
'''生成一个html标签'''
if cls is not None:
attrs['calss'] = cls
if attrs:
attr_str = ''.join(' %s="%s"'%(attr,value)
for attr,value in sorted(attrs.items()))
else:attr_str = ''
if content:
return '\n'.join('<%s %s>%s</%s>'%(name,attr_str,c,name) for c in content)
else:
return '<%s %s />'%(name,attr_str)
"""print(tag('br')) # 传入单个位置参数
print(tag('p', 'hello')) # 第一个参数后面的任意个参数会被*content捕获,存入一个元组
print(tag('p', 'hello','world'))
print(tag('p', 'hello',id = 33)) # 没有明确指定名称的参数会被**attrs捕获,存入一个字典
print(tag('p', 'hello','world',cls='sidebar')) # cls参数只能作为关键字参数传入
print(tag(content = 'testing',name='img')) # 第一个位置参数也能作为关键字参数传入
my_tag = {'name':'img','title':'Sunset Boulevard',
'src':'sunset.jpg','cls':'framed'}
print(tag(**my_tag)) # 拆包 同名的键会被绑定到具名的参数上,余下的则被**attrs捕获
"""
# 如果不想支持数量不定的位置参数,但是想支持仅限关键字参数,在签名中放一个*
"""def f(a,*,b): # b必须强制传入关键字参数
return a,b
print(f(1, b=2)) # (1,2)
# print(f(1, 2)) # 报错
print(f(1)) # 报错 必须传入b的关键字参数
"""
# 获取关于参数的信息
"""import bobo
@bobo.query('/')
def hello(person):
return 'hello %s!'%person
print(hello('丁小马'))
"""
# 在指定长度截取字符串的函数
"""def clip(text,max_len = 80):
'''在manx_len的前面或者跟后面的第一个空格处截断文本'''
end = None
if len(text) > max_len:
space_before = text.rfind(' ',0,max_len)
if space_before >= 0 :
end = space_before
else:
space_after = text.rfind(' ',max_len)
if space_after >= 0:
end = space_after
if end is None: # 没找到空格
end = len(text)
return text[:end].rstrip()
print(clip.__defaults__) # >>>(80,)
print(clip.__code__) # >>><code object clip at 0x00000281885292F0, file "E:\pythonProjects\pythonProject\读书笔记\流畅的Python\04第五章一等函数\__init__.py", line 205>
print(clip.__code__.co_varnames) # >>>('text', 'max_len', 'end', 'space_before', 'space_after')
print(clip.__code__.co_argcount) # >>>2
"""
# 提取函数的签名
"""from inspect import signature
sig = signature(clip)
print(sig)
for name,param in sig.parameters.items():
print(param.kind,':',name,'=',param.default)
# POSITIONAL_OR_KEYWORD : text = <class 'inspect._empty'> 表示没有默认值
# POSITIONAL_OR_KEYWORD : max_len = 80
# .kind属性的值
# POSITIONAL_OR_KEYWORD:可以通过位置参数和关键字参数传入的形参
# VAR_POSITIONAL : 定位参数元组
# VAR_KEYWORD : 关键字参数字典
# KEYWORD_ONLY : 仅限关键字参数
# POSITIONAL_ONLY : 仅限位置参数
"""
# 把tag函数的签名绑定到一个参数字典上
"""import inspect
sig = inspect.signature(tag) # 获取函数签名
my_tag = {'name':'img','title':'Sunset Boulevard',
'src':'sunset.jpg','cls':'framed'}
bound_args = sig.bind(**my_tag) # 将实参绑定给函数调用中的形参
print(bound_args)
for name,value in bound_args.arguments.items():
print(name,'=',value)
del my_tag['name']
bound_args = sig.bind(**my_tag) # 报错缺少了 name参数
"""
#函数注解
def clip(text:str,max_len:'int > 0' = 80)->str: # 有注解的函数声明
'''在manx_len的前面或者跟后面的第一个空格处截断文本'''
end = None
if len(text) > max_len:
space_before = text.rfind(' ',0,max_len)
if space_before >= 0 :
end = space_before
else:
space_after = text.rfind(' ',max_len)
if space_after >= 0:
end = space_after
if end is None: # 没找到空格
end = len(text)
return text[:end].rstrip()
print(clip.__annotations__) # 注解存放在这个属性里
#从函数签名中提取注解
from inspect import signature
sig = signature(clip)
print(sig.return_annotation)
for param in sig.parameters.values():
note = repr(param.annotation).ljust(13)
print(note,':',param.name,'=',param.default)
operator?和?functools模块介绍
# 计算阶乘
# operator包提供兼用运算符的函数形式
"""from functools import reduce
from operator import mul
def fact(n):
return reduce(mul,range(1,n+1))
print(fact(5))
# itemgetter(): 构建一个函数,返回序列的某个位置上的值
# itemgetter(1) 作用等同于 lambda fields:fields[1]
# 使用itemgetter排序一个元组列表
metro_data= [('Tokyo','JP',36.933,(35.689722,139.691667)),
('New Yory','US',20.104,(40.808611,-74.020386)),
('Delhi NCR','IN',21.935,(28.613889,77.208889)),
('Mexico City','MX',20.124,(19.43333,-99.113333)),
('Sao Paulo','BR',19.649,(-23.547778,-46.638533))]
from operator import itemgetter
for city in sorted(metro_data,key=itemgetter(1)):
print(city)
# 如果把多个参数传给itemsgetter,它构建的函数会返回提取的值构成的元组
cc_name = itemgetter(1,0)
for city in metro_data:
print(cc_name(city))
# attrgetter:创建的函数根据名称提取对象的属性
# 定义一个namedtuple,演示使用attrgetter处理它
from collections import namedtuple
LatLong = namedtuple('LatLong','lat long')
Metropolis = namedtuple('Metropolis','name cc pop coord')
metro_areas = [Metropolis(name,cc,pop,LatLong(lat,long))
for name,cc,pop,(lat,long) in metro_data]
print(metro_areas[0])
print(metro_areas[0].coord.lat)
from operator import attrgetter
name_lat = attrgetter('name','coord.lat')
for city in sorted(metro_areas,key=attrgetter('coord.lat')):
print(name_lat(city))
"""
"""import operator
# operator中的函数
print([name for name in dir(operator) if not name.startswith('_')])
#['abs', 'add', 'and_', 'attrgetter', 'concat', 'contains', 'countOf',
# 'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand',
# 'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul', 'index',
# 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift', 'is_', 'is_not',
# 'isub', 'itemgetter', 'itruediv', 'ixor', 'le', 'length_hint', 'lshift',
# 'lt', 'matmul', 'methodcaller', 'mod', 'mul', 'ne', 'neg', 'not_', 'or_',
# 'pos', 'pow', 'rshift', 'setitem', 'sub', 'truediv', 'truth', 'xor']
"""
# methodcaller
"""from operator import methodcaller
s = 'The time has come'
upcase = methodcaller('upper')
print(upcase(s))
hiphenate = methodcaller('replace',' ','_')
print(hiphenate(s))
"""
# 使用functools.partial冻结参数
# functools提供了一些列高阶函数
# functools.partial用于部分应用一个函数:
# 基于一个函数创建一个新的可调用对象,把原函数的某些参数固定
# 使用和这个函数可以把接受一个或者多个参数的函数改编成需要会回调的API,这样参数更少
# functools.partial的第一个参数是一个可调用对象,后面是任意个要绑定的位置参数和关键字参数
# 使用partial把一个两个参数的函数改编成需要单参数的可调用对象
from functools import partial
from operator import mul
triple = partial(mul,3) # 固定住做乘法的其中一个数为3
print(triple(7))
print(list(map(triple, range(1, 10))))
def tag(name,*content,cls = None,**attrs): # cls是一个仅限关键字参数
'''生成一个html标签'''
if cls is not None:
attrs['calss'] = cls
if attrs:
attr_str = ''.join(' %s="%s"'%(attr,value)
for attr,value in sorted(attrs.items()))
else:attr_str = ''
if content:
return '\n'.join('<%s %s>%s</%s>'%(name,attr_str,c,name) for c in content)
else:
return '<%s %s />'%(name,attr_str)
picture = partial(tag,'img',cls = 'pic-frame')
print(picture(src='wupus.jpeg'))
print(picture)
print(picture.func)
print(picture.args)
print(picture.keywords)
|