python 函数返回列表里为什么函数可以返回一个函数内部定义的函数

python内建函数总结
abs()函数返回数字(可为普通型、长整型或浮点型)的绝对值。如果给出复数,返回值就是该复数的模。例如:
>>>print abs(-2,4)
>>>print abs(4+2j)
2. apply(function,args[,keywords])
apply()函数将args参数应用到function上。function参数必须是可调用对象(函数、方法或其他可调用对象)。args参数必须以序列形式给出。列表在应用之前被转换为元组。function对象在被调用时,将args列表的内容分别作为独立的参数看待。例如:
apply(add,(1,3,4))
add(1,3,4)
在以列表或元组定义了一列参数,且需要将此列表参数分别作为个个独立参数使用的情况下,必须使用apply()函数。在要把变长参数列应用到已函数上时,apply()函数非常有用。
可选项keywords参数应是个字典,字典的关键字是字符串。这些字符串在apply()函数的参数列末尾处给出,它们将被用作关键字参数。
3. buffer(object[,offset[,size]])
如果object对象支持缓存调用接口buffer()函数就为object对象创建一个新缓存。这样的对象包括字符串、数组和缓存。该新缓存通过使用从offset参数值开始知道该对象末尾的存储片段或从offset参数值开始直到size参数给出的尺寸为长度的存储片段来引用object对象。如果没给出任何选项参数,缓存区域就覆盖整个序列,最终得到的缓存对象是object对象数据的只读拷贝。
缓存对象用于给某个对象类型创建一个更友好的接口。比如,字符串对象类型通用缓存对象而变得可用,允许逐个字节地访问字符串中的信息。
4. callable(object)
callable()函数在object对象是可调用对象的情况下,返回真(true);否则假(false),可调用对象包括函数、方法、代码对象、类(在调用时返回新的实例)和已经定义‘调用’方法的类实例
chr()函数返回与ASCII码i相匹配的一个单一字符串,如下例所示:
>>>print chr(72)+chr(101)+chr(108)+chr(111)
chr()函数是ord()函数的反函数,其中ord()函数将字符串转换回ASCII整数码,参数i的取值应在0~255范围内。如果参数i的取值在此范围之外,将引发ValueError异常。
6. cmp(x,y)
cmp()函数比较x和y这两个对象,且根据比较结果返回一个整数。如果xy,则返回正数。请注意,此函数特别用来比较数值大小,而不是任何引用关系,因而有下面的结果:
>>>b=int('99')
>>>cmp(a,b)
7. coerce(x,y)
coerce()函数返回一个元组,该元组由两个数值型参数组成。此函数将两个数值型参数转换为同一类型数字,其转换规则与算术转换规则一样。一下是两个例子:
>>>coerce(a,b)
>>>a=1+2j
>>>b=4.3e10
>>>coerce(a,b)
((1+2j),(+0j))
8 compile(string,filename,kind)
compile()函数将string编译为代码对象,编译生成的代码对象接下来被exec语句执行,接着能利用eval()函数对其进行求值。filename参数应是代码从其中读出的文件名。如果内部生成文件名,filename参数值应是相应的标识符。kind参数指定string参数中所含代码的类别,有关kind可能取值的详细信息,请参见表8-1
举例如下:
>>>a=compile(‘print “Hello World”’,’’,’single’)
>>>exec(a)
Hello World
>>>eval(a)
Hello World
由compile()函数编译的代码的类别
Kind取值 编译生成的代码
exec 语句序列
eval 简单表达式
Single 简单交互语句
9. complex(real,[image])
Complex()函数返回一个复数,其实部为real参数值。如果给出image参数的值,则虚部就为image;如果默认image参数,则虚部为0j。
10. delattr(object,name)
delattr()函数在object对象许可时,删除object对象的name属性,此函数等价于如下语句:
del object.attr
而delattr()函数允许利用方法定义来定义object和name参数,并不是在代码中显示指定。
11. dir([object])
当没有提供参数时,dir()函数列出在当前局部符号表中保存的名字,如下例所示:
>>>import sys
>>>dir(sys)
12. divmod(a,b)
devmod()函数返回一个元组,该元组包含a除以b的商和余数,如下例所示:
>>>divmod(7,4)
对整数而言,返回&#20540;与a/b和a%b相同。如果给出的参数&#20540;是浮点数,则结果就是(q,a%b),其中:q通常是math.floor(a/b),但是也可能比这小1,不管在什么情况下,q*b&#43;a%b都非常&#36924;近a;如果a%b是个非零&#20540;,则其正负号与b相同,并且有0<=abs(a%b)<abs(b)成立。下面的例子显示了divmod()函数是如何处理浮点数的:
>>>divmod(3.75,1.125)
(3.0,0.375)
>>>divmod(4.99,1.001)
(4.0,0.00065)
>>>divmod(-3.5,1.1)
(-4.0,0.00036)
13. eval(expression[,global[,locals]])
eval()函数将expression字符串作为python标准表达式进行分析并求&#20540;,返回expression字符串的&#20540;,当不可调用其他可选参数时,expression访问调用该函数的程序段的全局和局部对象。另一个选择是:以字典形式给出全局和局部符号表(参见后面部分对global()和local()函数的论述)。
Eval()函数的返回&#20540;是被求职表达式的&#20540;,如下例所示:
>>>eval(‘divmod(a,7)’)
任何求职操作的语法错误,都将引发成异常
eval()函数还能用来编译诸如由complie()函数创建的代码对象,但仅当该代码对象用“eval”模式编译过后才可用eval()函数编译。
要执行混合了语句和表达式的python任意代码,请使用exec语句或使用execfile()函数来动态地执行含有任意代码的文件。
14.execfile(file[,globals[,locals]])
execfile()函数与exec语句等价,不同之处在于:execfile()函数执行文件中的语句,而exec语句处理字符串。其中globals和locals参数应是字典,该字典包含文件在执行期间有效的符号表;如果locals参数省略,则所有的引用都使用globals名称空间。如果两个可选参数都省略,文件就访问运行期间的当前符号表。
15.filter(function,list)
filter()函数根据function参数返回的结果是否为真(true)来过滤list参数中的项,最后返回一个新列表,如下例所示:
a=[1,2,3, 4, 5,6,,7,8,9]
b=filter(lambda x:x>6,a)
如果function参数&#20540;为None,就是用identity函数,list参数中的所有为假(false)的元素都被删除。
16. flaot(x)
float()函数将x参数转换为浮点数,其中:x可以是字符串,也可以是数字。
17. getattr(object,name[,default])
getattr()函数返回object的name属性&#20540;。在语法上,以下语句:
getattr(x,’myvalue’)
如果name参数不存在,但给出defalut参数的&#20540;,则此函数就返回default参数&#20540;;否则引发AttributeError异常
18. globals()
globals()函数返回一个表示当前全局符号表的字典。这个字典通常就是当前模块的字典。如果globals()函数是在一函数或方法中被调用,它就返回定义该函数或方法的模块的符号表,而不是调用此函数的模块的符号表。
19. hasattr(object,name)
如果object对象具有与name字符串相匹配的属性,hasattr()函数返回真(true);否则返回0。
20. hash(object)
hash()函数返回关于object对象的整数散列&#20540;。如任何两个对象比较起来是等价的,则它们的散列&#20540;是一样的。此函数不应用于可便对向上。
21.hex(x)
hex()函数将一整数转换为十六进制字符串,该字符串是个有效的python表达式、
22. id(object)
id()函数返回&#20540;为一个整数(或长整型整数)――该对象的“标识“――该标识在其对应对象的生命期内,确保是唯一的和恒定不变的。
23. input([prompt])
input()函数与eval(raw_input(prompt))等价。
24. int(x,[radix])
int()函数将使数字或字符串x转换为“普通”整数。如果给出radix参数的&#20540;,则radix参数&#20540;用作转换的基数,该参数应是2~36范围内的一个整数。
25. intern(string)
intern()函数将string加入到保留字符串的表,返回&#20540;为保留的版本号。“保留字符串”通过指针可用,而不是一个纯的字符串;因此允许利用指针比较代替字符串比较来进行字典关键字的查找,这比通常的字符串比较方法功能有所改善。
在python名称空间表和用于保留模块、类或实力属性的字典中使用的名字通常被保留用以加速脚本执行。
保留字符串定义后不能被作为无用单元收集,所以必须注意在大字典关键字集上使用保留字符串将大大增加内存需求,即使字典关键字应急超出了作用域。
26. isinstance(object,class)
isinstance()函数在object参数是class参数的一个实例时,返回真。函数&#20540;的确定服从普通继承法则和子类。如果object参数是在types模块中利用类型类定义的特殊类型的实例,也能用isinstance()函数来识别。如果class参数不是类,也不是类型对象,就引发TypeError异常
27.issubclass(class1,class2)
如果class1参数是class2参数的子类,issubclass()函数则返回真。类通常被认为是其自身的子类。若两个参数中任一个都不是类对象,则引发TypeError异常
28. len(s)
len()函数返回一序列(字符串、元组或列表)或字典对象的长度
29. list(sequence)
list()函数返回以列表。该列表的项及顺序与sequence参数的项及顺序相同,如下例所示:
>>>list(‘abc’)
[‘a’,’b’,’c’]
>>>list([1,2,3])
30. locals()
locals()函数返回表示当前局部符号表的字典
31. long(x)
long()函数将字符串或数字转换为长整型数,对浮点数的转换遵循与int()相同的规则
32. map(function,list,…)
map()函数将function运用到list中的每一项上,并返回新的列表,如下例所示:
>>>a=[1,2,3,4]
>>>map(lambda x:pow(x,2),a)
[1,4,9,16]
若提供附加的列表,则它们就被并行地提供给function。在后续无元素的列表增加None,直到所有参数列表达到相同的长度为止。
如果function参数&#20540;为None,则假定为identify函数,将使map()函数返回删除所有为假的参数的list。如果function参数&#20540;为None,且给定多个列表参数,返回的列表由一个个元组组成,这些元组由函数中的每一个参数列表内相同对应位置上的参数组成,如下例所示:
>>>map(None,[1,2,3,4],[4,5,6,7])
[(1,4),(2,5),(3,6),(4,7)]
上例的结果与zip()函数产生的结果等价
33. max(s,[,args…])
当仅给定一个参数时,max()函数返回序列s的最大&#20540;。当给定一列参数时,max()函数返回给定参数的最大参数
34. min(s[,args…])
当仅给定一个参数时,min()函数返回序列s的最小&#20540;。当给定一列参数时,min()函数返回给定参数中的最小&#20540;。记住:多参数调用的序列不被遍历,每个列表参数作为一个整体进行比较,如:
min([1,2,3],[4,5,6])
而不是通常所想的结果为1,要得到一个或多个列表中元素的最小&#20540;,可将所有列表连成一串,如下所示:
min([1,2,3]&#43;[4,5,6])
35. oct(x)
该函数将整数转换为八进制字符串。其结果是个有效的python表达式,如下例所示:
>>>oct(2001)
请注意,返回&#20540;通常是无符号数。这样致使oct(-1)在32位机器上产生’’的结果
36. open(filename[,mode[,bufsize]])
open()函数通过使用mode和缓存bufsize类型来打开filename标识的文件。此函数返一文件对象
其中mode与函数fopen()使用的模式相同。如果mode参数省略,其默认取&#20540;为r
r 打开用于读
w 打开用于写
a 打开用于附加(打开期间,文件位置自动移到文件末尾)
r&#43; 打开用于更新(读和写)
w&#43; 截断(或清空)文件,接着打开文件用于读写
a&#43; 打开文件用于读和写,并自动改变当前为止到文件尾
当附加任何模式选项时,以二进制模式而不是文本模式,打开文件(这种模式
b 仅对、和其他一些操作系统有效,对Unix、MacOS和BeOS则不管选项为何&#20540;,以二进制模式对待所有文件)
open()函数的bufsize选项参数决定从文件中读取数据时所使用的缓存的大小,如果bufsize省略,就使用系统默认的缓存容量
bufsize&#20540;
>1 使用大小近&#20284;为bufsize字符长度的缓存
<0 使用系统默认
37.ord(c)
该函数返回由一个字符c组成的字符串的ASCII码&#20540;或Unicode数字码。ord()函数是chr()函数和nuichr()函数的反函数
38.pow(x,y[,z])
该函数返回以x为底数以y为指数的幂&#20540;。如果给出z,该函数就计算x的y次幂&#20540;被z取模的&#20540;,这样的计算比利用:
pow(x,y)%z
的效率更高
提供给pow()函数的参数应是数&#20540;型,并且给定的类型决定返回&#20540;的类型。如果计算得出的数&#20540;不能用给定参数&#20540;的类型表示,则引发异常,比如,以下对pow()的调用将失败:
pow(2.0,-1)
39. range([start,]stop[,step])
该函数返回数&#20540;列表,该数&#20540;列表从start开始,以step为步长,于stop之前结束。所有的数字都应列出,并且以普通整型数返回。如果step省略,则默认取1.如果start省略,则从0开始求&#20540;。如果以两个参数形式调用,则认作给定的参数是start和stop,如果要定义步长就必须给出全部的三个参数。下面对range()函数的调用使用了&#20540;为正数的步长step:
>>>range(5,25,5)
[5,10,15,20]
请注意,最后的数&#20540;是stop减去step,range()函数的返回&#20540;从小递增到大,趋近stop的&#20540;,但不包含stop这个&#20540;
如果step的给定&#20540;是负数,range()函数的返回&#20540;从大递增到小,而不是递增,stop必须比stop小;否则返回的列表为空。下列说明了step取&#20540;为负数的运用情况:
>>>range(10,0,-1)
[10,9,8,7,6,5,4,3,2,1]
>>>range(25,0,-5)
[25,20,15,10,5]
>>>range(0,10,-1)
40. raw_input([prompt])
该函数从sys.stdin接受原始输入并返回字符串。输入以换行符为结束,其中换行符在输入字符串返回给调用者之前被去除。如果给出prompt,末尾不含换行符的prompt就被写到sys.stdout中,并用作输入的提示,如下例所示:
>>>name=raw_input(‘Name?’)
Name?Martin
如果已加载readline模块,则诸如行编辑和历史记录的特性在输入期间就得到支持
41. reduce(function,sequence[,initializer])
该函数一次应用function(支持两个函数)到sequence中的每个元素上,逐渐缩短整个语句直到为一个单一的&#20540;。举例,下面的语句模拟了算术运算符“!”:
reduce(lambda x,y:x*y,[1,2,3,4,5])
其结果如同执行以下计算一样:
((((1*2)*3)*4)*5)
结果等于120
如果给出initializer参数&#20540;,则initializer参数&#20540;就被用作序列的第一个元素,如下列所示:
>>>reduce(lambda x,y:x*y,[1,2,3,4,5],10)
42. reload(module)
reload()函数将以前导入过的模块再加载一次。重新加载(reload)包括最初导入模块是应用的分析过程和初始化过程。这样就允许在不退出解释器的情况重新加载已更改的python模块。
使用reload()函数的若干注意事项如下:
*如果模块在语法上是正确的,但在初始化过程中失败,则导入过程不能正确地将模块的名字绑定到符号表中,这时,必须在模块能被重新加载之前使用import()函数加载该模块。
*重新加载的模块不删除最初旧版本在符号表中的登记项。对于有恒定名字的对象和函数,这当然不是问题;但是,若对一模块实体更改了名字,模块名在重新加载后仍保持在符号表中
*支持扩展模块(它依赖与内置的或所支持的动态加载的函数库)的重新加载,但可能是无目标的,并且确定可能导致失败,这完全依赖于动态加载的函数库的行为
*如果以模块利用from…import…方式从另一个模块导入对象,reload()函数不重定义导入的对象,可利用import…形式避免这个问题
*提供类的重新加载模块不影响所提供类的任何已存实例――已存实例将继续使用原来的方法定义;只有该类的新实例使用新&#26684;式。这个原则对派生类同样适用
43. repr(object)
repr()函数返回对象的字符串表示。这与将对象或属性适用单反引号(‘)的结果是一致的。返回的字符串产生一个对象,该对象的&#20540;与将object传递给eval()函数产生的&#20540;一样,如下例所示:
>>>dict={‘One’:1,’Two:2’,’Many’:{‘Many’:4,’ManyMany’:8}}
>>>repr(dict)
“{‘One’:1,’Many’:{‘Many’:4,’ManyMany’:8},’Two’:2}”
44. round(x[,n])
round()函数返回浮点型参数x舍入到十进制小数点后n位的&#20540;,如下例所示:
>>>round(0.4)
>>>round(0.5)
>>>round(-0.5)
>>>round(1985,-2)
45. setattr(object,name,value)
该函数将object参数的name属性设置为value参数&#20540;。setattr()函数是getattr()函数的反函数,后者仅获得信息,以下语句:
setattr(myattr’,’new value’)
myobj.myattr=’new value’
setattr()函数能用在这样的情况下:属性是通过name参数以编程方式命名,而不是显式地命名属性
46. slice([start,]stop,[,step])
该函数返回已序列切片(slice)对象,该对象表示由range(start,stop,step)指定的索引集。如果给出一个参数,此参数就作为stop参数&#20540;;如果给出两个参数,它们就作为start和stop的参数&#20540;;任何未给出参数&#20540;的参数默认取&#20540;为None。序列切片对象有3个属性(start,stop,和step),这3个属性仅仅返回要提供给slice()函数的参数
47. str(object)
返回对象的一个字符串表示。这与repr()函数相&#20284;,唯一不同之处在于:此函数返回&#20540;设计为可打印字符串而不是与eval()函数相兼容的字符串
48. tuple(object)
tuple()函数返回一个元组,该元组的项及项的顺序与sequence参数完全一样,以下就是tuple()函数的举例:
>>>tuple(‘abc’)
(‘a’,’b’,’c’)
>>>tuple([1,2,3])
49. type(object)
该函数返回object参数的类型。返回&#20540;是个如类型模块所描述一样的类型对象,举例如下:
>>>import type
>>>if type(string)==type.StringType:
print ‘This is a string’
50. unichr(i)
该函数返回代码是一个整型参数i的Unicode字符的Unicode字符串。此函数等价于前面论述的chr()函数。请注意,要将Unicode字符转换回其整数&#26684;式,可使用ord()函数;没有uniord()函数、如果给出的整数超出0~65535这个范围,则引发ValueError异常
51. unicode(string[,encoding[,errors]]))
该函数利用编码&#26684;式解码器将给定的字符串从一种&#26684;式解码为另一种&#26684;式。编码的任何错误都用errors参数定义的字符串标记
此函数特别用于在字符串和Unicode编码&#26684;式之间转换。默认(当不给出encoding参数&#20540;)操作是以严&#26684;方式将字符串解码为UTF-8&#26684;式,发生errors错误时就引发ValueError异常。有关合适的解码列表,请见codecs模块
52.vars([object])
该函数返回对应于当前局部符号表的字典。当给出模块、类或实例时,vars()函数返回对应那个对象的符号表的字典。因为结果是非定义的,所以一定不要修改返回的字典
53. xrange([start,]stop[,step])
该函数的作用与range()函数一样,唯一的区别是:xrange()函数返回一个xrange对象。xrange()对象是个不透明对象类型,此类型返回的信息与所请求的参数列表是一致的,但是它不必存储列表中每个独立的元素。在创建非常巨大列表的情况下,此函数特别有用;利用xrange()函数节省下来的内存比起用range()函数是相当可观的
54. zip(seq1,…)
zip()函数处理一系列序列,将这些序列返回一个元组列表。其中,每个元组包含了给定的每个序列的第n个元素。以下是个例子:
>>>a=[1,2,3,4]
>>>b=[5,6,7,8]
>>>zip(a,b)
[(1,5),(2,6),(3,7),(4,8)]
55. 执行任意语句
python支持3条指令,这3条指令允许执行一些任意文件或python代码的字符串,这3条指令是exec语句、execfile()和eval()函数。
56. exec语句
exec语句被设计为执行能使用函数和语句的任意组合的python的任何代码片段。执行的代码访问相同的全局定义和局部定义的对象、类和方法或函数。以下是使用exec语句的简单例子:
exec “print ‘Hello World’”
也能通过提供一个包含对象及其取&#20540;的列表的字典来限定对exec语句有效的资源,如下例这样:
exec “print message” in myglobals,mylocals
能用globals()和locals()函数来获得当前的字典
请注意,exec语句执行表达式和语句、或者对表达式和语句求&#20540;,但是exec语句不返回任何&#20540;。因为exec是语句不是函数,所以任何获取返回&#20540;的试图都将导致语法错误
57. execfile()函数
该函数执行与exec语句同样的操作,正如前面所描述的那样,它们的不同之处在于:execfile()函数从问几十年中读取被执行的语句,执行的对象不是字符串,不是代码对象;execfile()函数的其他所有方面都与exec语句等价
58. eval()函数
该函数不允许执行任意的python语句。eval()函数被设计为:执行一个python表达式,并返回&#20540;,如下例中一样:
result=eval(userexpression)
或者在语句中更显式地给出表达式,如下例所示:
result=eval(“3&#43;6”)
不能使用eval()函数去执行语句,根据经验,通常使用eval()函数开将一表达式求&#20540;并返回一个&#20540;,而在其他所有情况下则使用exec语句
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'python,定义一个函数A,函数B有一个变量,函数调用时怎么在函数A里获取变量的值。可以用数据库是什么的
python,定义一个函数A,函数B有一个变量,函数调用时怎么在函数A里获取变量的值。可以用数据库是什么的
python,定义一个函数A,函数B有一个变量,函数调用时怎么在函数A里获取变量的值。可以用数据库是什么的
被浏览84次
两个函数的参数不一样
采纳率:57%
可以把变量设置为:
def fun1():
global var1
def fun2():
global var1 分享到:
等您帮助的附近的朋友换一换1分钟前6分钟前7分钟前14分钟前14分钟前
发表评论:
TA的最新馆藏Python pow() 函数
当前位置:
>> Python pow() 函数
Python pow() 函数
Python pow() 函数
import math
math.pow( x, y )
注:此功能是不能直接访问的,所以我们需要导入的数学模块,然后我们需要调用这个函数,用数学的静态对象。
下面是详细参数:
X:这是一个数值表达式。
Y:这也是一个数值表达式。
X **&Y价值。
#!/usr/bin/python
import math
# This will import math module
print &math.pow(100, 2) : &, math.pow(100, 2)
print &math.pow(100, -2) : &, math.pow(100, -2)
print &math.pow(2, 4) : &, math.pow(2, 4)
print &math.pow(3, 0) : &, math.pow(3, 0)
这将输出以下结果:
math.pow(100, 2) :
math.pow(100, -2) :
math.pow(2, 4) :
math.pow(3, 0) :Python 里为什么函数可以返回一个函数内部定义的函数?
Python 初学。&br&看@函数修饰符的例子。看到一个这样的例子&br&&div class=&highlight&&&pre&&code class=&language-python&&&span class=&k&&def&/span& &span class=&nf&&spamrun&/span&&span class=&p&&(&/span&&span class=&n&&fn&/span&&span class=&p&&):&/span&
&span class=&k&&def&/span& &span class=&nf&&sayspam&/span&&span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&args&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span& &span class=&s&&&spam,spam,spam&&/span&
&span class=&k&&return&/span& &span class=&n&&sayspam&/span&
&/code&&/pre&&/div&&br&内部定义的函数可以作为返回值……内部这个函数的是不是被复制了一份然后返回给外部了……是不是可以这样理解:&br&&div class=&highlight&&&pre&&code class=&language-python&&&span class=&k&&def&/span& &span class=&nf&&spamrun&/span&&span class=&p&&(&/span&&span class=&n&&fn&/span&&span class=&p&&):&/span&
&span class=&n&&f&/span& &span class=&o&&=&/span& &span class=&k&&lambda&/span& &span class=&n&&args&/span&&span class=&p&&:&/span&&span class=&k&&print&/span& &span class=&s&&&spam,spam,spam&&/span&
&span class=&k&&return&/span& &span class=&n&&f&/span&
&/code&&/pre&&/div&&br&我想百度相关的知识的,找了半天没有找到,“函数内部定义函数”这样的关键字没有找到想要的答案。求懂的人指导。&br&&br&------------------------------------修改补充----------------------------&br&&div class=&highlight&&&pre&&code class=&language-python&&&span class=&k&&def&/span& &span class=&nf&&addspam&/span&&span class=&p&&(&/span&&span class=&n&&fn&/span&&span class=&p&&):&/span&
&span class=&k&&def&/span& &span class=&nf&&new&/span&&span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&args&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span& &span class=&s&&&spam,spam,spam&&/span&
&span class=&k&&return&/span& &span class=&n&&fn&/span&&span class=&p&&(&/span&&span class=&o&&*&/span&&span class=&n&&args&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&n&&new&/span&
&span class=&nd&&@addspam&/span&
&span class=&k&&def&/span& &span class=&nf&&useful&/span&&span class=&p&&(&/span&&span class=&n&&a&/span&&span class=&p&&,&/span&&span class=&n&&b&/span&&span class=&p&&):&/span&
&span class=&k&&print&/span& &span class=&n&&a&/span&&span class=&o&&**&/span&&span class=&mi&&2&/span&&span class=&o&&+&/span&&span class=&n&&b&/span&&span class=&o&&**&/span&&span class=&mi&&2&/span&
&/code&&/pre&&/div&&br&&br&理解执行 useful(3, 4) 相当于:&br&&br&useful(3,4)
--& addspam(useful(3,4))--&&br&&br&到这里就不知道怎么理解好了。addspam 返回了一个new,而 new 用到了addspam 传入的参数,即 useful(3, 4),但是 new 的形参是怎么给值的呢……所以 new 里执行的 fn(*args) 的 args 是怎么给的。看输出结果就是执行了 useful(3, 4)。只是不明白3,4怎么就给到了 *args。
Python 初学。看@函数修饰符的例子。看到一个这样的例子def spamrun(fn):
def sayspam(*args):
print "spam,spam,spam"
return sayspam
内部定义的函数可以作为返回值……内部这个函数的是不是被复制了一份然后返回给外部了……是不是可以这样理解:def spamrun(fn):
f = lambda args:print "spam,spam,spam"
我想百度相关的知识的,找了半天没有找到,“函数内部定义函数”这样的关键字没有找到想要的答案。求懂的人指导。------------------------------------修改补充----------------------------def addspam(fn):
def new(*args):
print "spam,spam,spam"
return fn(*args)
return new
def useful(a,b):
print a**2+b**2…
按投票排序
题主可能并没有理解“在Python中,函数本身也是对象”这一本质。那不妨慢慢来,从最基本的概念开始,讨论一下这个问题:1. Python中一切皆对象这恐怕是学习Python最有用的一句话。想必你已经知道Python中的list, tuple, dict等内置数据结构,当你执行:alist = [1, 2, 3]
时,你就创建了一个列表对象,并且用alist这个变量引用它:当然你也可以自己定义一个类:当然你也可以自己定义一个类:class House(object):
def __init__(self, area, city):
self.area = area
self.city = city
def sell(self, price):
#other code
return price
然后创建一个类的对象:house = House(200, 'Shanghai')
OK,你立马就在上海有了一套200平米的房子,它有一些属性(area, city),和一些方法(__init__, self):2. 函数是第一类对象和list, tuple, dict以及用House创建的对象一样,当你定义一个函数时,函数也是对象:def func(a, b):
return a+b
在全局域,函数对象被函数名引用着,它接收两个参数a和b,计算这两个参数的和作为返回值。在全局域,函数对象被函数名引用着,它接收两个参数a和b,计算这两个参数的和作为返回值。所谓第一类对象,意思是可以用标识符给对象命名,并且对象可以被当作数据处理,例如赋值、作为参数传递给函数,或者作为返回值return 等因此,你完全可以用其他变量名引用这个函数对象:add = func
这样,你就可以像调用func(1, 2)一样,通过新的引用调用函数了:这样,你就可以像调用func(1, 2)一样,通过新的引用调用函数了:print func(1, 2)
print add(1, 2)
#the same as func(1, 2)
或者将函数对象作为参数,传递给另一个函数:def caller_func(f):
return f(1, 2)
if __name__ == "__main__":
print caller_func(func)
可以看到,函数对象func作为参数传递给caller_func函数,传参过程类似于一个赋值操作f=func;于是func函数对象,被caller_func函数作用域中的局部变量f引用,f实际指向了函数func;cc当执行return f(1, 2)的时候,相当于执行了return func(1, 2);因此输出结果为3。3. 函数对象 vs 函数调用无论是把函数赋值给新的标识符,还是作为参数传递给新的函数,针对的都是函数对象本身,而不是函数的调用。用一个更加简单,但从外观上看,更容易产生混淆的例子来说明这个问题。例如定义了下面这个函数:def func():
return "hello,world"
然后分别执行两次赋值:ref1 = func
#将函数对象赋值给ref1
ref2 = func()
#调用函数,将函数的返回值("hello,world"字符串)赋值给ref2
很多初学者会混淆这两种赋值,通过Python内建的type函数,可以查看一下这两次赋值的结果:In [4]: type(ref1)
Out[4]: function
In [5]: type(ref2)
Out[5]: str
可以看到,ref1引用了函数对象本身,而ref2则引用了函数的返回值。通过内建的callable函数,可以进一步验证ref1是可调用的,而ref2是不可调用的:In [9]: callable(ref1)
Out[9]: True
In [10]: callable(ref2)
Out[10]: False
传参的效果与之类似。4. 闭包&LEGB法则所谓闭包,就是将组成函数的语句和这些语句的执行环境打包在一起时,得到的对象听上去的确有些复杂,还是用一个栗子来帮助理解一下。假设我们在foo.py模块中做了如下定义:#foo.py
filename = "foo.py"
def call_func(f):
return f()
#如前面介绍的,f引用一个函数对象,然后调用它
在另一个func.py模块中,写下了这样的代码:#func.py
import foo
#导入foo.py
filename = "func.py"
def show_filename():
return "filename: %s" % filename
if __name__ == "__main__":
print foo.call_func(show_filename)
#注意:实际发生调用的位置,是在foo.call_func函数中
当我们用python func.py命令执行func.py时输出结果为:chiyu@chiyu-PC:~$ python func.py
filename:func.py
很显然show_filename()函数使用的filename变量的值,是在与它相同环境(func.py模块)中定义的那个。尽管foo.py模块中也定义了同名的filename变量,而且实际调用show_filename的位置也是在foo.py的call_func内部。而对于嵌套函数,这一机制则会表现的更加明显:闭包将会捕捉内层函数执行所需的整个环境:#enclosed.py
import foo
def wrapper():
filename = "enclosed.py"
def show_filename():
return "filename: %s" % filename
print foo.call_func(show_filename)
#输出:filename: enclosed.py
实际上,每一个函数对象,都有一个指向了该函数定义时所在全局名称空间的__globals__属性:#show_filename inside wrapper
#show_filename.__globals__
'__builtins__': &module '__builtin__' (built-in)&,
#内建作用域环境
'__file__': 'enclosed.py',
'wrapper': &function wrapper at 0x7f&,
#直接外围环境
'__package__': None,
'__name__': '__main__',
'foo': &module 'foo' from '/home/chiyu/foo.pyc'&,
'__doc__': None
当代码执行到show_filename中的return "filename: %s" % filename语句时,解析器按照下面的顺序查找filename变量:Local - 本地函数(show_filename)内部,通过任何方式赋值的,而且没有被global关键字声明为全局变量的filename变量;Enclosing - 直接外围空间(上层函数wrapper)的本地作用域,查找filename变量(如果有多层嵌套,则由内而外逐层查找,直至最外层的函数);Global - 全局空间(模块enclosed.py),在模块顶层赋值的filename变量;Builtin - 内置模块(__builtin__)中预定义的变量名中查找filename变量;在任何一层先找到了符合要求的filename变量,则不再向更外层查找。如果直到Builtin层仍然没有找到符合要求的变量,则抛出NameError异常。这就是变量名解析的:LEGB法则。总结:闭包最重要的使用价值在于:封存函数执行的上下文环境;闭包在其捕捉的执行环境(def语句块所在上下文)中,也遵循LEGB规则逐层查找,直至找到符合要求的变量,或者抛出异常。5. 装饰器&语法糖(syntax sugar)那么闭包和装饰器又有什么关系呢?上文提到闭包的重要特性:封存上下文,这一特性可以巧妙的被用于现有函数的包装,从而为现有函数更加功能。而这就是装饰器。还是举个例子,代码如下:#alist = [1, 2, 3, ..., 100]
--& 1+2+3+...+100 = 5050
def lazy_sum():
return reduce(lambda x, y: x+y, alist)
我们定义了一个函数lazy_sum,作用是对alist中的所有元素求和后返回。alist假设为1到100的整数列表:alist = range(1, 101)
但是出于某种原因,我并不想马上返回计算结果,而是在之后的某个地方,通过显示的调用输出结果。于是我用一个wrapper函数对其进行包装:def wrapper():
alist = range(1, 101)
def lazy_sum():
return reduce(lambda x, y: x+y, alist)
return lazy_sum
lazy_sum = wrapper()
#wrapper() 返回的是lazy_sum函数对象
if __name__
== "__main__":
lazy_sum()
这是一个典型的Lazy Evaluation的例子。我们知道,一般情况下,局部变量在函数返回时,就会被垃圾回收器回收,而不能再被使用。但是这里的alist却没有,它随着lazy_sum函数对象的返回被一并返回了(这个说法不准确,实际是包含在了lazy_sum的执行环境中,通过__globals__),从而延长了生命周期。当在if语句块中调用lazy_sum()的时候,解析器会从上下文中(这里是Enclosing层的wrapper函数的局部作用域中)找到alist列表,计算结果,返回5050。当你需要动态的给已定义的函数增加功能时,比如:参数检查,类似的原理就变得很有用:def add(a, b):
return a+b
这是很简单的一个函数:计算a+b的和返回,但我们知道Python是 动态类型+强类型 的语言,你并不能保证用户传入的参数a和b一定是两个整型,他有可能传入了一个整型和一个字符串类型的值:In [2]: add(1, 2)
In [3]: add(1.2, 3.45)
Out[3]: 4.65
In [4]: add(5, 'hello')
---------------------------------------------------------------------------
Traceback (most recent call last)
/home/chiyu/&ipython-input-4-f2f9e8aa5eae& in &module&()
----& 1 add(5, 'hello')
/home/chiyu/&ipython-input-1-02b3d3d6caec& in add(a, b)
1 def add(a, b):
return a+b
TypeError: unsupported operand type(s) for +: 'int' and 'str'
于是,解析器无情的抛出了一个TypeError异常。动态类型:在运行期间确定变量的类型,python确定一个变量的类型是在你第一次给他赋值的时候;强类型:有强制的类型定义,你有一个整数,除非显示的类型转换,否则绝不能将它当作一个字符串(例如直接尝试将一个整型和一个字符串做+运算);因此,为了更加优雅的使用add函数,我们需要在执行+运算前,对a和b进行参数检查。这时候装饰器就显得非常有用:import logging
logging.basicConfig(level = logging.INFO)
def add(a, b):
return a + b
def checkParams(fn):
def wrapper(a, b):
if isinstance(a, (int, float)) and isinstance(b, (int, float)):
#检查参数a和b是否都为整型或浮点型
return fn(a, b)
#是则调用fn(a, b)返回计算结果
#否则通过logging记录错误信息,并友好退出
logging.warning("variable 'a' and 'b' cannot be added")
return wrapper
#fn引用add,被封存在闭包的执行环境中返回
if __name__ == "__main__":
#将add函数对象传入,fn指向add
#等号左侧的add,指向checkParams的返回值wrapper
add = checkParams(add)
add(3, 'hello')
#经过类型检查,不会计算结果,而是记录日志并退出
注意checkParams函数:首先看参数fn,当我们调用checkParams(add)的时候,它将成为函数对象add的一个本地(Local)引用;在checkParams内部,我们定义了一个wrapper函数,添加了参数类型检查的功能,然后调用了fn(a, b),根据LEGB法则,解释器将搜索几个作用域,并最终在(Enclosing层)checkParams函数的本地作用域中找到fn;注意最后的return wrapper,这将创建一个闭包,fn变量(add函数对象的一个引用)将会封存在闭包的执行环境中,不会随着checkParams的返回而被回收;当调用add = checkParams(add)时,add指向了新的wrapper对象,它添加了参数检查和记录日志的功能,同时又能够通过封存的fn,继续调用原始的add进行+运算。因此调用add(3, 'hello')将不会返回计算结果,而是打印出日志:chiyu@chiyu-PC:~$ python func.py
WARNING:root:variable 'a' and 'b' cannot be added
有人觉得add = checkParams(add)这样的写法未免太过麻烦,于是python提供了一种更优雅的写法,被称为语法糖:@checkParams
def add(a, b):
return a + b
这只是一种写法上的优化,解释器仍然会将它转化为add = checkParams(add)来执行。6. 回归问题def addspam(fn):
def new(*args):
print "spam,spam,spam"
return fn(*args)
return new
def useful(a,b):
print a**2+b**2
首先看第二段代码:@addspam装饰器,相当于执行了useful = addspam(useful)。在这里题主有一个理解误区:传递给addspam的参数,是useful这个函数对象本身,而不是它的一个调用结果;再回到addspam函数体:return new 返回一个闭包,fn被封存在闭包的执行环境中,不会随着addspam函数的返回被回收;而fn此时是useful的一个引用,当执行return fn(*args)时,实际相当于执行了return useful(*args);最后附上一张代码执行过程中的引用关系图,希望能帮助你理解:
题主遇到的这个问题很典型,就是把修饰器当成了包装器, 认为调用 useful 前先调用 addspam。其实 useful 不是被 addspam 包装了,而是替换了。调用 useful 调用的就是 new。余下的 fn 指向原来的 useful, 才需要第一类函数、作用域继承等知识点来理解。可变参数 *args 则是干扰的另外一个知识点,替换成 x, y 就行了。
Python里面的@只是一个syntax sugar而已,在你声明useful的时候,interpreter检查到你有外面有装饰器@addspam的存在,这时候你就可以大致理解成解释器做了以下的手脚:useful = addspam(useful)
所以你以后调用useful的时候,你调用的其实是new,不信可以看一下这个useful.__name__,已经变成new了。到了这里就没有addspam什么事情了。
很好的问题!请搜索higher order functions了解更多信息。因为我没有能力来清楚地解释,就放几篇我在学习函数式编程的时候看到的比较好的博文来帮助你理解。我喜欢最后一篇文章,通过实例来理解效果更好。
Python中,函数并没有什么特殊的,就是一个对象。
你没理解修饰器。用addspam修饰了useful后,你应该理解为这个函数变成了new。当调用useful函数的时候,其实是调用了new。
没有复制,函数也是个对象,基本就和你 return 一个 list 一个 dict 没什么两样。试试看在 Python REPL 中创建一个 function:&&& def foobar(): print("你好")
&&& foobar
&&& func_list = [foobar, foobar, foobar]
&&& func_list[0]()
后者是一个闭包 ( closure ),简单来说就是函数对象中包装了函数中引用的外部变量,可以想象成这个函数被动态创建的时候,引用的外部变量冻结在函数里面了。你新补充的我没怎么看懂,*args 的作用吗?*args 在形参上的作用类似捕获给函数的实参放在一个 args 的表中作为形参,如果作为实参传入的话,就是将 args 这个表解开作为分别的形参输入。
不是简单地返回函数。至少在Python里,def定义的函数和lambda定义的函数,后者是包含closure的。具体closure是什么,这真不是一句话能说清,我也不觉得我能说好,所以还是自己搜一下吧。不要说我歧视用百度查这种问题,这去Google搜个nested functions多好。
看完就明白了
不错 看完就明白了
已有帐号?
无法登录?
社交帐号登录

我要回帖

更多关于 python调用自定义函数 的文章

 

随机推荐