一周学python系列(5)——函数

函数

基础
  • 函数的作用:减少代码重复,实现代码复用

  • 函数的使用步骤:

    1. 定义函数

      def 函数名(参数):
          代码1
          代码2
          ...
      

      空函数

      def nop():
      	pass
      
      # pass关键字可用来作为占位符
      
      
    2. 调用函数

      函数名(参数)
      

      注意:

      1.参数为可选项,可有可无

      2.在python中,函数必须先定义后调用,如果先调用会报错

      3.如果没有调用函数,函数里面的代码不会执行

  • 函数的参数

    调用函数时,若传入的参数数量不对,或参数类型不能被函数所接受,会报TypeError的错误

    # 定义函数时同时定义接收用户的数据a,b a和b是形参
    def add(a,b):
        res = a + b
        print(res)
    
    # 调用函数时调用用户的真实数据10和20,真实数据是实参
    add(10,20)   # 30
    
  • 函数的返回值

    在函数中,如果需要返回结果给用户需要使用函数返回值

    return会返回结果给函数调用的地方

    return负责函数返回值,且会退出当前函数,即导致return下方的函数体内部不执行

    def sum(a,b):
        return a + b
    # 用return变量保存函数返回值
    result = sum(100,50)
    print(result)  # 50
    
  • 函数的说明文档

    函数的说明文档也叫函数的文档说明,可更方便的查看函数的注释即作用

    1. 定义函数的说明文档

      def 函数名(参数):
          """说明文档的位置"""
          代码
          ...
      
    2. 查看函数的说明文档

      help(函数名)
      
    def sum(a,b):
      """求和函数"""
      return a + b
    
    help(sum)
    '''
    运行结果:
    sum(a, b)
        求和函数
    '''
    
    
  • 函数嵌套调用

    函数嵌套调用指一个函数里面又调用另外一个函数

    # 1.打印多条横线
    
    def pri_line():
        print('-' * 20)
    
    def pri_lines(num):
        for i in range(num):
            pri_line()
    
    pri_lines(5)
    
    '''
    结果为:
    --------------------
    --------------------
    --------------------
    --------------------
    --------------------
    '''
    
    # 2.求三个数平均数
    # 先求和
    def sum(a,b,c):
        return a + b + c
    
    def avg(a,b,c):
        return sum(a,b,c)/3  # 调用求和函数
    
    res = avg(10,10,10)
    print(res)  # 10.0
    
进阶
  • 变量作用域

    变量作用域指的是变量生效的范围,主要分为两类 : 局部变量全局变量

    1. 局部变量

      所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效

      def test():
          a = 100
          print(a)
      
      test()  # 100
      
      print(a)  # 报错 NameError: name 'a' is not defined
      

      变量a是定义在test函数内部的变量,属于局部变量,在函数外部访问则立即报错

      局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量

    2. 全局变量

      所谓全局变量,指的是在函数体内、外都能生效的变量

      # 定义全局变量a
      a = 100
      
      def test():
          print(a)
      
      test()  # 100
      
      def testb():
          global a # 声明a为全局变量
          a = 200
          print(a)
          
      testb()   # 200
      
      print(a)  # 200
      
      
      '''
      注意:
      1.如果在函数内部修改变量a,此时a并不是全局变量a的修改,而是相当于在函数内部声明一个新的局部变量
      2.若想函数体内部修改全局变量,需先global声明a为全局变量,然后再重新赋值,才能修改成功
      '''
      
      
      
  • 返回值作为参数传递

    def test1():
        return 100
    
    def test2(a):
        print(a)
    
    # 保存函数test1的返回值
    res = test1()
    
    # 将函数test1的返回值作为参数传递到函数test2
    test2(res)   # 100 
    
  • 函数的返回值

    若遇到一个函数有多个返回值的情况,应采用retrun a,b的写法

    def test():
        return 1,2
    
    res = test()
    print(res)  # (1,2)
    
    1. return a,b的写法,返回多个数据的时候,默认是元组类型
    2. return后可以连接列表、元组或字典,以返回多个值
  • 函数的参数

    1. 位置参数

      调用函数时根据函数定义的参数位置来传递参数

      传递和定义参数的顺序和个数必须一致

      def user(name,age):
          print(f'您的姓名是{name},年龄是{age}')
      
      user('Tom',21)
      user('Tom')   # 报错 个数定义和传递不一致  TypeError:user() missing a required psitional argument:'age'
      
    2. 关键字参数

      函数调用,通过key=value的键值对形式加之指定。可以让函数更加清晰、容易使用,同时消除参数的顺序要求

      def user(name,age):
          print(f'您的姓名是{name},年龄是{age}')
      
      user('Tom',21)     # 您的姓名是Tom,年龄是21
      user(age=21,name='Tom')    # 您的姓名是Tom,年龄是21
      

      函数调用时,如果有位置参数,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序

    3. 缺省参数

      缺省参数也称为默认参数,用于定义函数,为参数提供默认值,调用函数时可不传递该默认参数的值(注:所有位置参数必须出现在默认参数前,包括函数定义和调用)

      def user(name,age=16):
          print(f'您的姓名是{name},年龄是{age}')
      
      user('Tom',21)    # 您的姓名是Tom,年龄是21
      user('Tom')        # 您的姓名是Tom,年龄是16
      

      注意:函数调用时,如果为缺省参数传值则修改默认参数值;否则使用默认值

    4. 不定长参数

      不定长参数也称为可变参数。用来解决不确定嗲用时需要传递多少个参数(包括不传参)的情形。这种情形下,可用包裹(packing)位置参数,或包裹关键字参数,来进行参数传递。

      包裹位置传递

      def user(*args):
          print(args)
          
      user(11)  # (11,)
      user(11,14)   # (11,14)
      user()   # ()
      

      注意:包裹位置传递采用*args,传递的所有参数都会被args参数收集,他会根据传进参数的位置合并为一个元组,args是元组类型。

      包裹关键字传递

      def user(**kwargs):
          print(kwargs)
          
      user(name='Tom',age=18,id=1001)
      # {'name':'Tom','age':18,'id':1001}
      

      包裹关键字传递采用**kwargs,kwargs是字典类型

      无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程,即收集零散数据,返回一个整体

  • 拆包

    1. 拆包:元组

      def test():
          return 1,2
      
      a,b = test()    # 拆包
      print(a)   # 1
      print(b)   #2
      
    2. 拆包:字典

      dict1 = {'name':'Tom','age':18}
      
      a,b = dict1
      
      # 对字典进行拆包,取出来的是字典的key
      print(a)   # name
      print(b)   # age
      
      print(dict[a])   # Tom
      print(dict[b])   # 18
      
  • 交换变量值

    # 有变量a = 10 和b = 20,交换两个变量的值
    
    # 方法一:借助第三变量存储数据
    a,b = 10,20
    # 1.定义中间变量c
    c = 0
    
    # 2.将a的数据存储到c
    c = a
    
    # 3.将b的数据20赋值到a,此时a = 20
    a = b
    
    # 4.将c的数据10赋值到b,此时b = 10
    b = c
    
    print(a)  # 20
    print(b)  # 10
    
    
    # 方法二:
    a,b = 10,20
    a,b = b,a
    print(a)   # 20
    print(b)   # 10
    
  • 引用

    在python中,值是依靠引用来传递的

    id():判断两个变量是否为同一个值的引用,可将id理解为内存的地址标识

    # 1. int类型  不可变类型
    a = 1
    b = a
    
    print(b)   # 1
    
    # a和b的id值相同
    print(id(a))   # 2081153024240
    print(id(b))   # 2081153024240
    
    a = 2
    print(b)  # 1 说明int类型为不可变类型
    # 修改a的值,内存要开辟另一块内存存储2,id检测到a和b的地址不同
    
    # 2.列表类型   可变类型
    c = [1,2]
    d = c
    
    print(d)   # [1,2]
    
    print(id(c)) # 1896861660480
    print(id(d)) # 1896861660480
    
    c.append(20)
    print(c)    # [1, 2, 20]
    
    print(id(c))   # 1896861660480
    print(id(d))   # 1896861660480
    # id值相同,且与修改数据之前相同
    

    引用可以当做实参使用

    不可变类型计算前后id值不同

    可变类型计算前后id值相同

    可变类型:

    1. 列表
    2. 字典
    3. 集合

    不可变类型:

    1. 整型
    2. 浮点型
    3. 字符串
    4. 元组
递归

递归是一种编程思想,在函数内部,可以调用其他函数,如果函数在内部调用其自身,该函数就是递归函数

  • 特点:

    1. 函数内部自己调用自己
    2. 必须有出口
  • 示例:

    # 计算n!
    def fact(n):
        if n == 1:
            return 1
        else:
            return n * fact(n-1)
    
    print(fact(3))   # 6 正确
    
  • 注意:

    使用递归函数需要注意防止栈溢出,在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

    解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

    尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

lambda表达式

如果一个函数有一个返回值,且只有一句代码,可使用lambda简化

  • lambda语法

    lambda 参数列表 : 表达式
    

    lambda表达式的参数可有可无,函数的参数在lambda表达式中完全适用

    lambda表达式能接收任何数量的参数但只返回一个表达式的值

    # 函数
    def fn1():
        return 100
    
    print(fn1)   # <function fn1 at 0x000002C802233E20>
    print(fn1())   # 100
    
    
    
    # lambda表达式
    fn2 = lambda : 200
    
    print(fn2)   # <function <lambda> at 0x000002C80234E8C0>
    print(fn2())   # 200
    # 直接打印lambda表达式,输出的是lambda的内存地址
    
  • 参数

    1. 无参数

      f = lambda : 100
      print(f())
      
    2. 单参数

      f = lambda a : a
      print(f(1))  # 1
      
    3. 默认参数

      f = lambda a,b,c = 100 : a + b + c
      print(f(1,2))   # 103
      
    4. 可变参数:*args

      f = lambda *args : args
      print(f(10,20))   # (10,20)
      
    5. 可变参数:**kwargs

      f = lambda **kwargs : kwargs
      print(f(name='python',age=10))
      # {'name':'python','age':10}
      
  • lambda应用

    # 带判断的lambda
    f = lambda a,b : a if a > b else b
    print(f(10,50))   # 50
    
    # lambda表达式支持三目运算符
    
高阶函数

把函数作为另一个函数的参数传入,这样的函数称为高阶函数,高阶函数是函数式编程的体现。函数式编程是指高度抽象的编程范式。

abs(100)是函数调用,而abs是函数本身

函数本身也可以赋值给变量,即变量可以指向函数

变量可指向函数,而函数的参数能接收变量,所以一个函数可以接收另一个函数作为参数,此函数称之为高阶函数

# abs()   绝对值
abs(-10)   # 10

# round()  四舍五入计算
round(3.6)   # 4

# 任意两个数字,按照指定要求整理数字后在进行求和计算
# 绝对值后进行求和计算
# 方法一:
def add(a,b):
    return abs(a) + abs(b)
print(add(1,-10))   # 11

# 方法二:
def sum(a,b,f):
    return f(a) + f(b)
res = sum(1,-10,abs)
print(res)  # 11

res1 = sum(1.1,2.1,round)
print(res1)  # 3
map/reduce

python内置函数map()reduce()

map()

map()函数接收两个参数,一个是函数,一个是Iterable,map()将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator(迭代器)返回

def f(x):
    return x * x

r = map(f,[1,2,3,4])
list(r)
# [1,4,9,16]

reduce()

reduce()函数把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算

注意:reduce()传入的参数func必须接收2个参数

# reduce(f,[x1,x2,x3,x4]) = f(f(f(x1,x2),x3),x4)

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

reduce(add,[1,3,5,7,9])   # 25

# 将序列[1,3,5,7,9]变换成整数13579
del f(x,y):
    return x * 10 + y

reduce(f,[1,3,5,7,9])   # 13579
filter

python内置的filter()函数用于过滤序列,过滤掉不符合条件的元素,返回一个filter对象,若要转换为列表,可使用list()转换

和map()类似,filter()接收一个函数和一个序列,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素

# 在一个list中,删除偶数,保留奇数
def is_ok(n):
    return n % 2 == 1
print(list(filter(is_ok,[1,2,3,4,5,6,7,8,9])))
# [1, 3, 5, 7, 9]
sorted

=sorted(list,key= ,reverse= )

python内置的sorted()函数可对list进行排序

sorted([36, 5, -12, 9, -21])
# [-21, -12, 5, 9, 36]

sorted()函数作为高阶函数,可接收一个key函数来实现自定义排序,其关键在于实现一个映射函数

其中,key指定的函数将作用于list的每个元素上,并根据key函数返回的结果进行排序,并按照对应关系返回list相应的元素

第三个参数reverse=True可进行反向排序

# sorted()
sorted([36, 5, -12, 9, -21])
# [-21, -12, 5, 9, 36]

# sorted()作为高阶函数,实现自定义排序
# 按绝对值大小排序
sorted([36, 5, -12, 9, -21], key=abs)
# [5, 9, -12, -21, 36]

# 对该列表按名字排序
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
    return t[0]
L2 = sorted(L, key=by_name)  
print(L2)   # [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]

# 按成绩从高到底排序
def by_score(t):
    return -t[1]
L3 = sorted(L, key=by_score)
print(L3)   # [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Python的计算思维训练主要涉及到函数的概念。函数Python中的基本编程结构,通过函数可以将一系列操作封装起来,提高代码的复用性和可维护性。 首先,函数的定义和调用是计算思维中重要的一部分。习者需要理解如何使用def关键字定义函数,并且会传入参数和返回数值。这能够帮助他们将复杂的问题拆分成更小的部分,然后再分别解决。 其次,函数的参数和返回值的运用是培养计算思维的有效途径。习者需要理解函数的参数可以是任意类型的数据,也可以是默认值,还可以是可变数量的参数。同时,他们需要掌握函数可以返回单个数值、多个数值或者其他函数的能力。 此外,函数的嵌套和递归是培养计算思维的重要方法。习者需要了解函数可以在其内部调用其他函数,从而实现更复杂的功能。而递归则可以帮助他们理解问题的分治和循环求解策略。 最后,函数的高阶用法和闭包也是培养计算思维的关键。习者需要明白函数可以作为参数传递给其他函数,也可以作为返回值被另一个函数使用。此外,他们还需要掌握闭包的概念和运用,以便更好地理解函数的作用域和生命周期。 通过习和实践以上内容,习者不仅可以掌握Python函数的用法,还可以培养出较强的计算思维能力,从而更好地应对复杂的问题和挑战。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值