python 常用语法及命令(二) 函数(__doc__ 可变参数 *和** 返回值 嵌套) 闭包 全局变量和局部变量 lambda

python 函数

__doc__

函数默认属性 打印函数文档 #例如print__doc__

help()也可以

>>> def Myfun(name):
...     'name是形参'
...     print('My name is' + name)
... 
>>> Myfun('harry')
My name isharry
>>> Myfun.__doc__
'name是形参'

可变参数(收集参数) 

就是把参数变成一个元组

>>> def test(*params):
...     print('参数的长度: ', len(params));
...     print('第二个参数: ', params[1])
... 
>>> def test(*params):
...     print('参数的长度: ', len(params))
...     print('第二个参数: ', params[1])
... 
>>> test(1,'abc','def',2,3)
参数的长度:  5
第二个参数:  abc

如果除了params还有额外的参数要显示的赋值,不然会报错

>>> def test(*params,exp):
...     print('参数的长度: ', len(params),exp)
...     print('第二个参数: ', params[1])
... 
>>> test(1,'abc','def',2,3,4,5)
  File "<stdin>", line 1
    test(1,'abc','def',2,3,4,5)
                             ^
SyntaxError: invalid character in identifier
>>> 
>>> test(1,'abc','def', 2, 3, 4, exp = 5)
参数的长度:  6 5
第二个参数:  abc

或者定义的时候给默认值 ,这时候exp也叫关键字参数

>>> def test(*params,exp=5):
...     print('参数的长度: ', len(params),exp)
...     print('第二个参数: ', params[1])
... 
>>> test(1,'abc','def', 2, 3, 4, 5)
参数的长度:  7 5
第二个参数:  abc

 参数放到某个*或者单个*后面,就会使得函数的某些参数强制使用关键字参数传递。

def recv(maxsize, *, block):
    'Receives a message'
    pass

recv(1024, True)  # TypeError
recv(1024, block=True)  # Ok

 利用这种技术,我们还能在接受任意多个位置参数的函数中指定关键字参数。比如

def mininum(*values, clip=None):
    m = min(values)
    if clip is not None:
        m = clip if clip > m else m
    return m

# minimum(1, 5, 2, -5, 10) # Returns -5
# minimum(1, 5, 2, -5, 10, clip=0) # Returns 0

使用强制关键字参数会比使用位置参数表意更加清晰,程序也更加具有可读性
使用强制关键字参数也会比使用 **kwargs 参数更好,因为在使用函数 help的时候输出也会更容易理解

强制关键字参数在一些更高级场合同样也很有用。例如,它们可以被用来在使用*args 和 **kwargs 参数作为输入的函数中插入参数
 

* params和 **params

*表示单个值,**表示键值对

>>> def sums(*args):
	s = 0
	for item in args:
		s += item
	return s
>>> sums(4,5,6)
15
>>> def printinfo(name, age, gender='男', *args, **kwds):
	    print('姓名:%s,年龄:%d,性别:%s'%(name, age, gender))
	    print(args)
	    print(kwds)

>>> printinfo('jay',35,'男',175,80,'范特西',hobby='milktea',daily='photo')
姓名:jay,年龄:35,性别:男
(175, 80, '范特西')
{'daily': 'photo', 'hobby': 'milktea'}

 这里args打印一个元组,kwd打印一个字典

* 参数能让一个函数接收任意数量的位置参数

>>> def avg(first,*rest):
...     return (first + sum(rest))/(1+len(rest))
...
>>> avg(1,2)
1.5
>>> avg(1,2,3,4)
2.5
#rest 是由所有其他位置参数组成的元组。然后我们在代码中把它当
#成了一个序列来进行后续的计算。

**参数 接收任意数量的关键字参数

import html

def make_element(name, value, **attrs):
    keyvals = [' %s="%s"' % item for item in attrs.items()]
    attr_str = ''.join(keyvals)
    element = '<{name}{attrs}>{value}</{name}>'.format(
                name=name,
                attrs=attr_str,
                value=html.escape(value))
    return element

# Example
# Creates '<item size="large" quantity="6">Albatross</item>'
make_element('item', 'Albatross', size='large', quantity=6)
# Creates '<p>&lt;spam&gt;</p>'
make_element('p', '<spam>')

如果你还希望某个函数能同时接受任意数量的位置参数和关键字参数,可以同时使用 * 和 **

def anyargs(*args, **kwargs):
    print(args) # A tuple
    print(kwargs) # A dict

使用这个函数时,所有位置参数会被放到 args 元组中,所有关键字参数会被放到字典 kwargs 中。
 

* 和 ** 用于列表、元组、字符串和字典的解包(https://blog.csdn.net/xufive/article/details/102856921)

>>> a = (1,2,3)
>>> print(a)
(1, 2, 3)
>>> print(*a)
1 2 3
>>> b = [1,2,3]
>>> print(b)
[1, 2, 3]
>>> print(*b)
1 2 3
>>> c = {'name':'xiaoming', 'age':5}
>>> print(c)
{'name': 'xiaoming', 'age': 51}
>>> print(*c)
name age
>>> print('name:{name}, age:{age}'.format(**c))
name:xiaoming, age:5

 注意 这里用.format格式化打印

默认参数

def spam(a, b=42):
    print(a, b)
spam(1) # Ok. a=1, b=42
spam(1, 2) # Ok. a=1, b=2

 如果默认参数是一个可修改的容器比如一个列表、集合或者字典,可以使用 None作为默认值,就像下面这样:

# Using a list as a default value
def spam(a, b=None):
    if b is None:
        b = []
    ...

如果你并不想提供一个默认值,而是想仅仅测试下某个默认参数是不是有传递进来,可以像下面这样写:

_no_value = object()

def spam(a, b=_no_value):
    if b is _no_value:
        print('No b value supplied')
    ...
>>> spam(1)
No b value supplied
>>> spam(1, 2) # b = 2
>>> spam(1, None) # b = None

 关于默认参数的几个关键点:

默认参数的值仅仅在函数定义的时候赋值一次

>>> x = 42
>>> def spam(a, b=x):
... print(a, b)
...
>>> spam(1)
1 42
>>> x = 23 # Has no effect
>>> spam(1)
1 42

 默认参数的值应该是不可变的对象比如 None、 True、 False、数字或字符串。特别的,千万不要像下面这样写代码:

def spam(a, b=[]): # NO!
    ...

 如果你这么做了,当默认值在其他地方被修改后你将会遇到各种麻烦。这些修改会影响到下次调用这个函数时的默认值。比如:

>>> def spam(a, b=[]):
... print(b)
... return b
...
>>> x = spam(1)
>>> x
[]
>>> x.append(99)
>>> x.append('Yow!')
>>> x
[99, 'Yow!']
>>> spam(1) # Modified list gets returned!
[99, 'Yow!']
>>>

 为了避免这种情况的发生,最好是将默认值设为None,然后在函数里面检查它。

在测试 None 值时使用 is 操作符是很重要的,也是这种方案的关键点。有时候大家会犯下下面这样的错误:

def spam(a, b=None):
    if not b: # NO! Use 'b is None' instead
        b = []
    ...

 这么写的问题在于尽管 None 值确实是被当成 False,但是还有其他的对象 (比如长度为 0 的字符串、列表、元组、字典等) 都会被当做 False。因此,上面的代码会误将一些其他输入也当成是没有输入。

>>> spam(1) # OK
>>> x = []
>>> spam(1, x) # Silent error. x value overwritten by default
>>> spam(1, 0) # Silent error. 0 ignored
>>> spam(1, '') # Silent error. '' ignored

一个函数需要测试某个可选参数是否被使用者传递进来。这时候需要小心的是你不能用某个默认值比如 None、 0 或者 False 值来测试用户提供的值 (因为这些值都是合法的值,是可能被用户传递进来的)。因此,你需要其他的解决方案了。
 为了解决这个问题,你可以创建一个独一无二的私有对象实例,就像上面的_no_value 变量那样。在函数里面,你可以通过检查被传递参数值跟这个实例是否一样来判断。这里的思路是用户不可能去传递这个 _no_value 实例作为输入。因此,这里通过检查这个值就能确定某个参数是否被传递进来了。

_no_value = object()

def spam(a, b=_no_value):
    if b is _no_value:
        print('No b value supplied')
    ...
>>> spam(1)
No b value supplied
>>> spam(1, 2) # b = 2
>>> spam(1, None) # b = None

这里对 object() 的使用看上去有点不太常见。 object 是 python 中所有类的基类。你可以创建 object 类的实例,但是这些实例没什么实际用处,因为它并没有任何有用的方法,也没有任何实例数据 (因为它没有任何的实例字典,你甚至都不能设置任何属性值)。你唯一能做的就是测试同一性。这个刚好符合我的要求,因为我在函数中就只是需要一个同一性的测试而已。

返回值

    函数没有return 也会返回一个空值

>>> def hello():
...   print('Hello World')
...
>>> temp = hello()
Hello World
>>> temp
>>> print(temp)
None
>>> type(temp)
<class 'NoneType'>
>>> def returntest():
...     return [1,2,'abc',3,33]
... 
>>> returntest()
[1, 2, 'abc', 3, 33]
>>> def returntest():
...     return 1,2,'abc',3,33
... 
>>> returntest()
(1, 2, 'abc', 3, 33)

 函数直接 return 一个元组就能返回多个值,尽管 returntest() 看上去返回了多个值,实际上是先创建了一个元组然后返回的。这
个语法看上去比较奇怪,实际上我们使用的是逗号来生成一个元组,而不是用括号。
当我们调用返回一个元组的函数的时候,通常我们会将结果赋值给多个变量,这就是 所说的元组解包。返回结果也可以赋值给单个变量,这时候这个变量值就是函数返回的那个元组本身.
 

>>> def myfun():
... return 1, 2, 3
...
>>> a, b, c = myfun()
>>> a
1
>>> b
2
>>> c
3

>>> x = myfun()
>>> x
(1, 2, 3)

 

 python支持嵌套函数

>>> def fun1():
        print('调用fun1()....')
        def fun2():
            print('调用fun2()...')
        fun2()
   
>>> fun1()
调用fun1()....
调用fun2()...

使用函数参数注解,给函数参数增加元信息

def add(x:int, y:int) -> int:
    return x + y

python 解释器不会对这些注解添加任何的语义。它们不会被类型检查,运行时跟没有加注解之前的效果也没有任何差距。然而,对于那些阅读源码的人来讲就很有帮助。第三方工具和框架可能会对这些注解添加语义。同时它们也会出现在文档中

>>> help(add)
Help on function add in module __main__:
add(x: int, y: int) -> int

尽管你可以使用任意类型的对象给函数添加注解 (例如数字,字符串,对象实例等等),不过通常来讲使用类或者字符串会比较好

 函数注解只存储在函数的 __annotations__ 属性中。例如:

>>> add.__annotations__
{'y': <class 'int'>, 'return': <class 'int'>, 'x': <class 'int'>}

尽管注解的使用方法可能有很多种,但是它们的主要用途还是文档。因为 python并没有类型声明,通常来讲仅仅通过阅读源码很难知道应该传递什么样的参数给这个函数。这时候使用注解就能给程序员更多的提示,让他们可以正确的使用函数。

 

减少可调用对象的参数个数

如果需要减少某个函数的参数个数,你可以使用functools.partial() 。partial()函数允许你给一个或多个参数设置固定的值,减少接下来被调用时的参数个数。

def spam(a, b, c, d):
    print(a, b, c, d)

使用partial() 函数来固定某些参数值

>>> from functools import partial
>>> s1 = partial(spam, 1) # a = 1
>>> s1(2, 3, 4)
1 2 3 4
>>> s1(4, 5, 6)
1 4 5 6
>>> s2 = partial(spam, d=42) # d = 42
>>> s2(1, 2, 3)
1 2 3 42
>>> s2(4, 5, 5)
4 5 5 42
>>> s3 = partial(spam, 1, 2, d=42) # a = 1, b = 2, d = 42
>>> s3(3)
1 2 3 42
>>> s3(4)
1 2 4 42
>>> s3(5)
1 2 5 42

可以看出partial() 固定某些参数并返回一个新的callable 对象。这个新的callable接受未赋值的参数,然后跟之前已经赋值过的参数合并起来,最后将所有参数传递给原始函数。

以某个点为基点,根据点和基点之间的距离来排序所有的这些点。列表的sort() 方法接受一个关键字参数来自定义排序逻辑,但是它只能接受一个单个参数的函数(distance() 很明显是不符合条件的)。现在我们可以通过使用partial() 来解决这个问题:

import math
def distance(p1, p2):
    x1, y1 = p1
    x2, y2 = p2
    return math.hypot(x2 - x1, y2 - y1)
>>> points = [ (1, 2), (3, 4), (5, 6), (7, 8) ]
>>> pt = (4, 3)
>>> points.sort(key=partial(distance,pt))
>>> points
[(3, 4), (1, 2), (5, 6), (7, 8)]

更进一步,partial() 通常被用来微调其他库函数所使用的回调函数的参数。例如,下面是一段代码,使用multiprocessing 来异步计算一个结果值,然后这个值被传递给一个接受一个result 值和一个可选logging 参数的回调函数:

 

def output_result(result, log=None):
    if log is not None:
        log.debug('Got: %r', result)
# A sample function
def add(x, y):
    return x + y

if __name__ == '__main__':
    import logging
    from multiprocessing import Pool
    from functools import partial
    logging.basicConfig(level=logging.DEBUG)
    log = logging.getLogger('test')
    
    p = Pool()
    p.apply_async(add, (3, 4), callback=partial(output_result, log=log))
    p.close()
    p.join()

 当给apply_async() 提供回调函数时,通过使用partial() 传递额外的logging参数。而multiprocessing 对这些一无所知——它仅仅只是使用单个值来调用回调函数。

闭包

https://www.cnblogs.com/yssjun/p/9887239.html

一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行,也就是会返回内部函数作为返回值。这样的一个函数我们称之为闭包。

看文字不好理解的定义,看实例就好了。

def funX(x):
    def funY(y):
        return x*y
    return funY
>>>x = funX(8)
>>> x
<function funX.<locals>.funY at 0x0000029B1F56CEA0>
>>> type(x)
<class 'function'>
>>> x(5)
40
>>> funX(8)(5)
40

 

能看出来满足两个条件 :一是函数(FunY)定义中引用了函数外定义的变量(x),二是该函数可以在其定义环境外被执行。

下面返回Fun2()  会有一个错误

>>> def fun1():
	x=5
	def fun2():
		x*=x
		return x
	return fun2()

>>> fun1()
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    fun1()
  File "<pyshell#28>", line 6, in fun1
    return fun2()
  File "<pyshell#28>", line 4, in fun2
    x*=x
UnboundLocalError: local variable 'x' referenced before assignment

return Fun2()会执行函数,而Fun2函数中的x是非全局变量的外部变量,所以 Fun2()中使用x变量是未定义的

使用容器可以解决,或者用 nonlocal 将变量声明为不是局部变量,用global不行

>>> def fun1():
	x=[5]
	def fun2():
		x[0] *= x[0]
		return x[0]
	return fun2()

>>> fun1()
25

python3中使用 nonlocal 将变量声明为不是局部变量

>>> def fun1():
	x=5
	def fun2():
		nonlocal x
		x*=x
		return x
	return fun2()

>>> fun1()
25

 

全局变量和局部变量

局部变量只能在函数内部使用,如果局部变量如全局变量重名,在函数内部会使用局部变量。在python中如果对变量做赋值操作,会认为定义了局部变量。

>>> a = 1
>>> def fun():
	a =3
	print(a)
	
>>> fun()
3
>>> a
1

如果需要修改全局变量的值需要加上global

>>> a
1
>>> def fun():
	global a
	a =5
	print(a)
	
>>> fun()
5
>>> a
5

列表、字典 在函数中当作全局变量,不用加global,这里不加global不是绝对的,如果对列表做增删改改查是不需要,如果直接对列表整个赋值是要加global的

>>> l = [9, 2, 3]
>>> def fun():
	l.append(5)
	print(l)

	
>>> fun()
[9, 2, 3, 5]
>>> l
[9, 2, 3, 5]

如果这样,对列表直接赋值

>>> l = [9, 2, 3, 5]
>>> def fun():
	l = 9
	print(l)

	
>>> fun()
9
>>> l
[9, 2, 3, 5]

 看到,函数输出改变了但是列表l是没有改变的,加上global会改变

>>> l = [9, 2, 3, 5]
>>> def fun():
	global l
	l = 9
	print(l)

	
>>> fun()
9
>>> l
9

 

闭包的使用

将单方法的类转换为函数

为了简化代码,将一个除__init__() 方法外只定义了一个方法的类转换成一个函数。大多数情况下,可以使用闭包来将单个方法的类转换成函数。下面示例中的类允许使用者根据某个模板方案来获取到URL 链接地址。

from urllib.request import urlopen

class UrlTemplate:
    def __init__(self, template):
        self.template = template
    def open(self, **kwargs):
        return urlopen(self.template.format_map(kwargs))

# Example use. Download stock data from yahoo
yahoo = UrlTemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f=,!{fields}')

for line in yahoo.open(names='IBM,AAPL,FB', fields='sl1c1v'):
    print(line.decode('utf-8'))

这个类可以被一个更简单的函数来代替:

def urltemplate(template):
    def opener(**kwargs):
        return urlopen(template.format_map(kwargs))
    return opener

# Example use
yahoo = urltemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f=,!{fields}')
for line in yahoo(names='IBM,AAPL,FB', fields='sl1c1v'):
    print(line.decode('utf-8'))

 一个闭包就是一个函数,只不过在函数内部带上了一个额外的变量环境。闭包关键特点就是它会记住自己被定义时的环境。因此,在我们的解决方案中,opener() 函数记住了template参数的值,并在接下来的调用中使用它。
任何时候只要你碰到需要给某个函数增加额外的状态信息的问题,都可以考虑使用闭包。相比将你的函数转换成一个类而言,闭包通常是一种更加简洁和优雅的方案。

带额外状态信息的回调函数

你的代码中需要依赖到回调函数的使用(比如事件处理器、等待后台任务完成后的回调等),并且你还需要让回调函数拥有额外的状态值,以便在它的内部使用到。   

为了演示与测试,我们先定义如下一个需要调用回调函数的函数:

def apply_async(func, args, *, callback):
    # Compute the result
    result = func(*args)
   
    # Invoke the callback with the result
    callback(result)
>>> def print_result(result):
...     print('Got:', result)
...
>>> def add(x, y):
...     return x + y
...
>>> apply_async(add, (2, 3), callback=print_result)
Got: 5
>>> apply_async(add, ('hello', 'world'), callback=print_result)
Got: helloworld

注意到print_result() 函数仅仅只接受一个参数result 。不能再传入其他信息。而当你想让回调函数访问其他变量或者特定环境的变量值的时候就会遇到麻烦。

为了让回调函数访问外部信息,一种方法是使用一个绑定方法来代替一个简单函数。比如,下面这个类会保存一个内部序列号,每次接收到一个result 的时候序列号加1:

class ResultHandler:
    def __init__(self):
        self.sequence = 0
    def handler(self, result):
        self.sequence += 1
        print('[{}] Got: {}'.format(self.sequence, result))
>>> apply_async(add, (2, 3), callback=r.handler)
[1] Got: 5
>>> apply_async(add, ('hello', 'world'), callback=r.handler)
[2] Got: helloworld

 第二种方式,作为类的替代,可以使用一个闭包捕获状态值,例如:

def make_handler():
    sequence = 0
    def handler(result):
        nonlocal sequence
        sequence += 1
        print('[{}] Got: {}'.format(sequence, result))
    return handler
>>> handler = make_handler()
>>> apply_async(add, (2, 3), callback=handler)
[1] Got: 5
>>> apply_async(add, ('hello', 'world'), callback=handler)
[2] Got: helloworld

需要注意对那些可修改变量的操作。在上面的方案中,nonlocal声明语句用来指示接下来的变量会在回调函数中被修改。如果没有这个声明,代码会报错。 

还有另外一个更高级的方法,可以使用协程来完成同样的事情:

def make_handler():
    sequence = 0
    while True:
        result = yield
        sequence += 1
        print('[{}] Got: {}'.format(sequence, result))

 对于协程,你需要使用它的send() 方法作为回调函数,如下所示:

>>> handler = make_handler()
>>> next(handler) # Advance to the yield
>>> apply_async(add, (2, 3), callback=handler.send)
[1] Got: 5
>>> apply_async(add, ('hello', 'world'), callback=handler.send)
[2] Got: helloworld

 send()函数实现了生成器与“外部程序” 动态地交换数据。send() 方法可以接收一个参数,它会将该参数传递给接收 yield 语句返回值的变量。这里的send是接受一个参数,也可以理解成像yield的返回值传送一个参数。

访问闭包中定义的变量 

通常来讲,闭包的内部变量对于外界来讲是完全隐藏的。但是,你可以通过编写访问函数并将其作为函数属性绑定到闭包上来实现这个目的。例如:

def sample():
    n = 0
    # Closure function
    def func():
        print('n=', n)
    # Accessor methods for n
    def get_n():
        return n
    def set_n(value):
        nonlocal n
        n = value
    # Attach as function attributes
    func.get_n = get_n
    func.set_n = set_n
    return func

 下面是使用的例子:

>>> f = sample()
>>> f()
n= 0
>>> f.set_n(10)
>>> f()
n= 10
>>> f.get_n()
10

为了说明清楚它如何工作的,有两点需要解释一下。首先,nonlocal 声明可以让我们编写函数来修改内部变量的值。其次,函数属性允许我们用一种很简单的方式将访问方法绑定到闭包函数上,这个跟实例方法很像(尽管并没有定义任何类)。 

还可以进一步的扩展,让闭包模拟类的实例。你要做的仅仅是复制上面的内部函数到一个字典实例中并返回它即可。例如:

import sys
class ClosureInstance:
    def __init__(self, locals=None):
        if locals is None:
            locals = sys._getframe(1).f_locals
        # Update instance dictionary with callables
        self.__dict__.update((key,value) for key, value in locals.items()
                if callable(value) )
    # Redirect special methods
    def __len__(self):
        return self.__dict__['__len__']()

# Example use
def Stack():
    items = []
    def push(item):
        items.append(item)
    def pop():
        return items.pop()
    def __len__():
        return len(items)
    return ClosureInstance()

 下面是一个交互式会话来演示它是如何工作的:

>>> s = Stack()
>>> s
<__main__.ClosureInstance object at 0x10069ed10>
>>> s.push(10)
>>> s.push(20)
>>> s.push('Hello')
>>> len(s)
3
>>> s.pop()
'Hello'
>>> s.pop()
20
>>> s.pop()
10
>>>

有趣的是,这个代码运行起来会比一个普通的类定义要快很多。你可能会像下面这样测试它跟一个类的性能对比: 

class Stack2:
    def __init__(self):
        self.items = []
    def push(self, item):
        self.items.append(item)
    def pop(self):
        return self.items.pop()
    def __len__(self):
        return len(self.items)
>>> from timeit import timeit
>>> # Test involving closures
>>> s = Stack()
>>> timeit('s.push(1);s.pop()', 'from __main__ import s')
0.9874754269840196
>>> # Test involving a class
>>> s = Stack2()
>>> timeit('s.push(1);s.pop()', 'from __main__ import s')
1.0707052160287276

 结果显示,闭包的方案运行起来要快大概8%,大部分原因是因为对实例变量的简化访问,闭包更快是因为不会涉及到额外的self 变量。

 

lamda表达式   

lambda  x :代码

   lamda表达式主要是使代码精简,尤其在python写脚本的时候,还避免给函数起名字,在函数只使用一两次的时候用lamda就大大简化了,可读性也高

>>> def fun(x):
	return 2*x+1

>>> fun(5)
11
>>> lambda x:2*x+1
<function <lambda> at 0x0000029B1F568488>
>>> f = lambda x:2*x+1
>>> f(5)
11
>>> def add(x,y):
	return x+y

>>> add(3,4)
7
>>> lambda x,y:x+y
<function <lambda> at 0x0000029B1F568598>
>>> f = lambda x,y : x+y
>>> f(3,4)
7

 

  1> filter函数中使用lamda

函数filter()用来计算并且过滤元素的迭代函数,原型是:filter(function,itearable)。

filter循环调用函数function,并且过滤传入的参数iterable,函数的结果返回的是true那就保存,返回false就不要,且返回的也是迭代器。filter返回的是一个filter对象可以通过list()或者for循环取出内容。传入的函数返回值必须是布尔类型

>>> filter(None,[1,0,False,True])
<filter object at 0x7f77a3486da0>
>>> list(filter(None,[1,0,False,True]))
[1, True]
>>> def odd(x):
	return x % 2

>>> temp = range(10)
>>> show = filter(odd,temp)
>>> list(show)
[1, 3, 5, 7, 9]
>>> list(filter(lambda x : x%2, range(10)))
[1, 3, 5, 7, 9]

 2> map中使用lambda map()函数类似函数filter,但是不会过滤,会输出全部计算结果

>>> list(map(lambda x : x *2,range(10)))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

相似的函数还有reduce(),函数原型是reduce(function,sequence),它的作用是用function对序列进行累积操作。也就是就是第 1、2 个元素用 function 函数运算,得到的结果再与第三个数据用 function 函数运算,然后得到的结果再与第四个进行运算,计算完所有数据。它返回值可以直接输出,不像map和filter返回的是一个迭代对象,还得去转化。

reduce函数是存放再functiontools模块中的,使用前要导入

>>> from functools import reduce
>>> print(reduce(lambda x,y:x*y,[1,2,3,4]))
24

排序sorted 

lambda 表达式典型的使用场景是排序或数据 reduce 等

>>> names = ['David Beazley', 'Brian Jones',
... 'Raymond Hettinger', 'Ned Batchelder']
>>> sorted(names, key=lambda name: name.split()[-1].lower())
['Ned Batchelder', 'David Beazley', 'Raymond Hettinger', 'Brian Jones']
>>> a = [{'name':'B', 'age':50}, {'name':'A', 'age':30}, {'name':'C', 'age':40}]
>>> sorted(a, key=lambda x:x['name']) # 按姓名排序
[{'name': 'A', 'age': 30}, {'name': 'B', 'age': 50}, {'name': 'C', 'age': 40}]
>>> sorted(a, key=lambda x:x['age']) # 按年龄排序
[{'name': 'A', 'age': 30}, {'name': 'C', 'age': 40}, {'name': 'B', 'age': 50}]

 尽管 lambda 表达式允许你定义简单函数,但是它的使用是有限制的。你只能指定单个表达式,它的值就是最后的返回值。也就是说不能包含其他的语言特性了,包括多个语句、条件表达式、迭代以及异常处理等等。

下面看一个关于lambda的问题

>>> x = 10
>>> a = lambda y: x + y
>>> x = 20
>>> b = lambda y: x + y

 a(10) 和 b(10) 返回的结果会被错误的认为是 20 和 30,实际上

>>> a(10)
30
>>> b(10)
30

这其中的奥妙在于 lambda 表达式中的 x 是一个自由变量,在运行时绑定值,而不是定义时就绑定,这跟函数的默认值参数定义是不同的。因此,在调用这个 lambda 表达式的时候, x 的值是执行时的值。

如果你想让某个匿名函数在定义时就捕获到值,可以将那个参数值定义成默认参数即可,就像下面这样:

>>> x = 10
>>> a = lambda y, x=x: x + y
>>> x = 20
>>> b = lambda y, x=x: x + y
>>> a(10)
20
>>> b(10)
30

再比如,通过在一个循环或列表推导中创建一个 lambda 表达式列表,并期望函数能在定义时就记住每次的迭代值。

>>> funcs = [lambda x: x+n for n in range(5)]
>>> for f in funcs:
... print(f(0))
...
4
4
4
4
4

 但是实际效果是运行是 n 的值为迭代的最后一个值。现在我们用另一种方式修改一下

 

>>> funcs = [lambda x, n=n: x+n for n in range(5)]
>>> for f in funcs:
... print(f(0))
...
0
1
2
3
4

通过使用函数默认值参数形式, lambda 函数在定义时就能绑定到值 

递归

可以设置递归最大层数,防止无限递归

>>> import sys
>>> sys.setrecursionlimit(10000)

1>斐波那契数

兔子繁殖问题

def fab(n):
	if n<1:
		print('输入错误')
		return -1
	if n==1 or n==2:
		return 1
	else:
		return fab(n-1) +fab(n-2)

result = fab(10)

随着n的增大,递归的时间远多于循环迭代

2>汉诺塔

(百度百科)汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

核心思想就是处理64盘子先处理钱63个

def hanoi(n,x,y,z):
	if n==1:
		print(x,' --> ',z)
	else:
		hanoi(n-1,x,z,y) #将前n-1个盘子从x移动到y上
		print(x, ' --> ',z) #将第n个盘子移动到z上
		hanoi(n-1,y,x,z) #将y上的n-1个盘子移动到z上

n= int(input('输入盘子数量: '))
hanoi(n,'X','Y','Z')
>>> n= int(input('输入盘子数量: '))
输入盘子数量: 4
>>> hanoi(n,'X','Y','Z')
X  -->  Y
X  -->  Z
Y  -->  Z
X  -->  Y
Z  -->  X
Z  -->  Y
X  -->  Y
X  -->  Z
Y  -->  Z
Y  -->  X
Z  -->  X
Y  -->  Z
X  -->  Y
X  -->  Z
Y  -->  Z

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值