函数基础
- def语句是一个可执行语句,当他运行时,他创建一个新的函数对象并将其赋值给一个变量名。一个def可以出现在任一语句可以出现的地方,并没有什么特别
>>> if True:
def Fun():
print('True')
else:
def Fun():
print('False')
>>> Fun()
True
- 函数允许任意的属性附加到记录信息以供使用
>>> def Fun() : pass
>>> 'Test' in dir(Fun)
False
>>> Fun.Test = 'Hello Python'
>>> 'Test' in dir(Fun)
True
>>> Fun.Test
'Hello Python'
作用域
- 当在函数中使用未认证的变量名时,python会搜索四个作用域:本地作用域,之后是上一层def或lambda的本地作用域,之后是全局作用域,最后是内置作用域
- 内置作用域仅仅是一个名为
__builtin__
的标准库模块
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
- global是一个命令空间声明,告诉python生成一个或多个全局变量名
>>> v = 0
>>> def Fun():
global v, v1
v, v1 = "ab"
>>> print(v)
0
>>> print(v1)
Traceback (most recent call last):
File "<pyshell#39>", line 1, in <module>
print(v1)
NameError: name 'v1' is not defined
>>> Fun()
>>> print(v, v1)
a b
- 函数能够记住嵌套作用域的变量值,即使那个作用域已经不存在了。若lambda或def在函数中定义,嵌套在一个循环内,并且嵌套的函数引用了一个上层作用域的变量,该变量被循环改变,所有在这个循环内中产生的函数将具有相同的值,这个值是最后一次循环完成时,被引用变量的值
>>> def Fun():
value = 1
def FunTest():
print(value)
return FunTest
>>> pFunTest = Fun()
>>> pFunTest()
1
>>> def Fun():
v = []
for i in range(0, 5):
v.append(lambda : print(i))
return v
>>> v1 = Fun()
>>> for i in range(0, 5):
v1[i]()
4
4
4
4
4
- 默认情况下,当一个函数嵌套在另一个函数中时,嵌套的函数可以引用嵌套的外层def作用域中定义的任何名称,但是不能修改他们。
- nonlocal声明了将要在一个嵌套的def中修改的名称,此名称不能是全局模块作用域中的,在声明nonlocal时,他必须已存在在该嵌套函数的作用域中。
>>> def F1():
v1 = 1
def F2():
v1 += 1
print(v1)
F2()
>>> F1()
Traceback (most recent call last):
File "<pyshell#241>", line 1, in <module>
F1()
File "<pyshell#240>", line 6, in F1
F2()
File "<pyshell#240>", line 4, in F2
v1 += 1
UnboundLocalError: local variable 'v1' referenced before assignment
>>> def F1():
v1 = 1
def F2():
nonlocal v1
v1 += 1
print(v1)
F2()
>>> F1()
2
>>> def F1():
v = 1
def F2():
def F3():
nonlocal v
v += 1
print(v)
F3()
F2()
>>> F1()
2
参数
-
函数参数传递:不可变参数类似C通过值进行传递,可变对象类似C通过指针进行传递
-
在函数调用中,参数必须以此顺序出现:任何位置参数,后接任何关键字参数和*sequence形式的组合,后跟**dict形式(关键字参数可能会包含在**dict中)
-
在函数的头部,参数必须以此顺序出现:任何一般参数,后接任何默认参数,如果有的话后接*name(或者python3.0中的*),后面接任何name或name = value 的keyword-only参数,后接**name的形式
-
利用*和**收集参数
>>> def Fun(*a, **b): print(a, b)
>>> Fun(1, 2, 3, x = 1, y = 2, 'c' = 3)
SyntaxError: keyword can't be an expression
>>> Fun(1, 2, 3, x = 1, y = 2, c = 3)
(1, 2, 3) {'y': 2, 'c': 3, 'x': 1}
- 解包参数
>>> def Fun(a, b, c, d) : print(a, b, c, d)
>>> Fun(*"abcd")
a b c d
>>> Fun(**{'a':1, 'b':2, 'c':3, 'd':4})
1 2 3 4
>>> def Fun(**a) : print(a)
>>> Fun(**{'a':1, 'b':2, 'c':3, 'd':4})
{'a': 1, 'c': 3, 'd': 4, 'b': 2}
>>> def Fun(a, b = 1, **c):print(a, b, c)
>>> Fun(1, x = 1, y = 2, b = 3)
1 3 {'y': 2, 'x': 1}
- 强制按照关键字传递参数:在参数列表使用*
>>> def Fun(a, *b, c = 1) : print(a, b, c)
>>> Fun(1, 2)
1 (2,) 1
>>> def Fun(a, *, b = 0, c = 1) : print(a, b, c)
>>> Fun(1)
1 0 1
>>> Fun(1, 2)
Traceback (most recent call last):
File "<pyshell#358>", line 1, in <module>
Fun(1, 2)
TypeError: Fun() takes 1 positional argument but 2 were given
函数的高级话题
- 函数注解
>>> def Fun(a:'A', b:'B' = 1, c:'Test' = [1]) -> int:
print(a, b, c)
>>> Fun(1, 2)
1 2 [1]
>>> Fun.__annotations__
{'b': 'B', 'c': 'Test', 'return': <class 'int'>, 'a': 'A'}
- lambda表达式只能封装有限的逻辑,甚至连一般的if都不能包含
lambda arg0, arg1...:expression
>>> f = lambda a, b, c : a + b + c
>>> print(f(*"abc"))
abc
>>> f = lambda x : print('True') if x else print('False')
>>> f(0)
False
>>> f(1)
True
>>> f = lambda x : if x : print(x)
SyntaxError: invalid syntax
- map filter reduce
>>> list(map(lambda x : x * 2, "abc"))
['aa', 'bb', 'cc']
>>> list(map(pow, [1, 2 ,3], [1, 2, 3]))
[1, 4, 27]
>>> list(filter(lambda x : x > 0, [0, 1, 2, -1]))
[1, 2]
>>> from functools import reduce
>>> reduce(lambda x, y : x + y, [1, 2, 3])
6
迭代和解析第二部分
- 列表解析在一个序列的值上应用任意一个表达式,将其结果收集到一个新的列表中并返回
>>> [ord(x) for x in "szn"]
[115, 122, 110]
>>> [x * 2 + y * 2 for x in "abc" if x == "a" for y in "123" if y == '1' or y == "2"]
['aa11', 'aa22']
- 生成器函数和常规函数之间的主要不同之处在于,生成器yields一个值,而不是返回一个值。yield语句挂起该函数并向调用者发送回一个值,但是保留足够的状态使得函数能够从他离开的地方继续。当调用时,生成器函数返回一个迭代器对象,该对象支持__next__
>>> def Fun():
for i in range(0, 5):
print('Fun:', i)
yield i
>>> Fun()
<generator object Fun at 0x00000000036DFAF8>
>>> list(Fun())
Fun: 0
Fun: 1
Fun: 2
Fun: 3
Fun: 4
[0, 1, 2, 3, 4]
- send()方法生成一系列结果的下一个元素,这一点类似于next(),但send还提供了一种调用者与生成器之间通信的方法
>>> def Fun():
for i in range(0, 5):
x = yield i
print(x)
>>> G = Fun()
>>> G.send(1024)
Traceback (most recent call last):
File "<pyshell#46>", line 1, in <module>
G.send(1024)
TypeError: can't send non-None value to a just-started generator
>>> next(G)
0
>>> G.send(1024)
1024
1
>>> G.send('s')
s
2
>>> next(G)
None
3
>>> next(G)
None
4
>>> next(G)
None
- 生成器表达式语法上类似于一般的列表解析,但他是括在圆括号中
- 集合解析
{f(x) for x in s}
等同于set(f(x) for x in s)
- 字典解析
{x:f(x) for x in items}
等同于dict((x, f(x)) for x in items)
>>> [x * 2 for x in "szn"]
['ss', 'zz', 'nn']
>>> (x * 2 for x in "szn")
<generator object <genexpr> at 0x00000000036E6EE8>
>>> list((x * 2 for x in "szn"))
['ss', 'zz', 'nn']
>>> {x * 2 for x in "szn"}
{'zz', 'nn', 'ss'}
>>> {x : x * 2 for x in "szn"}
{'s': 'ss', 'z': 'zz', 'n': 'nn'}
- 生成器函数和生成器表达式自身都是迭代器,并由此只支持一次活跃迭代,我们无法有在结果集中位于不同位置的多个迭代。
>>> def Fun():
for x in "szn":
yield x
>>> G0, G1 = Fun(), Fun()
>>> iter(G) is G
True
>>> it0, it1 = iter(G0), iter(G0)
>>> next(it0)
's'
>>> next(it1)
'z'
>>> next(G1)
's'
>>> G0 is G1
False
- 计时
>>> import time
>>> time.clock()
9.330551584887492e-07
>>> import time
>>> def Fun():
nT0 = time.clock()
time.sleep(0.1)
return time.clock() - nT0
>>> Fun()
0.09960021696645072
- 本地变量是静态检测的
>>> x = 'a'
>>> def Fun():
print(x)
x = 1
>>> Fun()
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
Fun()
File "<pyshell#4>", line 2, in Fun
print(x)
UnboundLocalError: local variable 'x' referenced before assignment
产生上述问题的原因在于被赋值的变量名在函数内部被当做本地变量来对待,而不是仅仅在赋值之后的语句中才被当做本地变量
- 默认参数是在def语句运行时评估并保存的,而不是在函数调用时
>>> def Fun(x = []):
x.append(1)
print(x)
>>> Fun()
[1]
>>> Fun()
[1, 1]
>>> Fun([2])
[2, 1]
>>> Fun()
[1, 1, 1]
网友评论