7、函数

# def 函数名(参数列表):   函数名-标识名-指向一个函数对象
#     函数体(代码块)
#     [return 返回值]

形参

  1. 位置传参

    可有缺省值,定义时,若没有提供该参数,动用缺省值,缺省值定义往后放;

    缺省值也叫默认值;

5种

  1. 普通形参:可有缺省值,2种传实参方式都可用;
  2. *args (元组): 可变位置形参,只能接受按照位置传入的实参,可接收0个或任意个,没缺省值;
  3. **kwargs {字典}: 可变仅关键字形参,只能接收关键字传入的实参,可接收0个或任意个,放到最后边,没缺省值;
  4. keyword-only形参*args*之后,只仅仅能接收关键字传入实参,缺省值,无所谓前后;
  5. 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
posted on 2023-07-08 20:15  anyu967  阅读(12)  评论(0)    收藏  举报