python函数/参数/参数结构/匿名函数/生成器函数


python函数由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元

函数的作用:
结构化编程对代码的最基本的封装,一般按照功能组织一段代码
封装的目的为了复用,减少冗余代码使代码更加简洁美观、可读易懂

函数定义

def 函数名(参数列表):
函数体(代码块)
[return 返回值]

  1. 函数名就是标识符,命名要求一样,语句块必须缩进,约定4个空格
  2. Python的函数若没有return语句,会隐式返回一个None值
  3. 定义中的参数列表称为形式参数,只是一种符号表达(标识符),简称形参

函数调用
函数定义,只是声明了一个函数,它不能被执行,需要调用执行
调用的方式,就是函数名后加上小括号,如有必要在括号内填写上参数。调用时写的参数是实际参数,是实实在在传入的值,简称实参。


函数参数
函数在定义是要约定好形式参数,调用时也提供足够的实际参数,一般来说,形参和实参个数要一致(可变参数除
外)。
传参方式有4种,分别是:

1.位置传参
定义时def f(x, y, z), 调用使用 f(1, 3, 5),按照参数定义顺序传入实参
2.关键字传参
用了形参的名字。传参时可以位置可以不一样。注:有位置参数和关键字传参的时候,位置参数要在关键字参数前。位置参数是按位置对应的

 *args 可变位置参数

可以接受多个实际参数,将收集来的实参组织到一个tuple中

  1. **kwags 可变关键字参数,
    将收集来的实参组成个字典
  2. 可变位置参数和可变关键字参数都可以收集若干个实参,可变位置参数收集形成一个tuple,可变关键字参数 收集形成一个dict,
def ad(x,y,z=4,*args,k=5,**kwargs):
    print(x,y,z,k)
    print(args)
    print(kwargs)

参数解构

  1. 在给函数提供实参的时候,可以在可迭代对象前使用 * 或者 ** 来进行结构的解构,提取出其中所有元素作为 函数的实参
  2. 使用 *解构成位置传参
  3. 使用 ** 解构成关键字传参
  4. 提取出来的元素数目要和参数的要求匹配
    参数解构只能在传实参的时候使用。

顺序为:普通参数,缺省值,可变位置参数,关键字参数,可变位置关键字参数

例子:
1、编写一个函数,能够接受至少2个参数,返回最小值和最大值
2、完成一个函数,可以接收输入的多个数,每一次都能返回到目前为止的最大值、最小值。

1>
def add(x,y,*args):
    max_num = max(x,y,*args)
    min_num = min(x,y,*args)
    return max_num,min_num
import random
print(add(*[random.randint(10, 20) for i in range(random.randint(2, 10))]))


2>
def test():
    max_ = min_ = None
    while True:
        num = input('>>>').replace(',',' ').split()
        sums = [int(s) for s in num]
        if num is None:
            continue
        if max_ is None:
            max_=min_=sums[0]
        max_=max(max_,*sums)
        min_ = min(min_,*sums)
        print(max_,min_)
test()

函数返回值

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

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

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

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

  • 返回值作用:结束函数调用,返回‘返回值’

  • 函数不能同时返回多个值,如果返回多个值,隐式的被python封装成了一个元组

函数作用域***

作用域

一个标识符的可见范围,这就是标识符的作用域,一般常说的是变量的作用域
函数的封装会开辟一个作用域,变量如果被限制在这个作用域中,则外部函数变量不可见
注意: 每一个函数都会开辟一个作用域

作用域分类
  • 全局作用域
      • 在整个程序运行的环境中都可见
      • 全局作用域中的变量称为全局变量
  • 局部作用域
      • 在函数、类等内部可见
      • 局部作用域中的变量称为局部变量,其使用范围不能超过其所在的作用域
函数嵌套

global使用原则

外部作用域变量会在内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是 为了封装,尽量与外界隔离
如果函数需要使用外部全局变量,请尽量使用函数的形参定义,并在调用传实参解决
不用global!

闭包

自由变量: 未在本地作用域中定义的变量。函数可以嵌套的,所以自由变量未必是全部变量
闭包:指的是内层函数引用到了外层函数的自由变量

如果要对这个普通变量使用闭包,Python3中可以使用nonlocal关键字
nonlocal 只能作用于当前作用域,不能用于全局变量,只用于嵌套内层函数
形参就是标识符,就是变量,就是本地变量

-- 全局变量
def counter():
    global count
    count = 0
    def inc():
        global count
        count += 1
        return count
	return inc
foo = counter()
print(foo(), foo())

--nonlocal使用局部变量
def counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc
foo = counter()
print(foo(), foo())

递归Recursion
  • 函数直接或者间接调用自身就是 递归

  • 递归需要有边界条件,递归前进段、递归返回段

  • 递归一定要有边界条件

  • 当边界条件不满足的时候,递归前进

  • 当边界条件满足的时候,递归返回

    斐波那契数列:

def fib(n):
    return 1 if n <= 1 else fib(n - 1) + fib(n - 2)

递归要求

  • 递归一定要有退出条件,递归调用一定要执行到这个退出条件。没有退出条件的递归,就是无限调用
  • 递归调用的深度不宜过深
    • python对递归调用的深度做了限制,以保护解释器
    • 超过递归深度限制,抛出recursionError:maxinum recursion depth exceedd超出最大深度

习题:
1、求n的阶乘
2、将一个数逆序放入列表中,例如1234-》[4,3,2,1]
3 、猴子吃桃问题

1. 阶乘
from functools import reduce
print(reduce(lambda x, y: x * y, range(1, 5)))
1. 递归:
def jc(n):
    if n < 2:
        return 1
    return jc(n - 1) * n
print(jc(1))

2.
def petch(day=10):
    if day == 1:
        return 1
    return 2 * (petch(day-1) +1)

print(petch())

3.
data = [1, 2, 3, 4]
def sor(data):
    if not data:
        return []
    return [data[-1]] + sor(data[:-1])
print(sor(data))

或者列表做
def sor(data):
    li = []
    for i in range(len(data),0 , -1):
        li.append(i)
    return li
print(sor(data))



匿名函数

lambda函数

  • 匿名函数:没有名字的函数。可以进行函数调用,传入的都是可调用对象,一般用于高阶函数,
  • 如sorted格式为 lambda [参数列表]: 表达式
    冒号后不能出现等号
  • 参数列表不需要小括号。无参就不写参数
  • 冒号用来分割参数列表和表达式部分 不需要使用return。表达式的值,就是匿名函数的返回值。表达式中不能出现等号 lambda表达式(匿名函数)只能写在一行上,也称为单行函数

如果太复杂则使用其他函数,

生成器

生成器generator

  • 生成器指的是生成器对象,可以由生成器表达式得到,也可以使用yield关键字得到的一个生成器函数,调用这个函数得到一个生成器对象
  • 生成器对象,是一个可迭代对象,是一个迭代器
  • 生成器对象,是延迟计算,惰性求值

** 生成器函数 **

  • 函数体中包含yield语句的函数,就是生成器函数,调用后返回生成器对象
m = (i for i in range(5)) # 生成器表达式
print(next(m))

--生成器函数
def inc()
	for i in range(5):
	yield i 
g = inc()
for i in g:
	print(i)

普通函数的调用,函数会立即执行直到执行完毕。
生成器函数调用,并不会立即执行函数体,而是需要使用next 函数来驱动生成器函数,执行后获得生成器对象,
生成器表达式和生成器函数都可以的到生成器对象,只不过生成器函数可以写的更加复杂的逻辑

生成器函数实现斐波那契数列:

def fibs(n):
    a = 0
    b = 1
    for i in range(n):
        a, b = b, a + b
    return b
print(fibs(5))

--改造
def fibs():
    a = 0
    b = 1
    while True:
        yield b
        a, b = b, a + b

fi = fibs()
for i in range(5):
    print(next(fi))

yield from语法

yield from iterable 等价于 for item in iterable : yield item

yield from 是一种简化语法的语法糖

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

# 改进 ---等价

def incs():
    yield from range(1000)
fe = incs()
print(next(fe))
print(next(fe))

本质上yield from的意思就是,从from后面的可迭代对象中拿元素一个个yield出去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值