python进阶语法day7

1. 定义一个函数

def 函数名(形式参数列表):
    语句块

     注意实参要与形参个数一致。没有参数可以不填写。

python 函数的参数传递:

传不可变对象实例

通过内置的 id() 函数来查看内存地址变化:

python 中一切都是对象(后面会讲),严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

  • 什么是函数

    • 函数是可以重复执行的语句块,可以重复调用

  • 作用

    用于封装语句块, 提高代码的重用性。

  • 1.1 def 语句

  • 作用

    用来定义( 创建)函数

  • 语法

  • 说明

    1. 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()

    2. 函数名是一个变量,不要轻易对其赋值

    3. 函数有自己的名字空间,在函数外部不可以访问函数内部的变量,在函数内部可以访问函数外部的变量,但不能轻易对其改变

    4. 函数的形参列表如果不需要传入参数,形式参数列表可以为空

    5. 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

    6. 函数内容以冒号 : 起始,并且缩进。

    7. return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None

  • def max_nuber(a,b):
        if a > b:
            return a
        else:
            return b
    
    
    
    
    

    1.2 函数的调用

  • 语法
  • 函数名(实际调用传递参数)
  • 函数调用是一个表达式

  • 如果函数内没有return 语句,函数执行完毕后返回 None 对象

  • 注意实参要与形参个数一致。

  • def max_nuber(a,b):
        if a > b:
            return a
        else:
            return b
    max(2,5)
    print(max_nuber(2,5))
    
    
    
    5

    练习

  • 写一个函数 myadd, 此函数传入两个参数, x, y 
    次函数的功能是打印  x + y 的和:

  • def my_add(a,b):
        return a+b
    max = my_add(1,2)
    print(f'你输入的数据之和为{max}')
    
    
    
    
    你输入的数据之和为3

    1.3 return 语句

  • 语法
  • return [表达式]
  • 作用

    用于函数的内部,结束当前函数的执行,返回到调用此函数的地方,同时返回一个对象的引用关系

  • 说明

    1. return 语句后面的表达式可以省略,省略后相当于 return None

    2. 如果函数内部没有 return 语句, 则函数执行完毕后返回None, 相当于在最后一条语句后有一条return None

  • def my_add(a,b):
        return a+b
    max = my_add(1,2)
    print(f'你输入的数据之和为{max}')
    def return_none():
        return
    print(return_none())
    
    
    
    你输入的数据之和为3
    None

    2. 函数参数

    2.1 形参和实参

    形参:形参是函数定义时声明的参数,用于接收调用函数时传递的值。形参是函数内部的局部变量,只在函数体内有效。

    实参:实参是调用函数时传递给函数的具体值或变量。实参会传递给形参,从而在函数内部使用。

    示例:

  • def add(a, b):  # a 和 b 是形参
        return a + b
    
    result = add(3, 5)  # 3 和 5 是实参

    形参是函数定义时的占位符,用于描述函数需要接收的参数。

    实参是函数调用时传递的具体值,用于填充形参。

  • 2.3 可变参数与不可变参数

    可更改(mutable)与不可更改(immutable)对象

    在 python 中,strings, tuples, numbers,bool和None 是不可更改的对象,而 list,dict及set 等则是可以修改的对象。

  • 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。

  • 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

  • 不可变类型:值传递: 如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。

  • 可变类型:引用传递: 如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响

  • 不可变值的引用,类似c语言的值传递,对外部实参没影响

  • a = 10
    print(id(a))
    def id_a(a):
        print(id(a))
    id_a(a)
    
    
    140728933038808
    140728933038808
    a = 10
    def id_a(a):
        a += 1            #新生成的a
    id_a(a)
    print(a)             #没有影响a的值
    
    
    
    10
    
    
    
    

    可变引用id传递。有点像c语言指针,直接地址传递,会直接修改外面的值。

  • a = [1,2,3]
    print(id(a))
    def chage(a):
        a.append(4)
    chage(a)
    print(a)
    print(id(a))
    
    
    
    
    2407358716032
    [1, 2, 3, 4]
    2407358716032

    2.4 函数的形式参数定义方法

    形参的定义
  • 位置形参

  • 默认参数

  • 星号元组形参(*args)

  • 命名关键字形参

  • 双星号字典形参(**kwargs)

1)位置形参

位置形参是最常见的参数类型,它们按照定义的顺序传递给函数。

语法:

  def 函数名(形参名1, 形参名2, ...):
      pass

注意有多少传多少,与形参一致。

def a_b(a,b):
    return a+b
print(a_b(1,2))
a_b(1,2,3)
print(a_b(1,2))



3
Traceback (most recent call last):
  File "D:\study\python\pythonProject2\python\basic\python.day4.py", line 175, in <module>
    a_b(1,2,3)
TypeError: a_b() takes 2 positional arguments but 3 were given

如果想传递任意个参数,又不想修改函数本身呢?

2)缺省参数(默认参数)

在 Python 中,默认参数在函数定义时只计算一次。建议默认参数使用不可变对象,或将默认参数设置为 None,并在函数内部进行初始化。如果默认参数是一个可变对象(如列表或字典),可能会导致意外行为。

语法

def 函数名(形参名1=默认实参1, 形参名2=默认实参2, ... ):
     语句块

缺省参数即默认实参,必须自右向左依次存在(即,如果一个参数有缺省参数,则其右侧的所有参数都必须有缺省参数)

def a_b(a,b,c=0,d):
    return a+b

 def a_b(a,b,c=0,d):    #缺省参数后面必须是缺省参数
                    ^
SyntaxError: parameter without a default follows parameter with a default


def a_b(a,b,c=0,d=0):
    return a+b+c+d
a_b(1,2,3)
print(a_b(1,2,3))        #d默认为0


3)星号元组形参

星号元组形参允许函数接受任意数量的位置参数,并将这些参数打包成一个元组。

      • 语法

      • def 函数名(*元组形参名):
            pass

      • 作用

        收集多余的位置实参

        元组形参名一般命名为args

      • 示例

        def my_fun(*args):
            n=0
            for i in args:
                n +=i
            return n
        print(my_fun(1,2,3,4,5))
        
        
        
        15
        4)命名关键字形参

        命名关键字形参是指在函数定义中,必须通过关键字传递的参数。它们通常出现在 **args 之后。

      • 语法

      • def 函数名(*, 命名关键字形参1, 命名关键字形参2, ...):
            pass
        # 或者
        def 函数名(*args, 命名关键字形参1, 命名关键字形参2, ...):
            pass

      • *args 用于在函数定义中接收任意数量的位置参数,并将它们打包成一个元组(tuple)。

        * 是一个分隔符,用于在函数定义中分隔普通位置参数和命名关键字参数。它本身不接收任何参数,而是强制其后的参数必须通过关键字传递。

      • 作用

        强制,所有的参数都必须用关键字传参

        如果命名关键字参数在定义时指定了默认值(即缺省参数),则调用时可以不传递实参,函数会使用默认值。

        如果命名关键字参数在定义时没有指定默认值,则调用时必须传递实参,否则会抛出 TypeError

      • 示例

      • def key_func(*,a,b):
            return a+b
        print(key_func(1,2))           #非关键字命名传参 
        
        
        print(key_func(1,2))
                  ^^^^^^^^^^^^^
        TypeError: key_func() takes 0 positional arguments but 2 were given
        
        
        
        def key_func(*,a,b):
            return a+b
        print(key_func(a=1,b=2))
        
        
        
        3

      def myfunc4(a, b, *args, c, d):
          print(args)
          print(a, b, c, d)
      myfunc4(1, 2, d=4, c=3)			# 正确,c,d 必须关键字传参
      myfunc4(1, 2, 5, 6, d=4, c=3)   # 正确,c,d 必须关键字传参,5,6作为元组输入
      myfunc4(1, 2, 3, 4)   # 错误

      双星号字典形参允许函数接受任意数量的关键字参数,并将这些参数打包成一个字典。

      • 语法

      • def 函数名(**kwargs):
            pass

      • 作用

        收集多余的关键字传参

        字典形参名最多有一个,

        字典形参名 一般命名为 kwargs

      def my_fundic(**kwargs):
          print(kwargs)
      my_fundic(a=0,b=2,c=3)
      
      
      {'a': 0, 'b': 2, 'c': 3}

      2.4 函数的调用传参

      • 位置传参

        实际参数传递时,实参和形参按位置来依次对应

      • 关键字传参

        实际参数传递时,实参和形参 按名称依次对应

      注: 位置传参要先于关键字传参

      参数解包:

      如果调用时已经有一个元组或列表,可以使用 * 解包传递给函数;如果有一个字典,可以使用 ** 解包传递关键字参数。

      有点像指针。

      def myfun1(a, b, c):
          print('a=', a)
          print('b=', b)
          print('c=', c)
      
      ## 位置传参
      myfun1(1, 2, 3)
      ## 关键字传参
      myfun1(c=33, a=11, b=22)
      ## 位置传参要先于关键字传参
      myfun1(111, c=333, b=222)   # 正确
      
      # 序列实参:使用星号将序列拆分后,与形参进行对应
      # 序列实参的长度必须与形参的数量一致。
      list01 = [7,8,9]
      myfun01(*list01)
      
      # 字典实参:使用双星号将字典拆分后,依次与形参对应
      # 字典实参的键必须与形参的名称一致。
      dict01 = {"c":3,"b":2,"a":1}
      myfun01(**dict01)
      
      # 序列实参和字典实参混合使用
      list = [1]
      dic = {'b':2,'c':3}
      myfun1(*list, **dic)

      3. 返回值

      函数可以使用return语句来返回一个或多个值。

      如果没有明确的return语句,函数将默认返回None

      def fun1(x):
          return x * x,x
      print(fun1(5))
      
      
      
      (25, 5)

      4. 匿名函数

      在Python中,匿名函数通常使用lambda关键字来创建。匿名函数也被称为lambda函数,它是一种简单的、一行的函数,常用于临时需要一个小函数的地方。匿名函数的语法如下:

      语法

      lambda  [函数的参数列表]: 表达式

      • 作用

        • 创建一个匿名函数对象

        • lambda是关键字,表示你正在定义一个匿名函数。

        • 同 def 类似,但不提供函数名

        • [函数的参数列表]是函数的参数,可以有零个或多个参数,参数之间用逗号分隔。

        • : 表达式是函数的返回值,通常是一个表达式,匿名函数会计算这个表达式并返回结果。

      • 说明

        lambda 表达式 的创建函数只能包含一个表达式

      def add(a,b):
          return a+b
      add_1 = lambda x,y:x+y
      print(add_1(1,2))
      print(add(1,2))
      
      
      
      3
      3

      5. 变量作用域

      5.1 什么是变量作用域

      一个变量声明以后,在哪里能够被访问使用,就是这个变量"起作用"的区域:也就是这个变量的作用域

      一般来说,变量的作用域,是在函数内部和外部的区域 来体现,因此常常与函数有关

      5.2 局部变量和全局变量

      • 局部变量

        • 定义在函数内部的变量称为局部变量(函数的形参也是局部变量)

        • 函数内部的变量只能在函数内部或者函数内部的函数内部访问 ,函数外部不能访问

        • 局部变量在函数调用时才能够被创建,在函数调用之后会自动销毁

      • 全局变量

        • 定义在函数外部,模块内部的变量称为全局变量

        • 全局变量, 所有的函数都可以直接访问(取值,但函数内部不能直接将其赋值改变)

      • 局部变量示例

      • def add(a,b):
            return a+b
        result = add(1,2)
        print(a,b)
        
        
        
           print(a,b)
                  ^
        NameError: name 'a' is not defined

      • 全局变量示例

      • a = 100
        def add(b,c):
            return a+b+c
        result = add(1,2)
        print(a,result)
        
        
        
        100 103

        5.3 嵌套函数

        嵌套函数是指在一个函数内部定义的另一个函数。它可以像普通函数一样使用,但通常是作为外部函数逻辑的一部分,内部函数可以将一些复杂的逻辑隐藏在外部函数内部,只暴露必要的接口,隐藏实现细节,具有更强的局部化和封装性。

        嵌套函数的外部函数可以调用内部函数。

        函数也可以看作是定义在作用域中的数据,在执行函数的时候,要遵循:优先在自己的作用域中寻找,没有则返回到上一层的作用域寻找。

        示例1:定义两个全局函数func,execute,其中execute调用func

      • def fun():
            print('hello')
        
        def excute():
            fun()
            print('world')
        excute()

        现在定义两个func函数,一个在execute外部,一个在execute内部

      def fun():
          print('hello')
      def excute():
          def fun():
              print('world')
          fun()
      excute()
      
      world

      此时execute执行时优先执行函数内部的func,而不是执行全局的func。

      示例2:当同一作用域里面出现了两个同名函数时,后面的会将前面的同名函数覆盖。

      def fun():
          print('hello')
      
      def fun():
          print('world')
      fun()
      
      
      
      world

       示例3:当内部函数执行时需要变量,如果在局部作用域中找不到,则到上层作用域中找

      def fun1():
          name = 'zhangsan'
          def fun2():
              print(name)
          fun2()
      fun1()
      
      
      
      zhangsan

      示例4:嵌套函数可以访问外部函数的变量和参数,但外部函数不能直接访问内部函数的变量。

      def fun1():
          name = 'zhangsan'
          def fun2():
              age = 18
              print(f'name is {name},age is {age}')
          fun2()
          print(f'age is {age}')
      fun1()
      
      
      
      
        print(f'age is {age}')
                          ^^^
      NameError: name 'age' is not defined
      name is zhangsan,age is 18                

      总结:我内层找不到可以去外层找,但是外层找不到是真的找不到,不能进去找。

      5.4 作用域查找顺序(LEGB)

      LEGB 是 Python 中用于查找变量作用域的规则,它代表了四个不同的作用域层次:

      1. Local (局部作用域)

      2. Enclosing (嵌套作用域)

      3. Global (全局作用域)

      4. Built-in (内置作用域)

      Local (L):

      • 本地作用域,指当前函数内部的变量。

      • 当你在函数内部定义变量并尝试访问它时,Python 首先会在函数内部查找这个变量

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

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

      抵扣说明:

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

      余额充值