在Python中,函数是一等对象,而一等对象的定义是满足下述条件的程序实体:
- 在运行时创建
- 能赋值给变量或数据结构中的元素
- 能作为参数传递给函数
- 能作为函数的返回结果
我们通过下面的例子来证明python中的函数是对象:
>>> def factorial(n):
... '''return n!'''
... return 1 if n < 2 else n * factorial(n-1)
...
>>> factorial(41)
33452526613163807108170062053440751665152000000000
>>> factorial.__doc__
'return n!'
>>> type(factorial)
<class 'function'>
在第三行就可以看出,factorial
是一个类的示例,另外再看看下面的例子可以看出,python中的函数满足上面所讲的一等对象定义的要求:
>>> fact=factorial
>>> fact
<function factorial at 0x10d6daea0>
>>> fact(5)
120
>>> map(factorial,range(11))
<map object at 0x10d5e9c88>
>>> list(map(factorial,range(11)))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
下来再介绍下高阶函数,高阶函数就是接受函数作为参数,或者把函数作为结果返回的函数就是高阶函数。例如map
函数,filter
,reduce
和apply
(在python3中移除了)等。
>>> list(map(fact,range(6)))
[1, 1, 2, 6, 24, 120]
>>> list(map(factorial,filter(lambda n:n%2,range(6))))
[1, 6, 120]
为了使用高阶函数,有时候需要创建匿名函数会更加便利,在python
中,使用lambda
关键字来创建匿名函数,但是python
中的lambda
函数的定义体只能使用纯表达式,也就是不能赋值,也不能使用while
和try
等python
语句。如上面的例子。
可调用对象
除了用户定义的函数,调用运算符()还可以应用到其他对象上,如果要判断对象是否能调用,可以使用内置的callable()
函数,下面列出了7中可调用对象:
- 用户定义的函数,使用def
语句或lambda
表达式创建
- 内置函数,比如len
等
- 内置方法,如dict.get
- 方法 在类的定义体中定义的函数
- 类 调用类时候会运行__new__
方法创建实例,然后运行__init__
方法初始化,因为python
没有new
运算符,所以调用对象相当于调用函数
- 类的实例 如果类定义了__call__
方法,那么他的实例可以作为函数调用。
- 生成器函数 使用yield关键字的函数或方法。
实现__call__
方法的类是创建函数类对象的简便方法,此时必须在内部维护一个状态,让它在调用之间可用,创建保有内部状态的函数还有另一种方法--使用闭包。下面介绍下把函数视作对象处理的另一方面:运行时内省。
运行时内省
使用dir
函数可以看到factorial
具有下述属性:
>>> dir(factorial)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
其中大多数属性是python对象共有的,和用户定义的常规类一样,函数使用__dict__
属性存储赋予给它的用户属性。下面介绍下函数专有而用户定义的一般对象没有的属性:
>>> class C: pass
>>> obj=C()
>>> def func(): pass
>>> sorted(set(dir(func))-set(dir(obj)))
['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__']
上面所得到的差集就是类的实例没有而函数有的属性列表。下面的表格是介绍这些属性的类型和其说明:
名称 | 类型 | 说明 |
---|---|---|
__annotations__ | dict | 参数和返回值的注解 |
__call__ | method_wrapper | 实现()运算符 |
__closure__ | tuple | 函数闭包 |
__code__ | code | 编译成字节码的函数元数组和函数定义体 |
__defaults__ | tuple | 形式参数的默认值 |
__get__ | method_wrapper | 实现只读描述符协议 |
__globals__ | dict | 函数所在模块的全局变量 |
__kwdefaults__ | dict | 仅限关键字形式参数的默认值 |
__name__ | str | 函数名称 |
__qualname__ | str | 函数的限定名称 |
在python3中,提供了仅限关键字参数,调用函数是也可以使用和*展开可迭代对象,映射到单个参数,下面来介绍这些特性:
>>> def tag(name, *content, cls=None, **attrs):
... '''生成一个或多个html标签'''
... if cls is not None:
... attrs['class'] = 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)
...
>>> tag('br')
'<br />'
>>> tag('p','hello',id=33)
'<p id="33">hello</p>'
>>> tag(content='testing',name="img")
'<img content="testing" />'
>>> my_tag={'name':'img','title':'Sunset','src':'sunset.jpg','cls':'framed'}
>>> tag(**my_tag)
'<img class="framed" src="sunset.jpg" title="Sunset" />'
>>> tag('p','hello','world',cls='sidebar')
'<p class="sidebar">hello</p>\n<p class="sidebar">world</p>'
仅限关键字参数是python3新增的特性,cls参数只能通过关键字参数指定,它一定不会捕获未命名的定位参数。定义函数时如果想指定仅限关键字参数,要把它们放在前面有的参数后面。如果不想支持数量不定的定位参数,但是想支持仅限关键字参数,在签名中放一个,如下所示:
>>> def f(a,*,b)
return(a,b)
>>>f(1,b=2)
(1,2)
要注意,仅限关键字番薯不一定要有默认值,可以和上面的b那样,强制必须传入实参。
支持函数式编程的包
python中的operator
模块为多个算数运算符提供了对应的函数,比如:
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
... return reduce(mul,range(1,n+1))
...
>>> fact(4)
24
>>> data=[('xiaoming','19'),('xiaozhang','18')]
>>> sorted(data,key=itemgetter(1))
[('xiaozhang', '18'), ('xiaoming', '19')]
>>> class F():
... def __init__(self):
... self.name='zhangsan'
... self.age=29
... self.info={'city':'shanghai'}
...
>>> f=F()
>>> from operator import attrgetter
>>> attrgetter('name')(f)
'zhangsan'
>>> attrgetter('info.keys')(f)
<built-in method keys of dict object at 0x10d5f6510>
itemgetter
和attrgetter
会自行构建函数,itemgetter
使用的是[]
运算符,因此不仅支持序列,还支持映射和任何实现了__getitem__
方法的类,而attrgetter
的作用是根据名称提取对象属性,也就是.
运算符。
111
您好~你可不可以吧代码的md原文档发我看看,一直没有代码高亮………
你说的是这篇文章的md文档吗?
可以,如果不介意的话把关于django的md文档发过来也可以,我想学学……邮箱[email protected]
你好,django的md文档我没有的.我一般都是看官方文档.另外你说的没代码高亮是什么意思?我这里看到是有代码高亮的呀.
我的不知道为什么没有代码高亮………blog.fkomm.cn
站不错~~ 没有高亮应该是你在markdown中没有指定语言.比如python:
```python import os ```
可以发一篇你的文章么?我参考以下