Python 函数引入

Python 函数:

由若干语句组成的语句块,函数名称,参数列表构成,它是组织代码的最小单元,完成一定功能。

函数定义,调用:

def 语句定义函数

def 函数名(参数列表: 函数体()代码块 [return 返回值] # 函数名就是标识符,命名要求一样 #语句块必须缩进,约定4 个空格 #Python 的函数没有return 语句,隐式会返回一个None值 #定义中的参数列表成为形式参数,只有一种符号表达,简称 形参 #调用 函数定义,只是声明了一个函数,它不会被执行,需要调用 调用的方式,就是函数名加上小括号,括号内写上参数 调用时写的参数是实际参数,是实实在在传入的值,就是 实参

函数参数

(1)位置参数:按照参数定义顺序传入实参

(2)关键字参数定义顺序传入实参

# 要求位置参数必须在关键字参数之前传入,位置参数是按位置对应的

(3)参数默认值

# 参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值

(4) 可变参数

# 从传入一个可迭代对象,迭代元素求和

# 一个形参可以匹配任意个参数

def add(nums):
    sum = 0
    for x in nums:
        sum += x
    return sum
def add(*nums):
    sum = 0
    print(type(nums))     #------>    收集多个参数为一个tuple
    for x in nums:
        sum += x
    return sum

(5) 可变参数

def showconfig(**kwargs):
    print(type(kwargs))   #------>   收集为一个字典
    for k,v in kwargs.items():
        print('{} = {}'.format(k,v))

(6) 高级应用,可变参数的混合使用(多加练习)

(7)Python 3 引入keyword-only 参数

# 如果在一个星号参数后面,或者一个位置可变参数后,出现的普通参数,实际上已经不是普通参数了,而是keyword-only参数

 #  特别注意此处的语法错误:
   def fn(**kwargs,x):
    print(x)
    print(kwargs)

(8)参数小规则

# 参数列表参数一般顺序是,普通参数,缺省参数,可变参数,可变位置参数,keyword-only参数(可带缺省值),可变关键字参数

(9)参数结构

def add(x,y):
    return x + y
t = (4,5)
add(t[0],t[1])
add(*t)
d = {'x':5,'y':6}
add(**d)

给函数提供实参的时候,可以在集合类型前使用*或者**,把集合类型的结构解开,提取出所有元素作为函数的实际参数,非字典类型使用 * 解构成为位置参数,字典类型使用 ** 解构成为关键字参数

习题小练习:

编写一个函数,能够接收至少两个参数,返回最小值和最大值

def fn(*nums):
    return max(nums),min(nums)

输入一个整数左右对齐打印

def show(n):
    tail = ' '.join([str(i) for i in range(n,0,-1)])
    width = len(tail)
    for i in range(1,n):
        print("{:>{}}".format(' '.join([str(j) for j in range(i,0,-1)]),width))
    print(tail)
show(12)
def showtail(n):
    tail = ' '.join([str(i) for i in range(n,0,-1)])
    print(tail)
    for i in range(len(tail)):
        if tail[i] == ' ':
            print(' '*i,tail[i+1:])  # ----->  切片的使用
showtail(12)

函数的返回值(结束函数调用,返回值)

# Python 函数使用return语句返回 “返回值”

# 所有函数都有返回值,如果没有return 语句,隐式调用 return None

# return 语句并不一定是函数的语句块的最后一条语句

# 一个函数可以存在多个return 语句,但是只有一条可以执行。如果没有一条return 语句被执行到,隐式调用return None

# 如果有必要,可以显示调用return None, 可以简写为return

# 如果函数执行了return 语句,函数就会返回,当前被执行的return 语句之后的其它语句就不会被执行

函数嵌套

# 函数有可见范围,这就是作用域的概念

# 内部函数不能被外部直接使用,会抛NameError 异常

作用域

# 一个标识符的可见范围,这就是标识符的作用域。一般常说的是变量的作用域

全局作用域

# 在整个程序运行环境中都可见

局部作用域

# 在函数,类等内部可见

# 局部变量使用范围不能超过其所在的局部作用域

闭包:

# python 3  nonlocal 关键字的使用
def counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc
foo = counter()
foo()
foo()
# 划重点
  # 使用了nonlocal 关键字,将变量标记为不在本地作用域定义,而在上级的某一级局部作用域中定义,但不能是全局作用域中定义

默认值的作用域

属性__defaults__ 中使用元组保存所有位置参数默认值,它不会因为在函数体内使用了它而发生改变

变量名解析原则:(LEGB)

# Local, 本地作用域,局部作用域的local 命名空间。函数调用时创建,调用结束消亡

# Enclosing ,Python2.2 时引入了嵌套函数,实现了闭包,这个就是嵌套函数的外部函数的命名空间

# Global , 全局作用域,即一个模块的命名空间。模块被import 时创建,解释器退出时消亡

# Build-in, 内置模块的命名空间,生命周期从python 解释器启动时创建到解释器退出时消亡。

函数的销毁:

# 全局函数销毁
     重新定义同名函数
    del  语句删除函数对象
    程序结束时
#局部函数销毁
  重新在上一级作用域定义同名函数
  del  语句删除函数对象
  上级作用域销毁时

非线性结构,每个元素可以有多个前驱和后继

# 有序树:节点的子树是有顺序的,不能交换

# 无序树:结点的子树是无序的,可以交换

二叉树

每个结点最多2课子树

斜树

左斜树,所有结点都只有左子树

右斜树,所有节点都自由右子树

满二叉树

# 一颗二叉树的所有分支结点都存在左子树和右子树,并且所有叶子结点只存在在最下面一层

完全二叉树

# 满二叉树一定是完全二叉树,但完全二叉树不是满二叉树

# 若二叉树的深度为k, 二叉树的层数从1到k-1层的结点数都达到了最大个数,在第k 层的所有结点都集中在最左边,这就是完全二叉树。

函数执行流程

(流程演示: http://pythontutor.com/visualize.html#mode=display

递归Recursion

    函数直接或者间接调用自身就是递归
    递归需要有边界条件,递归前进段,递归返回段
    递归一定要有边界条件
    当边界条件不满足的时候,递归前进
    当边界条件满足的时候,递归返回
# 小练习:
    def fib(n):
    return 1 if n < 2 else fib(n-1) + fib(n-2)
for i in range(5):
    print(fib(i),end=' ')
  注意:
    递归有深度限制,如果递归复杂,函数反复压栈,栈内存很快就溢出
    
pre = 0
cur = 1
print(pre,cur,end=' ')
def fib(n,pre=0,cur=1):
    pre,cur = cur,pre + cur
    print(cur,end=' ')
    if n == 2:
        return
    fib(n-1,pre,cur)
fib(7)
# 添加判断条件,类循环写法

间接递归

# 通过别的函数调用了函数自身

(要用代码的规范来避免这种递归调用的发生)

匿名函数

Python 借助 Lamdba 表达式构建匿名函数

lamdba 表达式(匿名函数) 只能写在一行上,被称为单行函数

主要就是在高阶函数传参数时候,使用lamdba 表达式,往往能简化代码

(lambda x,y=3:x + y)(5)

[x for x in (lambda *args:map(lambda x:x+1,args))(*range(5))]
[x for x in (lambda *args:(x+1 for x in args))(*range(5))]
[x for x in (lambda *args:map(lambda x:(x+1,args),args))(*range(5))]

生成器

生成器generator

# 生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yied关键字得到一个生成器函数,调用这个函数得到一个生成器对象

生成器函数

#函数体中包含yield语句的函数,返回生成器对象

# 生成器对象,是一个可迭代对象,是一个迭代器

# 生成器对象,是延迟计算,惰性求值的

普通的函数调用fn() ,函数会立即执行完毕,但是生成器函数可以使用next函数多次执行

生成器函数等价于生成器表达式,只不过生成器函数可以更加的复杂

# 小练习:
def fib():
    x = 0
    y = 1
    while True:
        yield y
        x,y = y,x+y
foo = fib()
for _ in range(5):
    print(next(foo))
for _ in range(10):
    next(foo)
print(next(foo))
pre = 0
cur = 1
print(pre,cur,end=' ')
def fib1(n,pre=0,cur=1):
    pre,cur = cur,pre + cu
    print(cur,end=' ')
    if n == 2:
        return
    fib1(n-1,pre,cur)
fib1(10)

yield from

yield from 是Python 3.3 出现的新语法

yield from iterable 是 for item in iterable:yield item 形式的语法糖

def inc():
    for x in range(1000):
        yield x
foo = inc()
print(next(foo))
print(next(foo))
print(next(foo))
def inc():
    yield from range(1000)
foo = inc()
next(inc())
id(foo),id(inc)

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券