风清扬

导航

Python之路(三)——函数

本节内容

  1. 函数基本语法及特性
  2. 参数
  3. 局部变量
  4. 返回值
  5. 嵌套函数
  6. 递归
  7. 匿名函数
  8. 高阶函数
  9. 高级函数
  10. 内置函数

一、函数基本语法和特性

定义

函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

特性

  1. 减少重复代码
  2. 使程序变的可扩展,称作"解耦"
  3. 使程序变得易维护

基本语法

def cal(x,y):
    '''
    计算两个数的和
    :param x: 第一个数,可以是整数或者浮点数
    :param y: 第二个数,可以是整数或者浮点数
    :return:  x+y的值
    '''
    return x+y

print(cal(2,3)) # 5

二、参数

默认参数

def incre(x, step=1):
    '''
    返回一个数 + 10次step 的值
    :param x: 一个数
    :param step:  默认需要累加的基础值
    :return:
    '''
    for i in range(10):
        x += step
    return x

print(incre(5)) # 15
print(incre(5,2)) # 25  

非默认参数必须在默认参数之前,否: SyntaxError: non-default argument follows default argument

位置参数与关键字参数传递

users = []
def add_user(u_id,u_name,u_passwd='123'):
    '''
    新增用户,添加到users 列表中
    :param u_id: 用户id
    :param u_name: 用户名
    :param u_passwd: 用户密码
    :return: 多用户列表
    '''
    users.append({
        "u_id": u_id,
        "u_name": u_name,
        "u_passwd": u_passwd,
    })
    return users

#调用程序代码
if __name__ == '__main__':
    add_user(1,'alex1') # 按照位置传递参数 u_id = 1,u_name='alex1',默认参数u_passwd='123'
    add_user(2,u_name='alex2',u_passwd='abc')# 按照位置和关键字参数类型混合传递
    print(users)
# [{'u_id': 1, 'u_name': 'alex1', 'u_passwd': '123'}, {'u_id': 2, 'u_name': 'alex2', 'u_passwd': 'abc'}]    

注意:

  1. 函数定义中'varname=var'形式为默认参数,区别于位置参数
  2. 位置参数必须在关键字参数之前

非固定参数传递

有时参数的数量,传递形式(位置,关键字)不可知。

非固定位置参数用*args表示,非固定关键字参数用**kwargs表示。其中:*,**强制要求,args,kwargs 是约定俗称的参数名

*:打包所有位置参数,组成一个元祖,赋值给args;**:打包所有关键字参数,组成一个字典,赋值给kwargs

def stu_register(id, *args, **kwargs):
    '''
    注册一个学生,打印学生信息
    :param id: 学生id
    :param args: 学生其他信息,采用元祖形式保存
    :param kwargs: 学生其他信息,采用字典形式保存
    :return:
    '''
    # print(id, *arg, **kwargs)
    print(id, args, kwargs)#Alex ('男', 22) {'province': 'ShanDong', 'major': '计算机'}

stu_register("Alex", '男', 22, province="ShanDong", major="计算机")
#传参步骤
    # 1.位置参数匹配 id = "Alex"
    # 2.'男', 22没有固定位置参数匹配,打包成一个元组统一传输给可变位置参数args,至此所有位置参数匹配完毕
    # 3.province="ShanDong"关键字参数传递,无:打包成字典,统一传递给可变关键字参数kwargs   

解包与不解包

非固定长度参数传递中,存在传递的参数本身为元祖或者字典的情况。

解包:对传递的元祖或者字典处理,分割成单个参数进行传递

非解包:不对传递的元祖或者字典处理,作为一个整体进行传递

def stu_register(id, *args, **kwargs):
    '''
    注册一个学生,打印学生信息
    :param id: 学生id
    :param args: 学生其他信息,采用元祖形式保存
    :param kwargs: 学生其他信息,采用字典形式保存
    :return:
    '''
    # print(id, *arg, **kwargs)
    print(id, args, kwargs)

stu_register("Alex", '男', 22, province="ShanDong", major="计算机")
#Alex ('男', 22) {'province': 'ShanDong', 'major': '计算机'}

#传参步骤
    # 1.位置参数匹配 id = "Alex"
    # 2.'男', 22没有固定位置参数匹配,打包成一个元组统一传输给可变位置参数args,至此所有位置参数匹配完毕
    # 3.province="ShanDong"关键字参数传递,无:打包成字典,统一传递给可变关键字参数kwargs

#如果,参数本身已经是元祖或者字典形式, 如果需要传递前解包,元祖解包 * ,字典解包 **
tuple_stu_info = ('男', 22, ) #一般都会在最后一个元祖加',' 区分函数调用
dic_stu_info = {'province': "ShanDong", 'major':"计算机"}
stu_register("Alex", *tuple_stu_info, **dic_stu_info)
#同上:Alex ('男', 22) {'province': 'ShanDong', 'major': '计算机'}

#元组不解包,字典解包
stu_register("Alex", tuple_stu_info, **dic_stu_info)
# Alex (('男', 22),) {'province': 'ShanDong', 'major': '计算机'}
#字典不解包,元组解包
stu_register("Alex", *tuple_stu_info, dic_stu_info)
# Alex ('男', 22, {'province': 'ShanDong', 'major': '计算机'}) {}
#都不解包
stu_register("Alex", tuple_stu_info, dic_stu_info)
# Alex (('男', 22), {'province': 'ShanDong', 'major': '计算机'}) {}

三、局部变量

定义在函数内部的变量称 局部变量,变量定义时没有格式缩进的变量称 全局变量。其中:参数是函数的局部变量

变量作用域

变量可以被使用的范围,即变量的有效范围

  • L(Local) 局部作用域
  • E(Enclosing) 嵌套函数外的函数中
  • G(Global)全局作用域
  • B(Built-in)内建作用域

查找顺序:  按照 L –> E –> G –>B依次寻找

name = "刚娘"
def weihou():
    name = "沉着"
    weihou_name ="燥起来"
    print(name,weihou_name)
    def weiweihou():
        global name #只改全局,不改局部
        name = "冷静"
        nonlocal  weihou_name
        weihou_name = "李云龙"
        # nolocal name #报错: global ,nolocal 起指示作用,变量名还是唯一的
    weiweihou()
    print(name,weihou_name)
print(name)
weihou()
print(name)
#
# 刚娘
# 沉着 燥起来
# 沉着 李云龙
# 冷静

四、返回值

要想获取函数的执行结果,就可以用return语句把结果返回

注意:

  1. 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,可以理解为 return 语句代表着函数的结束
  2. 如果未在函数中指定return,那这个函数的返回值为None 

五、嵌套函数

函数定义中有另外一个函数的定义

六、递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自身,这个函数就是递归函数。

# 汉诺塔的移动可以用递归函数非常简单地实现。
#
# 请编写move(n, a, b, c)函数,它接收参数n,表示3个柱子A、B、C中第1个柱子A的盘子数量,然后打印出把所有盘子从A借助B移动到C的方法,例如:

def move(n, a, b, c):
    if n == 1:
        print(a,'--->',c)
        return

    move(n-1,a,c,b)
    move(1,a,b,c)
    move(n-1,b,a,c)
# 期待输出:
# A --> C
# A --> B
# C --> B
# A --> C
# B --> A
# B --> C
# A --> C

move(3, 'A', 'B', 'C')

尾递归

递归函数逻辑表达清晰,但太耗内存(不断保存上一次栈的状态)。变相提出了尾递归,即在返回的时候计算出下次函数被调用的值替代表达式。

#递归
def jiecheng(n):
    if n == 1:
        return 1
    else:
        return n * jiecheng(n-1) #返回值有同名函数表达式

#尾递归
def jiecheng2(n,product=1):
    if n == 1:
        return product
    else:
        return jiecheng2(n-1,n*product) #无函数表达式,理论上可以单独调用。但python没有优化

print(jiecheng2(10000)) # RecursionError: maximum recursion depth exceeded in comparison  

七、匿名函数

匿名函数就是不需要显式定义的函数,用于临时使用的简易逻辑函数

#求一个数的平方
cal = lambda x:x**2
print(cal(5)) # 25 

八、高阶函数

函数的参数or返回值是一个函数,这种函数就称之为高阶函数。常用于装饰器

#高阶函数
def cal(f, x, y):
    return f(x, y)

def add(x, y):
    return x + y

def div(x, y):
    return divmod(x, y)

print(cal(add, 2, 3)) # 5
print(cal(div, 5, 3)) # (1, 2)

九、高级函数

函数递归、高阶函数、高级函数是函数式编程的主要特色,原则不要重复造轮子。 本小节主要介绍 filter、map、functools.reduce以及for 推导式

1.找到长度不唯一的单词,并首字母大写,用,连接成字符串输出
employees = ['neal','s','stu','j','rich','bob','aiden','j','ethan','liam']
l = ','.join(map(lambda i:i.capitalize(),filter(lambda i:len(i)>1,employees)))
print(l) # Neal,Stu,Rich,Bob,Aiden,Ethan,Liam
#1.2
print(','.join(i.capitalize() for i in employees if len(i)>1)) #更加方便

#2. [‘adam’, ‘LISA’, ‘barT’]转换首字母大写,其他小写
l = ['adam', 'LISA', 'barT']
l = list(map(lambda i:i.capitalize(),l))
print(l)
#2.1
print([i.capitalize() for i in l])

#3.[1,3,5,6,7,10,2,5] 求乘积
l = [1,3,5,6,7,10,2,5]
import functools
print(functools.reduce(lambda x,y:x*y,l))

#4.求5000..10000 之间的回数
print([i for i in range(5000,10000) if str(i)== str(i)[::-1]])

#5. 1. 100 整除2 不能整除4的数,做平方
print(list(map(lambda i:i**2,filter(lambda x:x%2==0 and x%4 !=0,[i for i in range(100)]))))
#5.2 for 列表形式。简单元素处理可以取代 map ,filter(if)
print([i**2 for i in range(100)if i%2==0 and i%4!=0])
#取最长单词
s = ('dfsa','dsafdsaffdf','sad','adfdsaf')
functools.reduce(lambda a,b:a if len(a)>len(b) else b,s)

十、内置函数

Python解释器的内置函数(无论什么地方,什么时间都可以使用

posted on 2018-06-08 17:06  卜戈的博客  阅读(231)  评论(0编辑  收藏  举报