7、函数
# def 函数名(参数列表): 函数名-标识名-指向一个函数对象
# 函数体(代码块)
# [return 返回值]
形参
-
位置传参
可有缺省值,定义时,若没有提供该参数,动用缺省值,缺省值定义往后放;
缺省值也叫默认值;
5种
普通形参
:可有缺省值,2种传实参方式都可用;*args (元组)
: 可变位置形参,只能接受按照位置传入的实参,可接收0个或任意个,没缺省值;**kwargs {字典}
: 可变仅关键字形参,只能接收关键字传入的实参,可接收0个或任意个,放到最后边,没缺省值;keyword-only形参
:*args
或*
之后,只仅仅能接收关键字传入实参,缺省值,无所谓前后;position-only形参
: / 之前,仅仅接收位置传入参数;
除了可变参数外,都可以有缺省值,定义时,如果没有提供缺该参数,动用缺省值;
仅位置和普通参数,一起算,缺省值的定义往后放;
仅关键字参数,缺省值无所谓先后;
def fn(x, y, *args, **kwargs):
print(x, y, args, kwargs, sep='\n', end='\n\n')
fn(3, 5, 7, 9, 10, a=1, b='abc')
3
5
(7, 9, 10)
{'a': 1, 'b': 'abc'}
fn(3, 5)
3
5
()
{}
fn(3, 5, 7)
3
5
(7,)
{}
fn(3, 5, a=1, b='abc')
3
5
()
{'a': 1, 'b': 'abc'}
fn(x=1, y=2, z=3)
1
2
()
{'z': 3}
# fn(x=3, y=8, 7, 9, a=1, b='abc') # 错在位置传参必须在关键字传参之前
# fn(7, 9, x=3, a=1, b='abc') # 错在7和9已经按位置传参了,x=3, y=5又重复传参了
def fn(*args, x, y, **kwargs):
print(x, y, args, kwargs, sep='\n', end='\n\n')
# fn(3, 5, 7) # fn() missing 2 required keyword-only arguments: 'x' and 'y'
fn(3, 5, y=6, x=7, a=1, b='abc')
7
6
(3, 5)
{'a': 1, 'b': 'abc'}
def fn(a, /):
print(a, sep='\n')
fn(3)
3
# fn(a=4) # fn() got some positional-only arguments passed as keyword arguments: 'a'
def sum(iterable):
s = 0
for x in iterable:
s += x
return s
print(sum([1, 3, 5]))
print(sum(range(4)))
9
6
def sum(*args):
sum = 0
for x in args:
sum += x
return sum
print(sum(1, 3, 5))
9
def showconfig(**kwargs):
for k, v in kwargs.items():
print('{}={} '.format(k, v), end='')
showconfig(host='127.0.0.1', port=8080, username='wayne', passwd='mageedu')
host=127.0.0.1 port=8080 username=wayne passwd=mageedu
def bar(a, b, /, c, d=10, *args, m=100, n, **kwargs):
print(a, b, c, d, '|', m, n, args, kwargs)
bar(1, 2, x=7, n=2, c=3)
1 2 3 10 | 100 2 () {'x': 7}
# 重要的参数列在前面,最长改变的参数尽量往前方
# position-only /、普通参数、缺省参数、可变位置参数、ketword-only *arrgs/*参数(可带缺省值)、可变关键字参数
def config(host, username='wanyue', password='wanyue', *, port=3306, **options):
db = options.pop('db', 'test')
connstr = "mysql://{}:{}@{}:{}/".format(username, password, host, port, db)
print(connstr)
config('192.168.0.1', 'root', '123456', port=3361, db='cmdb')
mysql://root:123456@192.168.0.1:3361/
7.1 参数解构
def add(x, y):
print(x, y)
return x + y
add(4, 5)
4 5
9
t = 4, 5
add(t[0], t[1])
4 5
9
add(*t) # 解构为按位置参数
4 5
9
add(*(4, 5))
4 5
9
add(*[4, 5])
4 5
9
add(*range(4, 6))
4 5
9
add(*{'a':10, 'b':11}) # 解构为按关键字传参
a b
'ab'
add(**{'x':10, 'y':11})
10 11
21
def add(*iterable):
result = 0
for x in iterable:
result += x
return result
add(1, 2, 3)
6
add(*[1, 2, 3])
6
add(*range(5))
10
# z =100
# def fn1():
# # global z
# print(z)
# m = z+1
# print(m)
# z = z + 1 # 标识符 赋值即定义 局部变量,未定义就赋值了 UnboundLocalError: local variable 'z' referenced before assignment
# print(z)
# fn1()
z = 100
def fn2():
z = 300
print(z)
y = z + 1
print(y)
fn2()
300
301
8、闭包
# 自由变量:未在本地作用域定义的变量。例如定义在内层函数外的外层函数的作用域中的变量
# 闭包:出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包。
# 1、每一次函数执行都是独立的;
# 2、函数调用完毕后,局部变量消亡;
def inc():
a =(100,)
c = [0] # 自由变量
print(hex(id(c)))
def inner():
c[0] += 1 # 元素
print(a)
return c[0]
return inner # 没调用,返回inner的内存地址
foo = inc()
print(foo, foo.__name__, type(foo.__name__))
print(foo.__closure__) # 闭包作用:存储要用到的外部自由变量
print(1, foo()) # foo指向inc的地址,是一个函数,就可以加括号执行;
print(2, foo())
0x2ebc99dbe00
<function inc.<locals>.inner at 0x000002EBC9C04430> inner <class 'str'>
(<cell at 0x000002EBC9B288E0: tuple object at 0x000002EBC95345B0>, <cell at 0x000002EBC9B284C0: list object at 0x000002EBC99DBE00>)
(100,)
1 1
(100,)
2 2
# def inc():
# c = 0
# def inner():
# # nonlocal c
# c += 1 # UnboundLocalError: local variable 'c' referenced before assignment
# return c
# return inner
# f = inc()
# print(1, f())
# print(2, f())
# nonlocal var, 声明var 不在当前作用域;
# 变量名解析原则
## LEGB Local-->Enclosing-->Global-->Bulit-in(print str list int range Exception生命周期和解释器相同;
# 匿名函数
# lambda arguments : expression
(lambda :0)()
0
# (lambda x, /, *, y=10: x + y)(y=11, x=5) # / 之前的按位置传参
# <lambda>() got some positional-only arguments passed as keyword arguments: 'x'
(lambda x, *, y=10: x + y)(y=11, x=5)
16
(lambda *args: [i for i in args])(range(5)) # (*range(5))
[range(0, 5)]
map(lambda x:(str(x), x+1), range(5))
<map at 0x21bf54858b0>
dict(map(lambda x:(str(x), x+1), range(5)))
{'0': 1, '1': 2, '2': 3, '3': 4, '4': 5}
{str(i):i+1 for i in range(5)}
{'0': 1, '1': 2, '2': 3, '3': 4, '4': 5}
{k:[] for k in 'abcde'}
{'a': [], 'b': [], 'c': [], 'd': [], 'e': []}
dict(map(lambda k:(k, []), 'abcde' ))
{'a': [], 'b': [], 'c': [], 'd': [], 'e': []}
from collections import defaultdict
d2 = defaultdict(list) # [] list()
# d2 ==> defaultdict(list, {})
print(d2) # ==> defaultdict(<class 'list'>, {})
print(d2['t']) # ==> []
d2['t'].extend(range(5)) # d2['t'] KeyError, 会创建d2['t']=list() ==>[]
print(d2)
defaultdict(<class 'list'>, {})
[]
defaultdict(<class 'list'>, {'t': [0, 1, 2, 3, 4]})
d3 = defaultdict(lambda :list()) # [] list()
# d3 ==> defaultdict(<function __main__.<lambda>()>, {})
print(d3) # ==> defaultdict(<function <lambda> at 0x0000016FA75FAD30>, {})
print(d3['t']) # ==> []
d3['m'].append(100) # d3['m'] KeyError, 会创建d['m']=(lambda :list())() ==> list() ==> []
print(d3)
defaultdict(<function <lambda> at 0x0000016FA9B37430>, {})
[]
defaultdict(<function <lambda> at 0x0000016FA9B37430>, {'t': [], 'm': [100]})
x = ['a', '1', 'b', '20', 'c', 32]
print(sorted(x, key=lambda x:x if isinstance(x, int) else int(x, 16)))
['1', 'a', 'b', 'c', '20', 32]
# sorted?
# sorted(iterable, /, *, key=None, reverse=False)
8、生成器函数
8.1 生成器对象
- return,结束函数并返回结果;
- 生成器表达式,每一次生成器表达式执行一次都会得到一个全新的生成器对象;
- 生成器函数,每一次调用都会得到全新的生成器对象,只要有yield语句的函数都是生成器函数;
- 生成器函数每执行一次到yield这一句,把yield的值返回
def foo():
print(1)
yield 2
print(3)
yield 4
print(5)
return 6
yield 7
x = foo() # 生成器函数调用不再直接执行,并不返回结果,而是得到生成器对象
print(type(x), x)
r = next(x)
print(1, type(r), r)
<class 'generator'> <generator object foo at 0x0000020F33328900>
1
1 <class 'int'> 2
def inc():
def foo():
count = 0
while True:
count += 1
yield count
c = foo() # 生成器对象
return c
x = inc()
print(next(x))
print(next(x))
print(next(x))
1
2
3
def inc():
def foo():
count = 0
while True:
count += 1
yield count
c = foo() # 生成器对象
# def fn():
# return next(c)
# return fn
return lambda :next(c)
x = inc()
print(x) # x-->fn
print(x())
print(x())
print(x())
<function inc.<locals>.<lambda> at 0x0000020F34E61B80>
1
2
3
def fib():
a = 1
yield a
b = 1
yield b
while True:
a, b = b, a + b
yield b
f = fib() # 生成器对象
for i in range(10):
print(i + 1, next(f))
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
10 55
"".join(map(str, range(5)))
'01234'
9、递归
> 函数直接或者间接调用自身是递归
> 递归要有边界条件、递归前进段、递归返回段
> 递归一定要有边界条件
# 版本1
def get_values_1(x, y, *args):
t = (x, y, *args)
return min(t), max(t)
# 版本2
def get_values_2(x, y, *args):
head, *_, tail = sorted((x, y, *args))
return head, tail
import random
x = list(range(10000))
random.shuffle(x)
x[:10]
print(x[:10])
print(*x[:10])
[1588, 8196, 544, 814, 6050, 5332, 1512, 1347, 1301, 9123]
1588 8196 544 814 6050 5332 1512 1347 1301 9123
# 斐波那契数列
def fib1(n):
a = b = 1
for i in range(n-2):
a, b = b, a+b
return b
fib1(10)
55
# 递归 <==公式
def fib2(n):
if n < 3:
return 1
return fib2(n-1) + fib2(n-2)
fib2(10)
55
# n 阶乘
def factorial_1(n):
s = 1
for i in range(n, 1, -1): # n -1次
s *= i
return s
def factorial_2(n):
s = 1
for i in range(2, n+1):
s *= i
return s
print(factorial_1(5))
120
# 递归 <==循环
def factorial_3(n, s=1): # 2, 1
# s = s*n
if n == 1:
return s
return factorial_3(n-1, s*n) # f(2-1. 1*2)
print(factorial_3(5))
# 递归 <==公式
def factorial_4(n):
if n == 1:
return 1
return factorial_4(n-1) * n
print(factorial_4(5))
120
120
'''
猴子第一天摘下若干个桃子,当即吃了一半,又多吃一个;
第二天早上又将剩下的桃子吃掉一半,又多吃了一个,以后每天早上都吃了前一天
剩下的一半零一个
到第十天早上想吃时,只剩下一个桃子,求日一天共摘多少个桃子
'''
'''
假设猴子摘了x桃
d1 x//2 -1
d2 d1//2 -1
d3 d2//2 -1
...
d9 d8//2 -1
d10 1
'''
x = 1
for i in range(9):
x = 2 * (x + 1)
print(x)
1534
# 递归 <==循环
def peach(days=10, x=1):
# = 2 * (x + 1)
if days == 1:
return x
return peach(days-1, 2 * (x + 1))
print(peach())
1534
# 递归 <==公式
def peach(days):
if days == 1:
return 1
return 2 * (peach(days - 1) +1)
print(peach(10))
1534
本文来自博客园,作者:anyu967,转载请注明原文链接:https://www.cnblogs.com/anyu967/articles/17537780.html