python学习笔记

速撸《python学习手册》--第16-20章-函数

2018-08-18  本文已影响0人  DamaoShao

第16章 函数基础

为何使用函数

编写函数

17章 作用域

在默认情况下,一个函数的所有变量名都是与函数命令空间关联的。即

变量名解析:legb原则

对于一个def语句:

LEGB原则:

global语句

全局变量如果在函数内部被赋值的话,必须经过声明

尽量少用 global

导入进来的别的模块的全局变量,也是全局变量。

nonlocal语句

用于定义函数时,内层变量引用外层变量,不然修改时会报错,类似global。

# 不改变变量时,不报错
In [133]: def tester(start):
     ...:     state=start
     ...:     def nested(label):
     ...:         print(label,state)
     ...:     return nested

In [134]: F=tester(0)

In [135]: F
Out[135]: <function __main__.tester.<locals>.nested(label)>

In [136]: F('damao')
damao 0

In [137]: F('ermao')
ermao 0

# 一旦改变变量,不用nonlocal声明,报错
In [138]: def tester(start):
     ...:     state=start
     ...:     def nested(label):
     ...:         print(label,state)
     ...:         state+=1
     ...:     return nested

In [139]: F=tester(0)

In [140]: F('damao')
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-140-776037024ad4> in <module>()
----> 1 F('damao')

<ipython-input-138-c3d251ed857c> in nested(label)
      2     state=start
      3     def nested(label):
----> 4         print(label,state)
      5         state+=1
      6     return nested

UnboundLocalError: local variable 'state' referenced before assignment

# 内层函数用之前,一定要先声明,哪怕第一次使用时候,并没有改变变量
In [142]: def tester(start):
     ...:     state=start
     ...:     def nested(label):
     ...:         print(label,state)
     ...:         nonlocal state
     ...:         state+=1
     ...:     return nested
     ...:
     ...:
  File "<ipython-input-142-a0b8a3802677>", line 5
    nonlocal state
    ^
SyntaxError: name 'state' is used prior to nonlocal declaration


# 注意 不同的工厂函数可以生产出不同的值
In [143]: def tester(start):
     ...:     state=start
     ...:     def nested(label):
     ...:         nonlocal state
     ...:         print(label,state)
     ...:         state+=1
     ...:     return nested

In [144]: F=tester(0)

In [145]: F('damao')
damao 0

In [146]: F('ermao')
ermao 1

In [147]: F('sanmao')
sanmao 2

In [148]: F('damao')
damao 3

In [149]: F('ermao')
ermao 4

In [150]: G=tester(100)

In [151]: G('damao')
damao 100

In [152]: G('damao')
damao 101

In [153]: F('damao')
damao 5

In [154]: F('damao')
damao 6

还有一个注意的是,nonlocal声明的变量,毕竟在上层def中已经存在,不然立马报错。

另外,nonlocal 只会在嵌套的def中去查找变量,不会上升到全局。

# 如果不使用nonlocal声明,可以绑定内层函数
In [168]: def tester(start):
     ...:     def nested(label):
     ...:         print(label,nested.state)
     ...:         nested.state+=1
     ...:     nested.state=start
     ...:     return nested

In [169]: F=tester(1)

In [170]: F('damao')
damao 1

In [171]: F('damao')
damao 2

In [172]: F('damao')
damao 3

In [173]: G=tester(1000)

In [174]: G('damao')
damao 1000

In [175]: G('damao')
damao 1001

列举python中保持状态的方法?

第18章 参数


通过对象引用传递:

python类就是依靠传入的self来更新对象状态。

特定参数匹配模型

python内部赋值进行参数匹配:

模拟 python print函数

import sys


def print_redef(*args, **kargs):
    sep = kargs.get('sep', ' ')
    end = kargs.get('end', '\n')
    file = kargs.get('file', sys.stdout)
    output = ''
    for arg in args:
        output += str(arg) + str(sep)
    file.write(output[:-len(sep)] + end)

def print_redef_1(*args, **kargs):
    sep=kargs.pop('sep', ' ')
    end=kargs.pop('end', '\n')
    file=kargs.pop('file',sys.stdout)
    if kargs:raise TypeError('extra keywords:' % kargs)
    output = ''
    for arg in args:
        output += str(arg) + str(sep)
    file.write(output[:-len(sep)] + end)
    
def print_redef_2(*args, sep=' ', end='\n', file=sys.stdout):
    output = ''
    for arg in args:
        output += str(arg) + str(sep)
    file.write(output[:-len(sep)] + end)


print_redef(1, 2, 3)
print_redef(1, 2, 3, sep='--')
print_redef(1, [2, 20], (3, 30), sep='--')

print_redef_2(1, 2, 3)
print_redef_2(1, 2, 3, sep='__', end='!\n')
print_redef_2(1, 2, 3, sep='__')

第19章 函数的高级话题

函数设计概念

递归

即函数内调用本身

In [176]: def mysum(L):
     ...:     print(L)
     ...:     if not L:
     ...:         return 0
     ...:     else:
     ...:         return L[0]+mysum(L[1:])
     ...:

In [177]:

In [177]: mysum([1,2,3,4,5,6])
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
# 计算一个嵌套的子列表结构中所有数字和
In [184]: def sumtree(L):
     ...:     tot=0
     ...:     for x in L:
     ...:         if not isinstance(x,list):
     ...:             tot+=x
     ...:         else:
     ...:             tot+=sumtree(x)
     ...:     return tot
     ...:
     ...:

In [185]: sumtree([1,[2,[3,4,[5,6,[7,8],10]]]])
Out[185]: 46

函数对象:属性和注解

匿名函数

第20章 迭代和解析,第二部分

python对于延迟的只是:

生成器函数

状态挂起

生成器yield一个值,而不是return一个值,yield语句挂起函数后,向调用者发送一个值,保留足够的状态能够从它离开的地方继续。

迭代协议整合

可迭代对象定义了一个<next>方法,它要么返回迭代中的下一项,要么引发一个特殊的StopIteration。一个对象的迭代器用iter内置函数接受。

生成器是单迭代器对象

# 实现map函数
def mymap(func, *args):
    res = []
    for arg in zip(*args):
        res.append(func(*arg))
    return res


def mymap(func, *args):
    return [func(*arg) for arg in zip(*args)]


# yield版本,包含进入list中即可一次产生所有值
def mymap(func, *args):
    for arg in zip(*args):
        yield func(*arg)


def mymap(func, *args):
    return (func(*arg) for arg in zip(*args))


# print(mymap(abs,[1,2,-1,-100,2]))tuple
# print(list(mymap(abs,[1,2,-1,-100,2])))

# 截断zip
def myzip(*seqs):
    seqs = [list(S) for S in seqs]
    print(seqs)
    res = []
    # 利用数组原处改动的原理
    while all(seqs):
        #  相当于列表解析
        res.append(tuple(S.pop(0) for S in seqs))
    return res


# 不截断zip
def myzip(*seqs, pad=None):
    seqs = [list(S) for S in seqs]
    res = []
    while any(seqs):
        # pop完list之后是一个空数组
        res.append(tuple((S.pop(0) if S else pad) for S in seqs))

    return res


# 改成yield版本
def myzip(*seqs):
    seqs = [list(S) for S in seqs]
    while all(seqs):
        yield tuple(S.pop(0) for S in seqs)


def myzip(*seqs, pad=None):
    seqs = [list(S) for S in seqs]
    while any(seqs):
        # pop完list之后是一个空数组
        yield tuple((S.pop(0) if S else pad) for S in seqs)


# print(list(myzip([1,2,3],[4,5,6,7,8],[100,299,222])))

# 采用了判断长度的方法,返回值换成圆括号,就是生成器
def myzip(*seqs):
    minlen = min(len(S) for S in seqs)
    return [tuple(S[i] for S in seqs) for i in range(minlen)]




def myzip(*seqs, pad=None):
    maxlen = max(len(S) for S in seqs)
    return [tuple((S[i] if len(S) > i else pad) for S in seqs) for i in range(maxlen)]

# 为什么这里while iters 可以知道长度。
def myzip(*args):
    iters=list(map(iter,args))
    while iters:
        res=[next(i) for i in iters]
        yield tuple(res)

print(list(myzip([1, 3, 4, 5], [6, 7, 8, 9, 10])))

列表解析的语法

In [238]: [x*x for x in range(5)]
Out[238]: [0, 1, 4, 9, 16]

In [239]: [x*x for x in range(5) if x%2 == 0]
Out[239]: [0, 4, 16]

In [240]: [x*x if x%2 ==0 for x in range(5)]
  File "<ipython-input-240-7254a199a58d>", line 1
    [x*x if x%2 ==0 for x in range(5)]
                      ^
SyntaxError: invalid syntax


In [241]: [(x*x if x%2 ==0) for x in range(5)]
  File "<ipython-input-241-100abab91a2e>", line 1
    [(x*x if x%2 ==0) for x in range(5)]
                    ^
SyntaxError: invalid syntax


In [242]: [(x*x if x%2 ==0 else 0) for x in range(5)]
Out[242]: [0, 0, 4, 0, 16]

In [243]: [(x*x if x%2 ==0 else None) for x in range(5)]
Out[243]: [0, None, 4, None, 16]

注意map函数可能比列表解析快,他俩都比for要快的多

函数的陷阱

In [245]: def saver(x=[]):
     ...:     x.append(1)
     ...:     print(x)
     ...:

In [246]: saver([2])
[2, 1]

In [247]: saver()
[1]

In [248]: saver()
[1, 1]

In [249]: saver()
[1, 1, 1]

In [250]: saver()
[1, 1, 1, 1
 
In [251]: def saver(x=None):
     ...:     if x is None:
     ...:         x=[]
     ...:     x.append(1)
     ...:     print(x)
     ...:

In [252]: saver([2])
[2, 1]

In [253]: saver([2,2])
[2, 2, 1]

In [254]: saver()
[1]

In [255]: saver()
[1]

In [256]: saver()
[1]
 
 
# 利用函数的属性记录状态
 In [257]: def saver():
     ...:     saver.x.append(1)
     ...:     print(saver.x)
     ...:

In [258]: saver.x=[]

In [259]: saver()
[1]

In [260]: saver()
[1, 1]

In [261]: saver()
[1, 1, 1]

python迭代器和生成器的区别

relations
  1. 容器(container):

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象)在Python中,常见的容器对象有:

  1. 可迭代对象

但凡是可以返回一个迭代器的对象都可称之为可迭代对象,可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。

  1. 迭代器(iterator)

那么什么迭代器呢?它是一个带状态的对象,他能在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter____next__()(python2中实现next())方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常,至于它们到底是如何实现的这并不重要。

所以,迭代器就是实现了工厂模式的对象,它在你每次你询问要下一个值的时候给你返回。有很多关于迭代器的例子,比如itertools函数返回的都是迭代器对象。

  1. 生成器(generator)

生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()__next__()方法了,只需要一个yiled关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值。

  1. 生成器表达式(generator expression)

生成器表达式是列表推倒式的生成器版本,看起来像列表推导式,但是它返回的是一个生成器对象而不是列表对象。

上一篇 下一篇

猜你喜欢

热点阅读