zoukankan      html  css  js  c++  java
  • Python学习笔记(4)-函数

    函数

    函数的简介

    函数也是一个对象,函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用,函数中保存的代码不会立即执行,需要调用函数代码才会执行
        创建函数:
            def 函数名([形参1,形参2,...形参n]) :
                代码块
        调用函数:
            函数对象()

    函数的参数

    • 在定义函数时,可以在函数名后的()中定义数量不等的形参,多个形参之间使用,隔开
    • 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值
    • 实参(实际参数),如果函数定义时,指定了形参,那么在调用函数时也必须传递实参,实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参
    • 定义形参时,可以为形参指定默认值,指定了默认值以后,如果用户传递了参数则默认值没有任何作用,如果用户没有传递,则默认值就会生效

    实参的传递方式

    位置参数

    位置参数就是将对应位置的实参复制给对应位置的形参,第一个实参赋值给第一个形参,第二个实参赋值给第二个形参...

    关键字参数

    关键字参数,可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数

    fn(b=1 , c=2 , a=3)
    print('hello' , end='')
    

    位置参数和关键字参数可以混合使用,混合使用关键字和位置参数时,必须将位置参数写到前面

    fn(1,c=30)
    
    不定长的参数

    定义一个函数,可以求任意个数字的和

    def sum(*nums):
        # 定义一个变量,来保存结果
        result = 0
        # 遍历元组,并将元组中的数进行累加
        for n in nums :
            result += n
        print(result)
    sum(123,456,789,10,20,30,40)
    

    在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参,它将会将所有的实参保存到一个元组中
    a,b,*c = (1,2,3,4,5,6)
    *a会接受所有的位置实参,并且会将这些实参统一保存到一个元组中(装包)

    def fn(*a):
        print("a =",a,type(a))
    fn(1,2,3,4,5)
    

    带星号的形参只能有一个
    带星号的参数,可以和其他参数配合使用
    第一个参数给a,第二个参数给b,剩下的都保存到c的元组中

    def fn2(a,b,*c):
         print('a =',a)
         print('b =',b)
         print('c =',c)
    

    可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递
    第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数

    def fn2(a,*b,c):
         print('a =',a)
         print('b =',b)
         print('c =',c)
    

    所有的位置参数都给a,b和c必须使用关键字参数

     def fn2(*a,b,c):
         print('a =',a)
         print('b =',b)
         print('c =',c)
    

    如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递

    def fn2(*,a,b,c):
        print('a =',a)
        print('b =',b)
        print('c =',c)
    fn2(a=3,b=4,c=5)
    

    *形参只能接收位置参数,而不能接收关键字参数

    def fn3(*a) :
         print('a =',a)
    

    **形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中,字典的key就是参数的名字,字典的value就是参数的值
    **形参只能有一个,并且必须写在所有参数的最后

    def fn3(b,c,**a) :
        print('a =',a,type(a))
        print('b =',b)
        print('c =',c)
    fn3(b=1,d=2,c=3,e=10,f=20)
    

    参数的解包(拆包)

    def fn4(a,b,c):
        print('a =',a)
        print('b =',b)
        print('c =',c)
    

    创建一个元组
    t = (10,20,30)
    传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递,这里要求序列中元素的个数必须和形参的个数的一致

    fn4(*t)   
    

    创建一个字典
    d = {'a':100,'b':200,'c':300}
    通过**来对一个字典进行解包操作

    fn4(**d)
    

    返回值

    返回值,返回值就是函数执行以后返回的结果
    可以通过 return 来指定函数的返回值
    可以之间使用函数的返回值,也可以通过一个变量来接收函数的返回值

    def sum(*nums):
        # 定义一个变量,来保存结果
        result = 0
        # 遍历元组,并将元组中的数进行累加
        for n in nums :
            result += n
        print(result)
    sum(123,456,789)
    

    return 后边跟什么值,函数就会返回什么值
    return 后边可以跟任意的对象,返回值甚至可以是一个函数

      def fn():
        # return 'Hello'
        # return [1,2,3]
        # return {'k':'v'}
        def fn2() :
            print('hello')
        return fn2 # 返回值也可以是一个函数
    

    r = fn()  这个函数的执行结果就是它的返回值
    如果仅仅写一个return或者不写return,则相当于return None

    def fn2() :
        a = 10
        return 
    

    在函数中,return后的代码都不会执行,return一旦执行函数自动结束

    def fn3():
        print('hello')
        return
        print('abc')
    r = fn3()
    print(r)
    
    def fn4() :
        for i in range(5):
            if i == 3 :
                # break 用来退出当前循环
                # continue 用来跳过当次循环
                return # return 用来结束函数
            print(i)
        print('循环执行完毕!')
    
    def sum(*nums):
        # 定义一个变量,来保存结果
        result = 0
        # 遍历元组,并将元组中的数进行累加
        for n in nums :
            result += n
        return result
    r = sum(123,456,789)
    print(r + 778)
    
    def fn5():
        return 10
    

    fn和fn()的区别
    fn是函数对象,打印fn实际是在打印函数对象
    fn()是在调用函数,打印fn()实际上是在打印fn()函数的返回值

    文档字符串

    help()是Python中的内置函数
    通过help()函数可以查询python中的函数的用法
    语法:help(函数对象)
    help(print) # 获取print()函数的使用说明
    文档字符串(doc str)
    在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明,当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明
    文档字符串非常简单,其实直接在函数的第一行写一个字符串就是文档字符串

    def fn(a:int,b:bool,c:str='hello') -> int:
        '''
        这是一个文档字符串的示例
        函数的作用:。。。。。
        函数的参数:
            a,作用,类型,默认值。。。。
            b,作用,类型,默认值。。。。
            c,作用,类型,默认值。。。。
    
        '''
        return 10
    help(fn)
    

    作用域与命名空间

    作用域指的是变量生效的区域

    b = 20 # 全局变量
    def fn():
        a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问
        print('函数内部:','a =',a)
        print('函数内部:','b =',b)
    fn()    
    print('函数外部:','a =',a)
    print('函数外部:','b =',b)
    

    在Python中一共有全局作用域与函数作用域两种作用域

    全局作用域

    • 全局作用域在程序执行时创建,在程序执行结束时销毁
    • 所有函数以外的区域都是全局作用域
    • 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问

    函数作用域

    • 函数作用域在函数调用时创建,在调用结束时销毁
    • 函数每调用一次就会产生一个新的函数作用域
    • 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
    • 变量的查找
    1. 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,
      如果没有则继续去上一级作用域中寻找,如果有则使用,如果依然没有则继续去上一级作用域中寻找,以此类推,直到找到全局作用域,依然没有找到,则会抛出异NameError: name 'a' is not defined
    2. 如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量(global a),声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a

    命名空间(namespace)

    • 命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
    • 每一个作用域都会有一个它对应的命名空间
    • 全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
    • 命名空间实际上就是一个字典,是一个专门用来存储变量的字典
    • locals()用来获取当前作用域的命名空间
    • 如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间,返回的是一个字典
    • globals() 函数可以用来在任意位置获取全局命名空间
    scope = locals() # 当前命名空间
    scope['c'] = 1000 # 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做)
    
    def fn4():
        a = 10
        scope = locals() # 在函数内部调用locals()会获取到函数的命名空间
        scope['b'] = 20 # 可以通过scope来操作函数的命名空间,但是也是不建议这么做
    

    递归

    尝试求10的阶乘(10!)
    1! = 1
    2! = 1*2 = 2
    3! = 1*2*3 = 6
    4! = 1*2*3*4 = 24
    print(1*2*3*4*5*6*7*8*9*10)
    创建一个变量保存结果
    n = 10
    for i in range(1,10):
         n *= i
    print(n)
    创建一个函数,可以用来求任意数的阶乘
    def factorial(n):
        '''
            该函数用来求任意数的阶乘
            参数:
                n 要求阶乘的数字
        '''
        result = n
        for i in range(1,n):
            result *= i
        return result 
    print(factorial(20))
    递归式的函数
    递归简单理解就是自己去引用自己!
    递归式函数,在函数中自己调用自己!
    无穷递归,如果这个函数被调用,程序的内存会溢出,效果类似于死循环
    递归是解决问题的一种方式,它和循环很像
    它的整体思想是,将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题
    递归式函数的两个要件
    1.基线条件
    问题可以被分解为的最小问题,当满足基线条件时,递归就不在执行了
    2.递归条件
    将问题继续分解的条件
    递归和循环类似,基本是可以互相代替的,循环编写起来比较容易,阅读起来稍难,递归编写起来难,但是方便阅读
    10! = 10 * 9!
    9! = 9 * 8!
    8! = 8 * 7!
     ...
    1! = 1

    def factorial(n):
        '''
            该函数用来求任意数的阶乘
            参数:
                n 要求阶乘的数字
        '''
        基线条件 判断n是否为1,如果为1则此时不能再继续递归
        if n == 1 :
            # 1的阶乘就是1,直接返回1
            return 1
        # 递归条件    
        return n * factorial(n-1)
    print(factorial(10))
    

    创建一个函数 power 来为任意数字做幂运算 n ** i
    10 ** 5 = 10 * 10 ** 4
    10 ** 4 = 10 * 10 ** 3
    ...
    10 ** 1 = 10

    def power(n , i):
        '''
            power()用来为任意的数字做幂运算
            参数:
                n 要做幂运算的数字
                i 做幂运算的次数
        '''
        # 基线条件
        if i == 1:
            # 求1次幂
            return n
        # 递归条件
        return n * power(n , i-1)
    print(power(8,6))    
    

    创建一个函数,用来检查一个任意的字符串是否是回文字符串,如果是返回True,否则返回False
    回文字符串,字符串从前往后念和从后往前念是一样的
    abcba
    abcdefgfedcba
    先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串
    如果一致,则看剩余的部分是否是回文字符串
    检查 abcdefgfedcba 是不是回文
    检查 bcdefgfedcb 是不是回文
    检查 cdefgfedc 是不是回文
    检查 defgfed 是不是回文
    检查 efgfe 是不是回文
    检查 fgf 是不是回文
    检查 g 是不是回文

    def hui_wen(s):
        '''
            该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False
            参数:
                s:就是要检查的字符串
        '''
        # 基线条件
        if len(s) < 2 :
            # 字符串的长度小于2,则字符串一定是回文
            return True
        elif s[0] != s[-1]:
            # 第一个字符和最后一个字符不相等,不是回文字符串
            return False    
        # 递归条件    
        return hui_wen(s[1:-1])
    def hui_wen(s):
    
         '''
             该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False
             参数:
                 s:就是要检查的字符串
         '''
         # 基线条件
         if len(s) < 2 :
             # 字符串的长度小于2,则字符串一定是回文
             return True
         # 递归条件    
         return s[0] == s[-1] and hui_wen(s[1:-1])
    print(hui_wen('abcdefgfedcba'))
    

    函数式编程

    在Python中,函数是一等对象,一等对象一般都会具有如下特点:

    • 对象是在运行时创建的
    • 能赋值给变量或作为数据结构中的元素
    • 能作为参数传递
    • 能作为返回值返回

    高阶函数

    接收函数作为参数,或者将函数作为返回值的函数是高阶函数
    当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数
    创建一个列表
    l = [1,2,3,4,5,6,7,8,9,10]
    定义一个函数
    可以将指定列表中的所有的偶数,保存到一个新的列表中返回
    定义一个函数,用来检查一个任意的数字是否是偶数

    def fn2(i) :
        if i % 2 == 0 :
            return True
        return False    
    
    

    这个函数用来检查指定的数字是否大于5

    def fn3(i):
        if i > 5 :
            return True    
        return False
    def fn(func , lst) :
        '''
            fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回
            参数:
                lst:要进行筛选的列表
        '''
        # 创建一个新列表
        new_list = []
        # 对列表进行筛选
        for n in lst :
            # 判断n的奇偶
            if func(n) :
                new_list.append(n)
            # if n > 5 :
            #     new_list.append(n)
        # 返回新列表
        return new_list
    

    filter()

    filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中
    参数:
    1.函数,根据该函数来过滤序列(可迭代的结构)
    2.需要过滤的序列(可迭代的结构)
    返回值:
    过滤后的新序列(可迭代的结构)
    fn4是作为参数传递进filter()函数中
    而fn4实际上只有一个作用,就是作为filter()的参数
    filter()调用完毕以后,fn4就已经没用

    匿名函数lambda

    lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式
    语法:lambda 参数列表 : 返回值
    匿名函数一般都是作为参数使用,其他地方一般不会使用

    def fn5(a , b):
        return a + b
    (lambda a,b : a + b)(10,20)
    也可以将匿名函数赋值给一个变量,一般不会这么做
    fn6 = lambda a,b : a + b
    print(fn6(10,30))
    r = filter(lambda i : i > 5 , l)
    # print(list(r))
    

    map()

    map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回
    l = [1,2,3,4,5,6,7,8,9,10]
    r = map(lambda i : i ** 2 , l)
    print(list(r))

    sort()

    该方法用来对列表中的元素进行排序
    sort()方法默认是直接比较列表中的元素的大小
    在sort()可以接收一个关键字参数,key
    key需要一个函数作为参数,当设置了函数作为参数
    每次都会以列表中的一个元素作为参数来调用函数,并且使用函数的返回值来比较元素的大小
    l = ['bb','aaaa','c','ddddddddd','fff']
    l.sort(key=len)
    l = [2,5,'1',3,'6','4']
    l.sort(key=int)
    print(l)

    sorted()

    这个函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序
    并且使用sorted()排序不会影响原来的对象,而是返回一个新对象

    l = [2,5,'1',3,'6','4']
    # l = "123765816742634781"
    print('排序前:',l)
    print(sorted(l,key=int))
    print('排序后:',l)
    

    闭包

    将函数作为返回值返回,也是一种高阶函数,这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量,可以将一些私有的数据藏到的闭包中

    def fn():
        a = 10
        # 函数内部再定义一个函数
        def inner():
            print('我是fn2' , a)
        # 将内部函数 inner作为返回值返回   
        return inner
    

    r是一个函数,是调用fn()后返回的函数
    这个函数实在fn()内部定义,并不是全局函数
    所以这个函数总是能访问到fn()函数内的变量
    求多个数的平均值
    nums = [50,30,20,10,77]
    sum()用来求一个列表中所有元素的和
    print(sum(nums)/len(nums))
    形成闭包的要件
       ① 函数嵌套
       ② 将内部函数作为返回值返回
       ③ 内部函数必须要使用到外部函数的变量

    def make_averager():
        # 创建一个列表,用来保存数值
        nums = []
        # 创建一个函数,用来计算平均值
        def averager(n) :
            # 将n添加到列表中
            nums.append(n)
            # 求平均值
            return sum(nums)/len(nums)
        return averager
    averager = make_averager()
    print(averager(10))
    

    装饰器

    # 创建几个函数
    def add(a , b):
        '''
            求任意两个数的和
        '''
        r = a + b
        return r
    def mul(a , b):
        '''
            求任意两个数的积
        '''
        r = a * b
        return r  
    

    希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕
    我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
       ① 如果要修改的函数过多,修改起来会比较麻烦
       ② 并且不方便后期的维护
       ③ 并且这样做会违反开闭原则(OCP),程序的设计,要求开发对程序的扩展,要关闭对程序的修改
    我们希望在不修改原函数的情况下,来对函数进行扩展
    def fn():
        print('我是fn函数'')
    def fn2():
        print('函数开始执行')
        fn()
        print('函数执行结束')
    fn2()   
    def new_add(a,b):
        print('计算开始')
        r = add(a,b)
        print('计算结束')
        return r
    r = new_add(111,222)   
    print(r)
    上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了
    但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了
    为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数
    def begin_end(old):
        '''
            用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束
            参数:
                old 要扩展的函数对象
        '''

    # 创建一个新函数
        def new_function(*args , **kwargs):
            print('开始执行~~~~')
            # 调用被扩展的函数
            result = old(*args , **kwargs)
            print('执行结束~~~~')
            # 返回函数的执行结果
            return result
    

    # 返回新函数       
        return new_function
    f = begin_end(fn)
    f2 = begin_end(add)
    f3 = begin_end(mul)
    r = f()
    r = f2(123,456)
    r = f3(123,456)
    print(r)

    1. 像begin_end()这种函数我们就称它为装饰器
    2. 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
    3. 在开发中,我们都是通过装饰器来扩展函数的功能的
    4. 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
    5. 可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰
    def fn3(old):
        '''
            用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束
            参数:
                old 要扩展的函数对象
        '''
    
    # 创建一个新函数
        def new_function(*args , **kwargs):
            print('fn3装饰~开始执行~~~~')
            # 调用被扩展的函数
            result = old(*args , **kwargs)
            print('fn3装饰~执行结束~~~~')
            # 返回函数的执行结果
            return result
        # 返回新函数        
        return new_function
    @fn3
    @begin_end
    def say_hello():
        print('大家好~~~')
    say_hello()
    
    作者:Cstzar

    -------------------------------------------

    个性签名:君子藏器于身,待时而动

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

  • 相关阅读:
    Ed Chi 的 long range dependence works
    论文阅读:Stochastic Weight Completion for Road Networks using Graph Convolutional Networks
    论文阅读:HOP-Rec: High-Order Proximity for Implicit Recommendation
    温故BERT之Transformer
    论文阅读:Are We Really Making Much Progress-A Worrying Analysis of Recent Neural Recommendatin Approaches
    使用ffmpeg进行媒体格式转换
    使用ghostscript将pdf转图片
    linux下使用libreoffice将Office文档转PDF
    nginx指定文件路径有两种方式root和alias
    CentOS下的SVN服务器搭建过程
  • 原文地址:https://www.cnblogs.com/cstzar07/p/14820610.html
Copyright © 2011-2022 走看看