《流畅的Python》,优雅的python
在Python中,函数是一级对象:
创建一个元素,可以在运行时赋给变量或数据结构,可以作为参数传递给函数,可以是函数的返回结果。将函数视为object def factorial(n): #通过控制台会话在运行时创建函数。
. 返回n!
.如果n ^ 2否则返回1n *阶乘(n-1)
.
阶乘(42)
1405006117752879898543142606244511569936384000000000
阶乘。__doc__
返回n!
类型(阶乘)
类“function”是function类的一个例子。让我们来看看作业,调用:
事实=阶乘
事实
0x7f1c69958e18处的函数阶乘
事实(5)
120
map(阶乘,range(11))
0x7f1c62361908处的映射对象
列表(映射(事实,范围(11)))
【1,1,2,6,24,120,720,5040,40320,362880,3628800】对于一级函数,可以使用函数式风格编程。
高阶函数接受函数作为参数,或者返回函数作为结果的函数就是高阶函数。map函数是,sorted()函数也是:可选的key参数可用于提供一个函数,该函数可应用于每个元素进行排序。
根据单词长度对列表进行排序:
水果=[草莓,无花果,苹果,樱桃,覆盆子,香蕉]
已排序(水果,key=len)
[FIG , Apple , Cherry , Banana , Raspberry , Strawberry]根据反向拼写对单词列表进行排序:
定义反转(单词):
.返回单词[:-1]
.
反向(“测试”)
gnitset
已分类(水果,键=反向)
【香蕉,苹果,无花果,覆盆子,草莓,樱桃】香蕉的反向拼写以a开头,所以是第一个元素。
函数式语言是map、filter和reduce的替代品,通常提供三个高阶函数:map、filter和reduce。
求导和生成器表达式具有映射和过滤功能,更容易阅读。
计算阶乘列表:映射和过滤器与列表派生之间的比较
list(map(fact,range(6))) #0!敬5!的阶乘列表
[1, 1, 2, 6, 24, 120]
[范围(6)中n的fact(n)]#对列表派生做同样的事情。
[1, 1, 2, 6, 24, 120]
list(map(factorial,filter(lambda n: n % 2,range(6))))
[1,6,120]#奇数阶乘列表(1!3!5!)
[Factorial(n)for n in range(6)if n % 2]#使用列表派生而不是映射和筛选,同时避免lambda表达式。
[1,6,120]reduce在Python3中的functools模块中,常用于求和,但最好使用内置的sum函数:
从functools导入减少
从操作员导入添加
减少(增加,范围(100))
4950
总和(范围(100))
950为了使用高阶函数,有时创建一次性的小函数更方便。这就是匿名函数存在的原因。
匿名lambda关键字在Python表达式中创建匿名函数。
Python将lambda函数的定义限制在纯表达式、赋值、while和try等。
水果=[草莓,无花果,苹果,樱桃,覆盆子,香蕉]
已排序(水果,key=lambda word: word[:-1])
[香蕉,苹果,无花果,树莓,草莓,樱桃]可调用对象可以应用于除用户自定义函数之外的其他对象。调用运算符(即())也可以应用于其他对象。
callable()函数可以用来确定一个对象是否可以被调用。
abs,str,13
(内置函数abs,class str ,13)
[callable(obj) for obj in (abs,str,13)]
[True,True,False]用户定义的可调用类型任何Python对象只要实现了实例方法__call__,就可以表现得像函数一样。
例如,调用BingoCage实例从加扰列表中取出一个元素:
# -*-编码:utf-8 -*
随机导入
BingoCage类:
def __init__(self,items):
自我。_items=list(items) #接受任何可迭代对象并在本地构建副本
Random.shuffle(自我。_items) #心烦
定义选择(自己):
尝试:
回归自我。_items.pop()
exception error:#为空并引发异常。
引发LookupError(“从空BingoCage中选取”)
def __call__(self):
return self.pick()
if __name__==__main__ :
bingo=BingoCage(range(3))
print (bingo.pick()) #1
Print(bingo()) # print2可以像函数一样调用
Print(callable(bingo))#True这是将函数视为对象的另一个方面:运行时的自省。
函数自省除了__doc__,函数对象还有很多属性。使用dir函数找出答案
Factorial具有以下属性:
阶乘
[__annotations__ , __call__ , __class__ , __closure__ , __code__ ,
__defaults__ , __delattr__ , __dict__ , __dir__ , __doc__ , __eq__ ,
__format__ , __ge__ , __get__ , __getattribute__ , __globals__ ,
__gt__ , __hash__ , __init__ , __kwdefaults__ , __le__ , __lt__ ,
__module__ , __name__ , __ne__ , __new__ , __qualname__ , __reduce__ ,
__reduce_ex__ , __repr__ , __setattr__ , __sizeof__ , __str__ ,
__subclasshook__]这些属性大多数都是Python对象所共有的。本节讨论与将函数视为对象相关的问题。
的几个属性,从__dict__开始。
像用户定义的常规类一样,函数使用__dict__属性来存储分配给它的函数。
家居属性。这相当于一种基本形式的注释。
下面重点介绍函数独有的属性,这些属性不适用于一般用户定义的对象。计算两个属性集的差集,以获得特定于函数的属性列表:
C类:通过
obj=C()
def func():通过
sorted(set(dir(func))-set(dir(obj)))
[_ _ annotations _ _ , _ _ call _ _ , _ _ closure _ _ , _ _ code _ _ , _ _ defaults _ _ , _ _ get _ _ , _ _ globals _ _
类型
解释
__注释_ _
词典
以及对参数和返回值的注释。
__呼叫_ _
方法包装
实现()运算符;可调用对象协议
__关闭_ _
元组
函数闭包,即自由变量的绑定。
__代码_ _
密码
编译成字节码的函数元数据和函数定义体
__默认值_ _
元组
参数的默认值。
__get__
方法包装
实现只读描述符协议
__全局_ _
词典
函数所在模块中的全局变量
__kwdefaults__
词典
仅关键字表单参数的默认值。
__姓名_ _
潜艇用热中子反应堆(submarine thermal reactor的缩写)
函数名
__qualname__
潜艇用热中子反应堆(submarine thermal reactor的缩写)
函数的限定名,如Random.choice
从定位参数到只有关键字的参数,Python最好的特性之一是它提供了非常灵活的参数处理机制,而且Python
3进一步提供了一个只有关键字的参数。与之密切相关的
重要的是,在调用函数时,使用*和* *来“扩展”iterable对象,并将其映射到单个参数。
数数。
def标签(名称,*内容,cls=无,* *属性):
“”生成一个或多个HTML标记
:param name:定位参数(位置参数)
:param content:变量参数(允许传入任何(或0)个参数,并通过tuple存储)
:param cls: named keyword参数,需要一个*(或变量参数)作为分隔符,后跟named keyword参数,
必须传入参数名。
:param attrs:关键字参数,允许任何(或0个)带参数名的参数传入并由dict存储。
:返回:
如果cls不为None:
attrs[class]=cls
如果属性:
attr_str= 。join( %s=%s % (attr,value) for attr,value in sorted(attrs.items()))
否则:
attr_str=
如果内容:
返回“\n”。join( %s%s %s /%s %(name,attr_str,c,name) for c in content)
否则:
Return %s%s/%(name,attr_str)让我们解释一下这些参数:
名称:位置参数(positional parameter)*内容:变量参数(允许传入任意(或0)个参数,通过tuple存储)cls: only (named)关键字参数。命名关键字参数需要一个*(或变量参数)作为分隔符,这个分隔符后面的类似位置参数就是命名关键字参数。请注意,调用时必须传入参数名。Attrs:关键字参数,允许传入任意(或0)个带参数名的参数,并由dict存储。以下是调用的示例:
Tag(br) #将单个参数传递给定位参数名称,并生成一个具有指定名称的空标记
br /
Tag(p , hello) #第一个参数之后的任何参数都会被*content捕获并存储在tuple中。
p你好/p
Tag(p , hello , world) #第一个参数之后的任何参数都会被*content捕获并存储在tuple中。
p你好/p \n p世界/p
标签( p , hello ,id=33) #标签函数签名中没有指定名称的关键字将被**attrs捕获并存储在字典中(此处为id)
p id=33 你好/p
Tag (P , Hello , World ,CLS= Sidebar) # CLS参数只能作为关键字参数传入,且必须传入参数名,否则无法与position参数区分。
p你好/p \n p世界/p
标签(内容=测试,名称=img )
img内容=测试/
my_tag={name: img , title :日落大道, src: sunset.jpg , cls: framed}
Print(tag(**my_tag)) #my_tag前面是* *。字典中的所有元素都作为单个参数传入,同名的键绑定到相应的命名参数,其余的由**attrs捕获。
img= sunset . jpg title= sunset boulevard /定义函数时,如果要指定仅关键字的参数,应该将它们放在前面带*的参数之后。如果你不想支持无限数量的定位参数,但只想支持关键字参数,在签名
按如下方式填写a *:
def f(a,*,b):
.返回a,b
.
f(1,b=2)
(1, 2)
F(1,2) #参数名B必须公式化
回溯(最近一次呼叫):
模块中文件 stdin 的第1行
类型错误:f()接受1个位置参数,但接受2个有关参数的信息。HTTP微框架Bobo中有一个很好的使用函数自省的例子。例子就是波波。
教程中“Hello world”应用程序的改编说明了如何使用内省。
进口bobo
@bobo.query(/)
def hello(人):
返回“你好%s!”%Bobo检查hello函数,发现它需要一个名为
参数,然后从请求中获取与该名称对应的参数,并将其传递给
Hello函数,所以程序员根本不用接触被请求的对象。
使用以下命令启动程序:
波波-f波波_演示. py
在8080端口上提供[bobo__main__].
通过Postman访问http://localhost:8080,可以看到状态码是403,并且有一个person变量丢失的消息。
让我们亲自尝试一下:
Bobo怎么知道一个函数需要哪个参数?它如何知道参数没有默认值?
该函数有一个__defaults__属性,它的值是一个元组,它包含
定位参数和关键字参数的默认值。关键字参数的默认值仅在中
__kwdefaults__属性。但是,参数的名称在__code__属性中,
它的值是一个代码对象引用,它有许多属性。
定义剪辑(text,max_len=80):
在max_len之前或之后的第一个空格处截断文本
end=无
if len(text) max_len:
space_before=text.rfind(,0,max_len)
如果space_before=0:
end=space_before
否则:
space_after=text.rfind(,max_len)
如果space_after=0:
end=空格_后
如果end为None:
end=len(文本)
返回文本[:end]。rstrip()
打印(剪辑。__defaults__) #(80,)
打印(剪辑。_ _ code _ _)#0x 000001 f 1807759 c 0处的代码对象剪辑,文件“D:/workspace/python/fluent python/first _ class _ function/clip . py”,第3行
打印(剪辑。__代码_ _。co_varnames) #(text , max_len , end , space_before , space_after )
打印(剪辑。_ _代码_ _。co _ argcount) # 2可见这种组织信息的方式并不是最方便的。参数名称在
__代码_ _。co_varnames,但是还有在函数定义体中创建的office。
部分变量。因此,参数名是前n个字符串,n的值由下式确定
__代码_ _。co_argcount当然。
幸运的是,我们有一个更好的方法来使用——中的inspect模块。
sig=签名(剪辑)
print(sig) #(text,max_len=80)
对于名称,sig.parameters.items()中的参数:
print(param.kind,:,name,=,param.default)
# POSITIONAL _ OR _ KEYWORD:text=class inspect。_empty
# positive _ or _ keyword:max _ len=80 inspect。签名对象有一个绑定方法,可以绑定任何参数。
用于确定签名中参数的规则与用于匹配参数的规则相同。结构
您可以使用此方法在实际调用函数之前验证参数,如示例所示。
进口检验
Sig=inspect.signature(tag) #tag函数已经在上面定义了。
my_tag={name: img , title :日落大道, src: sunset.jpg , cls: framed}
bound_args=sig.bind(**my_tag)
Bound_args # Get BoundArguments对象
Boulevard参数(name=img ,cls=framed ,attrs={ title : Sunset Boulevard , src: sunset.jpg})
对于名称,bound_args.arguments.items()中的值:# iterative bound _ args.arguments
.打印(名称,=,值)
.
name=img
cls=框架
attrs={title :日落大道, src: sunset.jpg}
Del _ tag [name] #删除必须从my_tag中指定的参数名
Bound_args=sig.bind(**my_tag) #调用错误
回溯(最近一次呼叫):
模块中文件 stdin 的第1行
文件“/usr/lib/python 3.6/lib/python 3.6/inspect . py”,第2933行,在bind中
返回参数[0]。_bind(args[1:],kwargs)
文件“/usr/lib/python 3.6/lib/python 3.6/inspect . py”,第2848行,in _bind
从None引发TypeError(msg)
类型错误:缺少必需的参数:“name”框架和IDE可以使用这些信息来验证代码。Python 3的另一个特性
3354函数注释3354增强了该信息的使用。
注Python 3提供了在函数声明中将元数据附加到参数和返回值的语法。
以下是带注释的剪辑函数:
DEF CLIP (text: str,max _ len: int0=80)-str: #带注释的函数声明
在max_len之前或之后的第一个空格处截断文本
end=无
if len(text) max_len:
space_before=text.rfind(,0,max_len)
如果space_before=0:
end=space_before
否则:
space_after=text.rfind(,max_len)
如果space_after=0:
end=空格_后
如果end为None:
end=len(文本)
返回文本[:end]。rstrip()批注不会被处理,但会存储在函数的__annotations__属性(一个字典)中:
打印(剪辑。__批注_ _)
{text: class str , max _ len: int0 , return :class str } Python对注释做的唯一事情就是将它们存储在函数的
__annotations__属性。仅此而已。Python不检查,不强制,
没有验证什么都不做。
将来,像Bobo这样的框架可以自动支持注释和进一步处理请求。举个例子,
用price:float注释的参数可以自动将查询字符串转换成函数期望。
的浮点类型;Quantity:可以转换类似“int0”的字符串注释。
成对参数的验证。
支持函数式编程的包运算符模块,在函数式编程中经常需要使用算术运算符作为函数。例如,不要使用
递归阶乘计算。可以使用Sum函数,但是quadrature没有这样的函数。
数数。我们可以使用reduce函数,但是我们需要一个函数来计算序列中的2。
元素的乘积。这个例子展示了如何使用lambda表达式来解决这个问题。
从functools导入减少
定义事实(n):
.return reduce (lambda a,b: a * b,range (1,n-1))运算符模块为多个算术运算符提供了相应的函数,从而避免了编写。
Lambda a,b: a*b,一个普通的匿名函数。
从functools导入减少
从操作员导入mul
定义事实(n):
Return Reduce (Mul,Range (1,n-1))运算符模块中也有一类函数,可以代替从序列中取出元素或读取对象。
属性的lambda表达式:因此,itemgetter和attrgetter实际上
自我建构功能
metro_data=[
.(东京, JP ,36.933,(35.689722,139.691667)),
.(“德里NCR”,“在”,21.935,(28.613889,77.208889)),
.(墨西哥城, MX ,20.142,(19.433333,-99.133333)),
.(纽约-纽瓦克,美国,20.104,(40.808611,-74.020386)),
.(圣保罗, BR ,19.649,-23.547778,-46.635833),
.]
从运算符导入itemgetter
对于已排序的城市(metro_data,key=itemgetter(1)): #
.打印(城市)
.
(圣保罗, BR ,19.649,(-23.547778,-46.635833))
(“德里NCR”,“在”,21.935,(28.613889,77.208889))
(东京, JP ,36.933,(35.689722,139.691667))
(墨西哥城, MX ,20.142,(19.433333,-99.133333))
( New York-Newark , US ,20.104,(40.808611,-74.020386))其实itemgetter(1)的函数和lambda fields: fields[1]:创建一个接受集合并返回索引位1的元素的函数。
如果将多个参数传递给itemgetter,它构建的函数将返回提取的值结构。
分成元组:
cc_name=itemgetter(1,0)
对于metro_data中的城市:
.打印(抄送姓名(城市))
.
(“JP”,“东京”)
(“在”,“德里NCR”)
(“MX”,“墨西哥城”)
(“美国”、“纽约-纽瓦克”)
( BR ,圣保罗)attrgetter和itemgetter的相似之处在于,它创建的函数是根据其名称提取的。
对象的属性。如果将多个属性名传递给attrgetter,它也会返回fetch。
一组值。此外,如果参数名包含。(点),attrgetter
将深度嵌套对象并获得指定的属性。
从集合导入命名元组
LatLong=namedtuple (latlong , latlong) #使用namedtuple定义LatLong
Metropolis=named tuple( Metropolis , name cc pop coord )
metro_areas=[Metropolis(name,cc,pop,LatLong(lat,Long))
.对于metro_data中的名称、抄送、弹出、(纬度、经度)
metro_areas[0]
Metropolis(name=Tokyo ,cc=JP ,pop=36.933,coord=LatLong(lat=35.689722,long=139.691667))
Metro_areas[0].coord.lat#以获取其纬度
35.689722
从操作员导入attrgetter
Name _ lat=attrgetter (Name , coord.lat) #获取name属性和嵌套的coord.lat属性
对于已排序的城市(metro _ areas,key=attrgetter( coord . lat ):#使用attr getter并按纬度排序。
.打印(姓名(城市))
.
(“圣保罗”,-23.547778)
(“墨西哥城”,19.433333)
(“德里NCR”,28.613889)
(“东京”,35.689722)
(‘纽约-纽瓦克’,40.808611)使用Metropolis实例建立metro_areas列表;注意,我们使用
解包并提取嵌套元组(lat,long),然后用它们构建LatLong,
作为大都会的协调财产。
在操作员模块的剩余功能中,介绍最后一个。
它的功能类似于attrgetter和itemgetter,它
会创建自己的函数。methodcaller创建的函数将调用对象上的参数。
设置方法:
从运算符导入方法调用方
“时候到了”
Upcase=methodcaller(upper) #要调用str.upper方法
大写字母
时候到了
hiphenate=method caller( replace , ,-)
hiphenate
“时间已到来”使用functools.partial冻结参数functools.partial。此高阶函数用于部分应用函数。部分响应
使用是指基于一个函数创建一个新的可调用对象,并改变原函数的一些参数。
修好了。使用此函数修改接受一个或多个参数的函数以进行回调。
API,这样参数就少了。
从操作员导入mul
从functools导入部分
Triple=partial(mul,3) # Fix参数3,所以只需要传递一个参数。
三重(7)
21
列表(map(triple,range(1,10)))
[3,6,9,12,15,18,21,24,27]用上一篇文章介绍的unicode.normalize函数再举一个例子。这个例子
比较实用。如果您正在处理用多种语言编写的文本,在比较或排序之前,您可以
希望使用unicode.normalize(NFC ,s)来处理所有字符串。例如
如果您经常这样做,您可以定义一个nfc函数:
导入unicodedata,functools
nfc=func tools . partial(unicode data . normalize, NFC )
s1=“咖啡馆”
s2=cafe\u0301
s1、s2
(咖啡馆,咖啡馆)
s1==s2
错误的
nfc(s1)==nfc(s2)
True partial的第一个参数是一个可调用对象,后面是任何要绑定的对象。
定位参数和关键字参数。这个功能其实很有用。
原创作品来自愤怒的可乐,的博主,转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。