zoukankan      html  css  js  c++  java
  • (3)什么是函数(函数的定义、形参、实参、默认形参、可变长函数args kwargs,私有地址)

    什么是函数

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

    1、减少重复代码

    2、使程序变的可扩展

    3、使程序变得易维护

    定义函数的语法

    形参

    主要的作用就是接受实参参数的传递,并且被语法调用  #形参只有在被调用时才内存单元,在调用解释时,即可释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

    实参

    主要的作用就是讲参数传递给形参    #实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,他们都必须有确定的值,以便把这些值传递给形参。因此应预先用赋值,输入等办法使参数获得确定值

    定义函数的形参,并且将实参传递给形参再调用

    def calc(x,y):  #def关键词,calc函数名,括号里的是形参

      res = x**y

      return res

    c = calc(a,b)    #括号里的是实参,传递给x和y

    print(c)

    位置形参:指的是在函数定义阶段按照从左到右的顺序依次定义的形参

    特点: 必须被传值,多一个不行,少一个也不行

    位置实参: 指的是在函数调用阶段按照从左到右的顺序依次传入的值

    特点: 与形参一一对应

    形参也可以是默认值

    def calc(x,y=2)   #这样在函数调用时如果形参不指定参数,则在调用时就是默认值,如果指定,则是指定值

     默认参数(默认形参): 在函数定义阶段,就已经为形参赋值

    特点: 在定义阶段就已经有值,意味着在调用阶段可以不用传值

    注意: 可以混用位置形参与默认形参,但是

    1、位置形参必须放在默认形参前面

    2、默认形参的值只在函数定义阶段赋值一次,定义之后的任何改动都无法影响默认形参的值

    3、默认形参的值通常应该是不可变类型

    关键字参数

    一般情况下,给函数传参数时要按顺序,不想按顺序就可以用关键字参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),关键字参数必须放在位置参数(以位置顺序确定对应关系的参数)之后

    关键字参数(单指关键字实参): 在函数调用阶段,按照key=value形式为指定的形参赋值

    特点: 可以完全打乱传值的顺序,但仍然能指名道姓地为指定的形参赋值

    注意:可以混用位置实参与关键字实参,但是

    1、不能为同一个形参重复赋值

    2、位置实参必须放在关键字实参的前面

    PS:位置参数就是形参没有指定任何值,所以函数调用时候是按照位置传递的,关键字参数就是指定形参的默认值,所以必须放在位置参数的后面,不然在函数传递时候按照位置传递,会出现错误

    例:def stu_register(name,age,course='Py',counter='CN'):  #def是函数定义关键字,结尾必须用:结束,这是强制语法

      print("姓名:", name)

      print("年龄:", age)

      print("课程:" ,course)

      print("国籍:", counter)

    stu-register(‘Karl’,course='Py',age=22,counter='JP')  #这里Karl没有用赋值去指定赋值给哪一个形参,所以必须对应形参的位置,而后面的实参都有赋值给指定的形参,所以可以不用按位置写

    可变长参数

    指的是在调用函数时传入的值(实参)个数不固定,而实参无非两种,一种位置实参

    另外一种就是关键字实参,针对这两种形式实参的个数不固定,对应着形参也应该有两种解决方案来分别应对溢出位置实参(*)与关键字实参(**)

    若在函数的定义时不确定用户想传入多少个参数,就可以使用非固定参数(*args和*kwargs)

    *args会把多传入的参数变成一个元组形式

    def stu(name,age,*args)

      print(name,age,args)

    stu('Karl',22)

    输出的结果就是Karl 22()  #输出结果后面有一个(),元组符号,这个就是args,因为没有传入任何值,所以就是一个空元组

    **kwargs 会把多传入的参数变成一个dict的形式(字典形式)

    def stu(name,age,*args,**kwargs)

      print(name,age,args,kwargs)

    stu('Karl',22,'cn','Py',sex='male')

    输出结果就是Karl 22 ('cn', 'Py') {'sex': 'male'}

    PS:*args前面是一个*,**kwargs前面是两个*,args传入时候单个字符串即可,而kwargs传入的时候必须以键值(key=value)传入(即字典形式传入)

    PS:*args和**kwargs其实就是前面的*起作用,后面的名称只是约定俗成的名字(可以随便写),这样所有开发人员看到这个就知道一个是传入元祖,一个是将值变成关键字传入

    PS:在实参中出现*: 但凡是在实参中出现*,都将*后的值打算成位置实参,然后再进行赋值

    PS:在实参中出现**: 但凡是在实参中出现**,都将**后的值打算成关键字实参,然后再进行赋值

    PS:在形参中出现**: **会将溢出的关键实参存成字典的形式,然后赋值紧跟其后的形参

    PS:在形参中出现*: *会将溢出的位置实参存成元组的形式,然后赋值紧跟其后的形参

    例:利用可变长参数在函数体内调用另一个函数的时候,将实参传递给被调用的函数

    def index(a,b,c):   #先定义一个有形参的函数
      print('from index',a,b,c)  #执行打印形参

    def wrapper(*args,**kwargs):   #这里再定义一个函数带有可变长参数
      index(*args,**kwargs)    #直接调用上面的函数并且形参定义成可变长参数

    wrapper(1,c=3,b=2)   #在调用的时候将wrpper实参传递给形参,然后在传递给调用的index的形参

    PS:这里由于wapper函数执行的就是调用index

    列:利用位置参数传递

    def index(a,b,c):
      print('from index',a,b,c)   #这个函数执行的操作

    def wrapper(name,age,sex):  #这个带有形参的函数
      index(name,age,sex)   #这里调用函数时候的形参必须是这个函数块的形参

    wrapper('karl','123','male')   #这里按照位置实参传递

    PS:这是一个相互传递的过程,调用时候将位置实参传递给形参,然后再传递给调用的函数

    命名关键字形参:

    在定义函数阶段,但凡是在*与**之间的参数称之为命名关键字形参

    特点: 必须被传值, 并且在传值时必须按照key=value的形式传值

    例:

    def func(x,*args,m=111,n,**kwargs): 

      print(x)

      print(m)

      print(n)

      print(kwargs)

      print(args)

    func(1,1,2,3,4,n=3,a=5,b=6)

    PS:参数的顺序,先写位置,再写默认(*前面的才是默认参数),然后写*args,再跟关键字参数(*后面的是带有默认值(无默认值)的关键字参数),最后跟**kwargs

    PS:位置实参必须按照位置传递,关键字和*和**之间则无需按照位置,位置后面如果没有传递默认参数的值,也没有传递关键字参数,则会将所有溢出字符传递给*,如果是k=v的值全部溢出的传递给**

    返回值(return)

    函数外部代码想要获取函数的执行结果,就可以在函数里用return语句把结果返回

    def stu_register(name,age,course='Py',counter='CN'):

      print("姓名:" ,name)

      print("年龄:" ,age)

      print("课程:" ,course)

      print("国籍:" ,counter)

      if age > 22:  #这里输出一个判定条件,用return返回后面的结果

        return False

      else:

        return True

    s_reg = stu_register(‘Karl’,course='Py',age=22,counter='JP')

    if s_reg:

      print('注册成功')

    else:

      print('年龄太大‘’)

    PS:函数在执行过程中只要遇到return语句,就会停止执行并返回结果,return语句就是函数运行结束的一个语句,如果未在函数中指定return,那么这个函数的返回值为None

    全局变量和局部变量

    1、在函数中定义的变量就是局部变量,在程序的一开始定义的变量称为全局变量

    2、全局变量的作用域是整个程序,局部变量作用域就是定义该变量的函数

    3、当全局变量与局部变量同名时,在定义局部变量的函数内,局部变量起作用,在其他地方则是全局变量起作用

    name = 'Alex'   #这个是全局变量

    def change_name(name):

      print('beore change:',name)

      name ='Karl'  #这个是局部变量,只给下面的调用

      print('after change:',name)

    change_name(name)

    作用域

    作用域(scope),通常来说,一段 程序代码中所用到的名字并不总是有效/可用的,而限定这个民资的可用性的代码范围就是这个名字的作用域

    global 声明全局变量函数

    def change_name():  #这里没有定义形参

      global name     #用global 函数声明name就是全局变量

      name ='Karl'    

      print('after change:',name)

    change_name()   #用为用了global全局函数声明变量name,所以这里也可以打印name

    嵌套函数

    name = 'Alex'

    def change_name():  

      name = 'Alex2'

      def change_name2():

        name = 'Alex3'

        print('第三层:',name)

      change_name2()

      print('第二层:',name)

    change_name()

    print('最外层:',name)

    PS:函数嵌套的调用也是需要按照层级来依次调用的,如果在第二层调用第三层则会报错,所以第二层只能调用第二层

    匿名函数(lambda)

    匿名函数就是不需要显式的指定函数名

    通常函数的调用

    def calc(x,y)

      return x**y

    print(clac(2,5))

    采用匿名函数

    calc = lambda x,y:x**y

    print(calc(2,5))

    匿名函数的主要用法是和其他函数搭配使用

    res = map(lambda x:x**2,[1,5,7,4,8])  #这里直接定义了一个变量的计算过程,用lambda函数定义X,冒号后面传递一个计算的方式,最后用列表定义x的值

    for i in res:

      print(i)

    闭包函数

    什么是闭包函数=>函数嵌套+函数对象+名称空间与作用域

    闭:定义在函数内的函数

    包:该内部函数需要访问一个名字,该名字属于外层函数作用域的(强调:不是全局作用域)

    为何要用闭包函数?

    为了实现装饰器

    如何用闭包函数

    def outter(name): #定义函数

      x = ‘456’

      print(x)  #

      def inner():   #函数内嵌套一个函数

        print(‘成功调取这一层值’)

      return inner   #返回函数,不能加括号,加了括号就是调取函数的功能,不加括号就是返回一个函数的内存空间地址

    f = outter()  #outter内最后将inner的内存地址做返回结果,所以outter函数的只会返回inner的内存空间地址,这里outter就是inner的内存空间地址并且赋值给f

    f()  #这里调用f就获得了inner局部变量的值

    PS:首先定义一个函数,然后在下层定义一个函数,最后返回下层函数的内存空间地址给全局函数,然后将全局函数的赋值给一个变量

    PS:由于全局函数outter下层有一个打印值,所以在打印f的时候也会打印出来

    高阶函数

    变量可以指向函数,函数的参数能接受变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

    只要满足以下任意一个条件,即是高阶函数

    1、接受一个或多个函数作为输入

    2、return返回另一个函数

    def add(x,y,f):

      return f(x) + f(y)

    res = add(3,-6,abs)

    print(res)

    递归函数

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

    特性:

    1、必须有一个明确的结束条件

    2、每次进入更深一层的递归时,问题规模相比上次递归都应有所减少

    3、递归效率不高,栈就会增加一层栈帧,每当函数返回,栈就会减一层栈。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出

    def calc(n):

      print(n)

      if int(n/2) == 0:

        return n

    return calc(int(n/2)

    calc(10)

    私有地址  # 只能在函数的内部获取

    定义方式 __funcname # 私有地址的命名方式就是在函数名前加__

    在函数的内部调用方式  

    class FTPHandler():
    def handle(self):
    print('1')
    if hasattr(self,"_FTPHandler__get"): # hasattr判断如果有这个函数名,调用私有地址的方式是_父类名+私有地址的函数名将名字拼成私有地址的格式
    print('yes')
    else:
    print('没有找到')

    def __get(self):
    '''私有地址函数'''
    print('123')

    ftp = FTPHandler()
    ftp.handle()
  • 相关阅读:
    git三种模式及常用命令
    git remote
    页面中添加qq客服
    用ubuntu里的vim搭建一个apache2+php+mysql环境一路踩的坑
    jQuery无new创建对象原理
    国崛战略
    计算机公开课推荐 2019.8
    Unable to preventDefault inside passive event listener due to target being treated as passive 怎么办?
    VUE事件修饰符.passive、.capture、.once实现原理——重新认识addEventListener方法
    看各类框架源码淘来的一些JavaScript技巧
  • 原文地址:https://www.cnblogs.com/shizhengquan/p/9928100.html
Copyright © 2011-2022 走看看