ExASIC
分享让工作更轻松

python的函数(四):递归函数、匿名函数等

今天学习函数的最后一节。一般来说,前面三节的语法知识已经够用了,这一篇是几个高级一点的话题,主要包括递归函数、匿名函数、函数的属性与标注。由于是高级话题,我们就简单的介绍。

啥?前三节是啥?好吧。 不记得的童鞋点下面快速回顾一下!

python的函数(一):基本概念
python的函数(二):作用域
python的函数(三):参数传递

递归函数

递归函数,简言之就是“自己调用自己”的函数。有点绕口,用一个简单的例子来说明。对一个列表求和,你会想到什么方法?

上面的方法都不错。但今天我们用递归来对列表求和。

示例一
def list_sum(l):
    print(l)
    if not l:
        return 0
    else:
        return l[0] + list_sum(l[1:])
        #把l[1:],即列表除第一个元素外,传递给自己

sum = list_sum([1, 2, 3, 4, 5])
print(sum)

结果输出:
[1, 2, 3, 4, 5]
[2, 3, 4, 5]
[3, 4, 5]
[4, 5]
[5]
[]
15

这个例子中,把列表除第一个元素外的部分作为新列表,传递给递归函数。当列表为空时,就达到了递归结束的条件,计算出列表元素的和。这种方法仅仅用来演示递归函数的使用方法,大家在求和时还是要用前两种方法哈。

匿名函数

匿名函数,顾名思义就是没有名字的函数,临时的函数。下面举两个例子。

示例二
l = [lambda x : 1 ** x,
     lambda x : 2 ** x,
     lambda x : 3 ** x,
     lambda x : 4 ** x,
     lambda x : 5 ** x,
     lambda x : 6 ** x]

for f in l:
    print(f(2), end=' ')
print('')

for f in l:
    print(f(3))
print('')

结果输出:
1 4 9 16 25 36
1 8 27 64 125 216

lambda是匿名函数的定义关键字,紧接着是参数x,冒号后面是函数主体,但函数主体只能写一句话。lambda语句执行后,创建了一个函数对象,但没有名字。上面这个例子里,我们把这些函数对象放在一个列表里。在使用时,用f指向这个对象,用f(x)形式来调用匿名函数。

通常匿名用inline形式,就是说作为一个表达式嵌入在代码里。再看一个例子。

示例三
import tkinter

top = tkinter.Tk()

str_e1 = tkinter.StringVar()
e1 = tkinter.Entry(top, textvariable=str_e1)
str_e1.set("hello")
e1.pack()

b1 = tkinter.Button(top, text="press me", command=lambda : print(str_e1.get()))
b1.pack()

top.mainloop()

结果输出:

tk hello

点击按钮,终端里输出hello。

这个例子展示的是,在GUI编程时,可以用匿名函数实现一个简短的临时函数。比def要简洁很多。

函数的属性与标注

我们已经知道函数是一个对象,由<class 'function'>定义。那么作为一个对象,也可以用自己的属性(成员变量)和方法(成员函数)。我们用dir()来研究一下函数内部是什么样的。

假定有一个函数

def func(a, b):
    return a+b

执行dir(func)显示如下:

['__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__']

dir()的返回值是一个函数对象内部属性和方法的列表。我们下面主要看看其中的__annotations__,__code__,__name__等。

__name__

__name__里面保存的是函数的名字,print(func.__name__)输出func。

__code__

__code__是函数的主体对象,并包括函数的参数等信息。我们执行print(dir(func.__code__))输出如下:

['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']

例如, print(func.__code__.co_argcount)输出函数的参数个数 2。 print(func.__code__.co_varnames)输出函数参数的列表 ('a', 'b')。

__annotations__

我们直接看下面的例子。

def sum(a : int, b : int) -> int :
    if not type(a) == sum.__annotations__['a'] :
        print("Error: a should be type int")
        return

    return a + b

s = sum(2, 5)
print(s)
s = sum('abc', 5)
print(s)

结果输出:
7
Error: a should be type int
None

这个例子,我们使用annotation来限制变量类型,当不符合变量类型时报错。其中:int指定变量类型。函数的返回值的annotation写在最后面-> int。

总结

至此,函数部分讲完了,《Python在ASIC中的应用》的基础篇也结束了。各位童鞋学得怎么样?编程没有捷径,一定要多写,多思考!

下一次,我们一起学习《Python在ASIC中的应用》的中级篇,学习一些模块、文件读写、正则表达式等。

阅读数:
更多文章:文章目录
欢迎使用ExASIC订阅服务
仅用于ExASIC最新文章通知,方便及时阅读。
成都奥卡思微电科技有限公司,主要产品有AVE自动化验证工具软件和MegaEC等价验证工具软件。硅知识,上海市集成电路高技能人才培养基地NanDigits中国,主要产品GOF。AD