专栏首页TeamsSix的网络空间安全专栏Python3学习笔记 | 二十一、Python的函数-函数的高级话题

Python3学习笔记 | 二十一、Python的函数-函数的高级话题

部分设备阅读本文会存在代码错乱的情况,可点击阅读原文链接到博客中进行查看

一、函数设计概念

当我们使用函数时,就开始面对如何将组件组合在一起的选择。例如,如何将任务分解成为更有针对性的函数(导致了聚合性),函数将如何通讯(耦合性)等。我们要深入考虑函数的大小概念,因为它们直接影响到代码的可用性。 耦合性:对于输入使用参数并且对于输出使用return语句。 耦合性:只有真正必要的情况下使用全局变量。 耦合性:不要改变可变类型的参数,除非调用者希望这么做。 聚合性:每一个函数都应该有一个单一的、统一的目标。 大小:每一个函数应该相对较小。 耦合性:避免直接改变在另一个模块文件中的变量。

二、递归函数

之前笔记也提到过,就是调用自身来进行循环的函数。

>>> sum([1,2,3,4])
10
>>> def mysum(l):
...     if not l:
...             return 0
...     else:
...             return l[0]+mysum(l[1:])
...
>>> mysum([1,2,3,4,5])
15

函数也可简单写成如下:

>>> def mysum(l):
...     return 0 if not l else l[0] + mysum(l[1:])
...

循环VS递归

一般情况下,循环会比递归简单。上面函数可以使用循环来解决,不需要递归,如下面的例子。

>>> sum = 0
>>> l = [1,2,3,4,5]
>>> for i in l:
...     sum += i
...
>>> sum
15

但在一些特殊情况,递归还是比较有用。比如,获取下面列表中所有数字的合:

>>> l = [1,2,[3,[4,5],6],[7,[8,[9]]],10]
>>> def sumtree(l):
...     sum = 0
...     for i in l:
...             if not isinstance(i,list):
...                     sum += i
...             else:
...                     sum += sumtree(i)
...     return sum
...
>>> sumtree(l)
55

三、函数对象:属性和注解

在Python里函数也是以对象的形态出现。函数名也是以变量名形式存放。因此函数也可以跨模块,以参数形势等传递。函数对象也能调用根本无关的操作:属性存储与注释。

间接函数调用:

>>> def myprint(x):
...     print(x)
...
>>> myprint2 = myprint
>>> myprint2('Dora')
Dora

因为函数对象可以被引用到变量,因此函数里也可以以参数方式传递:

>>> def myfunc(func,text):
...     func(text)
...
>>> myfunc(myprint,'Dora')
Dora

或者把函数放进列表或元组里:

>>> printing = [(myprint,'first'),(myprint,'second'),(myprint,'thrid')]
>>> for func,text in printing:
...     func(text)
...
first
second
thrid

函数也可作为返回值:

>>> def make(food):
...     def myprint(quantity):
...             print('We made{}:{}'.format(food,quantity))
...     return myprint
...
>>> Cake = make('cake')
>>> Cake(10)
We madecake:10

由于函数是对象,我们可以使用对象工具来处理函数。

>>> def myfunc(text):
...     print(text)
...
>>> dir(myfunc)
['__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__']

我们可以发现它有很多属性、方法等。

>>> myfunc.__name__
'myfunc'

我们也可以查看代码里的内容:

>>> myfunc.__code__
<code object myfunc at 0x000002395FF8C5D0, file "<stdin>", line 1>
>>> dir(myfunc.__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']
>>> myfunc.__code__.co_varnames
('text',)
>>> myfunc.__code__.co_argcount
1

我们也可以在函数里添加任意属性,可以看到下面最后多了一个‘a’:

>>> myfunc.a = 10
>>> dir(myfunc)
['__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__', 'a']

四、Python3.x中的函数注解

从Python3.0开始可以为函数的参数与返回值进行注解:

>>> def myfunc(a:int,b:str):
...     return a + b
...
>>> myfunc(1,3)
4
>>> def myfunc(a:int,b:str) -> list:
...     return a + b
...
>>> myfunc(1,3)
4
>>> myfunc.__annotations__
{'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'list'>}

但在代码里,没有任何限制。我们可以在特定工具可以利用。

五、匿名函数:lambda

之前也使用过lambda匿名函数。lambda会生成函数对象,但不赋值给任何变量。 lambda表达式:lambda [] [,] [,<arg3]…. : expression using args 参数不是必须的,但没有参数就没有相对意义。 lambda简单说明: lambda是一个表达式,而不是一个语句。--生成一个对象。lambda的主体是一个单个的表达式,而不是一个代码块。

>>> lambda a:a*a
<function <lambda> at 0x00000239602732F0>
>>> myfunc = lambda a:a*a
>>> myfunc(3)
9
>>> (lambda a:a*a)(4)
16

为什么要使用 lambda?

通常 lambda 起到了一种函数速写的作用。功能上def完全可以代替lambda。但当我们把函数对象放进列表里等操作的时候,使用def感觉很臃肿。这个时候我们可以使用lambda来简化过程。

>>> funclist = [lambda x : x**2,
...             lambda x : x**3,
...             lambda x : x**4]
>>> funclist[0](3)
9
>>> funclist[1](3)
27
>>> funclist[2](3)
81

六、lambda 作用域

对于lambda来说,作用域与函数相当。也遵循LEGB原则,关于LEGB原则可以参考:https://www.jianshu.com/p/3b72ba5a209c

>>> a = (lambda:1,print(2))
2
>>> def action(x):
...     return lambda y:x+y
...
>>> act =action(10)
>>> act(10)
20
>>> act = lambda x:lambda y :x+y
>>> act_rslt = act(20)
>>> act_rslt(10)
30
>>> (lambda x:lambda y:x+y)(20)(2)
22

七、在序列中映射函数:map

我们有个要求:下面列表里的每个值增加10 [1, 3, 5] 这个时候我们会想到循环

>>> l = [1,3,5]
>>> for i in range(3):
...     l[i] += 10
...
>>> l
[21, 23, 25]

但这个要是使用map,会更简单。

>>> l = [1,3,5]
>>> l = list(map(lambda x: x +10,l))
>>> l
[11, 13, 15]

map的第一个传递参数是函数,第二个是可迭代的对象,每个对象当做函数的输入,输出结合为可迭代的对象(Python2.x里是列表)

八、函数式编程工具(1):filter

filter与map相似,但是针对返回的bool结果判断,结果为真,保留元素;结果为假,弃用元素。结果也是保存在可迭代的对象里,在Python2.x是存放列表里。

>>> list(filter((lambda x : x > 1),[-1,-3,-5,1,3,5]))
[3, 5]

下面的示例因为返回的是列表里的值,只有0的时候bool值判断为假,因此除了0以外都保存了起来。

>>> list(filter((lambda x : x ),[-1,-3,-5,0,1,3,5]))
[-1, -3, -5, 1, 3, 5]

九、函数式编程工具(2):reduce

reduce函数是在functools里的,因此我们得import这个函数。

>>> from functools import reduce
>>> reduce((lambda x, y: x + y), [1, 2, 3, 4])
10

这个方法是,第一次从可迭代对象里提取两个元素当做函数的参数传入,按前面的函数进行运算,保存返回值,当可迭代对象里还有元素的时候,之前的返回值为第一个参数,可迭代对象里取下一个继续运算,直到可迭代对象空。最后返回函数的返回值。

>>> reduce((lambda x, y: x + y), 'test text')
'test text'
>>> reduce((lambda x, y: x + y), ['test', ' ', 'text'])
'test text'

本文分享自微信公众号 - TeamsSix(OldCat0111),作者:Teamssix

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CS学习笔记 | 14、powerup提权的方法

    利用 PowerUp 进行提权需要首先导入 ps1 文件powershell-import PowerUp.ps1,再执行powershell Invoke-A...

    TeamsSix
  • 经验总结 | VPS欠费后Hexo博客521无法访问

    最近自己博客的VPS欠费了,但是充值之后,启动VPS发现博客依旧无法访问,经过多次排查后,最后的结果真的是哭笑不得,下面就记录一下我最后的解决办法。

    TeamsSix
  • Python3学习笔记 | 十七、Python的语句与语法-文档

    在之前章节中,介绍的一些方法等,都是不全的。对于一个类型,有多少个方法、或者参数、属性等,需要查看文档。下面介绍Python里几种文档形式。

    TeamsSix
  • C++11——lambda表达式

    定义: C++11新增了很多特性,lambda表达式(lambda expression)就是其中之一,很多语言都提供了 lambda 表达式,如 Pyth...

    Dabelv
  • 细说Python的lambda函数用法,建议收藏

    在Python中有两种函数,一种是def定义的函数,另一种是lambda函数,也就是大家常说的匿名函数。今天我就和大家聊聊lambda函数,在Python编程中...

    stormwen
  • Python lambda介绍

    在学习python的过程中,lambda的语法时常会使人感到困惑,lambda是什么,为什么要使用lambda,是不是必须使用lambda?

    战神伽罗
  • 生产者理论概述

    先前介绍了消费者理论,本文将简要介绍生产者理论。 通过模型去拟合消费者和生产者的行为,然后在市场的大背景下去分析市场行为,这些构成了微观经济学的基本骨架。 ...

    用户1147754
  • 医学图像处理案例(六)——生成血管三维模型

    在前面的文章中,已经分享了人体肋骨和肺组织分割生成三维模型的例子。今天将继续分享人体脑部血管分割并生成三维模型的案例。

    用户7498388
  • 【Python学习笔记之三】lambda表达式用法小结

    除了def语句之外,Python还提供了一种生成函数对象的表达式形式。由于它与LISP语言中的一个工具很相似,所以称为lambda。就像def一样,这个表达式创...

    Angel_Kitty
  • 【Java8新特性】01 函数式接口和Lambda表达式你真的会了吗

    Lambada表达式可以理解为:可传递的匿名函数的一种简洁表达方式。Lambda表达式没有名称,同普通方法一样有参数列表、函数主体、返回类型等;

    爱笑的架构师

扫码关注云+社区

领取腾讯云代金券