Python中的函数参数类型

技术交流QQ群:1027579432,欢迎你的加入!

  • 1.参数命名规则经验:绝大多数函数接收一定数量的参数,然后根据实际调用时提供的参数的值的不同,输出不同的结果。前面我们说过,将函数内部的参数名字,定义得和外部变量的名字一样是一种不好的习惯,它容易混淆思维,甚至发生错误。
  • 2.位置参数(必传参数/位置参数)
    • 必须在调用函数时明确提供的参数!位置参数必须按先后顺序,一一对应,个数不多不少的传递
      x, y, z = 1, 2, 3
      
      def add(a, b, c):
      
          return a+b+c
      
      add(x, y, x)        # 使用变量,传递参数
      add(4, 5, 6)        # 直接传递值也是可以的
      
    • 上面例子中的a,b,c就是位置参数,我们在使用add(4, 5, 6)调用时,就是将4传给a,5传给b,6传给c的一一对应传递。类似add(4, 5, 6, 7)、add(4)和add(5, 4, 6)这种“画蛇添足”、“缺胳膊少腿”和“嫁错郎”类型的调用都是错误的。其中,add(5, 4, 6)的调用在语法上没问题,但是输出结果可能和预期的不一致。注意: Python在做函数参数传递的时候不会对数据类型进行检查,理论上你传什么类型都可以!
  • 3.默认参数
    • 在函数定义时,如果给某个参数提供一个默认值,这个参数就变成了默认参数,不再是位置参数了。在调用函数的时候,我们可以给默认参数传递一个自定义的值,也可以使用默认值。
      def power(x, n = 2):
          return x**n
      
      ret1 = power(10)   # 使用默认的参数值n=2
      ret2 = power(10, 4)  # 将4传给n,实际计算10**4的值
      
    • 上面例子中的n就是个默认参数。默认参数可以简化函数的调用,在为最常用的情况提供简便调用的同时,还可以在特殊情况时传递新的值。但是在设置默认参数时,有几点要注意:
      • 默认参数必须在位置参数后面
      • 当有多个默认参数的时候,通常将更常用的放在前面,变化较少的放后面。
      • 在调用函数的时候,尽量给实际参数提供默认参数名。
      • 使用参数名传递参数
        • 通常我们在调用函数时,位置参数都是按顺序先后传入,而且必须在默认参数前面。但如果在位置参数传递时,给实参指定位置参数的参数名,那么位置参数也可以不按顺序调用,例如:
              def student(name, age, classroom, tel, address="..."):
                  pass
              
              student(classroom=101, name="Jack", tel=66666666, age=20)
          
      • 默认参数尽量指向不变的对象!
        def func(a=[]):
        a.append("A")
        return a
        
        print(func())
        print(func())
        print(func())
        # 输出结果:
        ['A']
        ['A', 'A']
        ['A', 'A', 'A']
        
        • 原因分析:因为Python函数体在被读入内存的时候,默认参数a指向的空列表对象就会被创建,并放在内存里了。因为默认参数a本身也是一个变量,保存了指向对象[]的地址。每次调用该函数,往a指向的列表里添加一个A。a没有变,始终保存的是指向列表的地址,变的是列表内的数据! 解决方法使用不可变的数据类型作为默认值!将默认参数a设置为一个类似None,数字或字符串之类的不可变对象。在函数内部,将它转换为可变的类型,比如空列表。这样一来,不管调用多少次,运行结果都是['A']了。
          def func(a=None):
              # 注意下面的if语句
              if a is None:
                  a = []
              a.append("A")
              return a
          
          print(func())
          print(func())
          print(func())
          
  • 4.动态参数
    • 动态参数就是传入的参数的个数是动态的,可以是1个、2个到任意个,还可以是0个。在不需要的时候,你完全可以忽略动态函数,不用给它传递任何值。
    • Python的动态参数有两种,分别是*args和**kwargs,这里面的关键是一个和两个星号的区别,而不是args和kwargs在名字上的区别,实际上你可以使用*any或**whatever的方式。但就如self一样,默认大家都使用*args和**kwargs。
    • 注意:动态参数,必须放在所有的位置参数和默认参数后面!
      def func(name, age, sex='male', *args, **kwargs):
      pass
      
    • 4.1 *args
      • 一个星号表示接收任意个参数。调用时,会将实际参数打包成一个元组传入形式参数。如果参数是个列表,会将整个列表当做一个参数传入。例如:
        def func(*args):
            for arg in args:
                print(arg)
        
        func('a', 'b', 'c')
        
        li = [1, 2, 3]
        func(li)
        
      • 通过循环args,我们可以获得传递的每个参数。但是li这个列表,我们本意是让它内部的1,2,3分别当做参数传递进去,但实际情况是列表本身被当做一个整体给传递进去了。怎么办呢?使用一个星号!调用函数,传递实参时,在列表前面添加一个星号就可以达到目的了。实际情况是,不光列表,任何序列类型数据对象,比如字符串、元组都可以通过这种方式将内部元素逐一作为参数,传递给函数。而字典,则会将所有的key逐一传递进去。
        def func(*args):
            for arg in args:
                print(arg)
        
        li = [1, 2, 3]
        func(*li)
        
    • 4.2 **kwargs
      • 两个星表示接受键值对的动态参数,数量任意。调用的时候会将实际参数打包成字典。例如:
        def func(**kwargs):
            for kwg in kwargs:
                print(kwg, kwargs[kwg])
                print(type(kwg))
        
        func(k1='v1', k2=[0, 1, 2])
        
      • 而如果我们这样传递一个字典dic呢?我们希望字典内的键值对能够像上面一样被逐一传入。使用两个星号!
        def func(**kwargs):
            for kwg in kwargs:
                print(kwg, kwargs[kwg])
        
        dic = {
            'k1': 'v1',
            'k2': 'v2'
        }
        
        func(**dic)
        
    • 4.3 “万能”参数
      • 当*args和**kwargs组合起来使用,理论上能接受任何形式和任意数量的参数,在很多代码中我们都能见到这种定义方式。需要注意的是,*args必须出现在**kwargs之前
        def func(*args, **kwargs):
        
            for arg in args:
                print(arg)
        
            for kwg in kwargs:
                print(kwg, kwargs[kwg])
        
        
        lis = [1, 2, 3]
        dic = {
            'k1': 'v1',
            'k2': 'v2'
        }
        
        func(*lis, **dic)
        
    • 4.4 关键字参数
      • 对于*args和**kwargs参数,函数的调用者可以传入任意不受限制的参数。比如:
        def func(*args):
            pass
        
        func("haha", 1, [], {})
        func(1,2,3,4,5,6)
        
      • 对于这样的参数传递方式,虽然灵活性很大,但是风险也很大,可控性差,必须自己对参数进行过滤和判定。例如下面我只想要姓名、年龄和性别,就要自己写代码检查:
        def student(name, age, **kwargs):
            if 'sex' in kwargs:
                student_sex = kwargs['sex']
        
      • 但是实际上,用户仍然可以随意调用函数,比如student("jack", 18, xxx='male'),并且不会有任何错误发生。而我们实际期望的是类似student("jack", 18, sex='male')的调用。那么如何实现这种想法呢?可以用关键字参数!关键字参数前面需要一个特殊分隔符*将位置参数和默认参数分隔开来,*后面的参数被视为关键字参数。在函数调用时,关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。不同于默认参数,关键字参数必须传递,但是关键字参数也可以有缺省值,这时就可以不传递了,从而简化调用
        def student(name, age, *, sex):
            pass
        
        student(name="jack", age=18, sex='male')
        
      • 如果函数定义中已经有了一个*args参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了。
        def student(name, age=10, *args, sex, classroom, **kwargs):
            pass
        
        student(name="jack", age=18, sex='male', classroom="202", k1="v1")
        
  • 5.博客原文
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349