• python基础|函数


    1 函数

      在python中的函数,内置函数有很多,如:int(), str(), list(), dict(), set() 等内置整形函数,bool()内置布尔值函数,len()内置长度计算函数 ,等等。在使用这些内置函数时,直接调用即可,且这些函数功能明确,十分方便简单。但是这些内置函数在我们写项目时仍然不够我们使用,有些地功能相同,重复写相同功能的代码,代码冗余,还十分费力,这就需要我们自己写函数了。

      定义函数的基本形式

    # 定义函数的基本形式
    def  xxx(a):    # def固定语法   xxx函数名   a函数参数
        代码1    # 函数内执行代码
        代码2
        代码3
        ...
       retuen y        # y返回值

      在python中定义一个函数,固定语法 def ,执行时表示这是一个定义的函数。空格一下与函数名区分开,(xxx)再取函数名,函数名的起名规则与变量相同。后加() 和 :a 括号内可加不加参数。

    另起一行,缩进四个空格,表示下面的代码是此函数的子代码快。写代码。函数结束需要 return 关键字,表示函数执行完毕。y retuen后空格写返回值,这个返回值是执行此函数之后,得到的值。

      在调用函数时有三种方式

    xxx()     # 直接调用
    
    a = xxx()   # 赋值形式调用
    a
    
    b = xxx    # 赋值函数名,再调用
    b()    

    1.1 函数返回值

      函数的返回值有四种形式

    # 函数不写retuen
    def fun():
        a = 1+2
    rec = fun()
    print(rec)
    >>>None
    # 函数返回值为空
    def fun1():
        a = 1+2
        return
    rec1 = fun1()
    print(rec1)
    >>> None
    # 函数返回值有一个值
    def fun2():
        a = 1+2
        return a
    rec2 = fun2()
    print(rec2)
    >>> 3
    # 函数返回值有多个值
    def fun3():
        a = 1+2
        b = 1-2
        return a, b
    rec3 = fun3()
    print(rec3)
    >>>(3, -1)

    1.2 函数的参数

      函数的参数分为形参和实参。实参是调用函数时函数内的参数,形参在定义函数内的参数。函数的实参和形参在函数结束之后随之结束。

      函数的参数类型

      位置参数

    # 位置参数
    def fun(x, y):    函数形参第一参数是x, 其次是y。则按照位置对应赋值x = 20, y = 100
        x += 1
        y += 1
        return x, y
    fun(20, 100)     # 调用函数,函数内第一个参数值是20,其次是100

      位置参数形式,传入实参的个数必须与形参个数保持一致。

      默认参数

    # 形参默认参数形式
    def fun(x, y = 100):  # x = 10 ,y默认为100
        pass
        return x, y
    fun(20)      # 函数第一个位置传入20
    fun(1, 30)    # x = 1, y 不在使用默认值100,y = 30
    def func(x, y):
        pass
        return x, y
    fun(y=10, x=20)  # 不在受位置的约束,直接指定赋值,这种传参方式,如果有位置参数,赋值参数必须在位置参数后面
     

       

    # 形参默认参数补充
    m= 3
    def func(x, y = m):  # 默认参数以变量名传参,变量在定义函数前被定义
        pass
        return x, y
    rec = func(10, 30)

      可变参数

      当位置参数实参有多个值需要传入形参中,可以使用可变参数

    def func(x, *y):
        pass
        return x, y
    rec = func(0, 1, 2, 3, 4, 5)
    print(rec)
    >>>0, (1, 2, 3, 4, 5)     # 溢出的参数将会以元组的形式保存,元组名是y

      当实参是一个一个容器类型,要把里面的值传入形参

    def func(x, y, z):
        pass
        return x, y, z
    rec = func(*[1, 2, 3])  # 将容器打散,以位置参数形式送入。容器可以是字符串类型,列表类型, 元组类型以及集合
    print(rec)
    >>> 1, 2, 3

      实参赋值,有多个需要传入

    def func(**z):    # 将赋值变量转成字典/ z={'a': 0, 'b': 1, 'c': 2}
        pass
        return x, y
    rec = func(a = 0, b = 1, c =2)  
    # 反之
    def func(a, b, c):   # 将赋值变量转成字典
    pass
    return a, b, c
    z = {'a': 0, 'b': 1, 'c': 2}
    rec = func(**z) # 将字典打撒赋值,给形参
    print(rec)

      可变参数使用十分频繁。通常我使用的形式是

    def func(*args, **kwargs):   # python中推荐这样使用,是实参不管传入多少值都可以被形参接收
        print(args, kwargs)

     2 函数对象

       函数有函数名,函数名指向的值,称之为函数对象。

    def func():
        print('这是func函数')
        return
    print(func)
    >>><function func at 0x0000025D53E51E18> # 函数名指向的值

      函数对象可以被引用,可以被当作参数传给另一个变量。也可以当作函数返回值,还可以当作容器类型的元素。

    # 可以被引用
    def func():
        print('这是func函数')
        return
    print(func)
    
    # 可以被赋值
    f = func
    f()
    
    # 可以当作函数返回值
    def func():
        print('这是func函数')
        return func      # 返回值 func
    
    # 可以当作容器类型的参数
    lis = [1, 2, 3, func]

    3 函数嵌套

      函数的嵌套有两种形式。一种是在调用函数的内部在调用另一个函数。另一种是,在函数内部定义一个函数,并调用。

    # 函数调用的第一种形式
    def f1():
        print('这是f1函数')
    
    def f2():
        f1()
        print('这是f2函数')
    f2()
    >>>这是f1函数
    这是f2函数
    
    # 第二种形式
    def f1():
        def f2():
            print('这是f2函数')
        print('这是f1函数')
        return f2
    rec = f1()
    rec()
    >>> 这是f1函数
    这是f2函数

    4 名称空间

      名称空间就是名字存在的空间。python中有三种名称空间。分别是内置名称空间,全局名称空间和局部名称空间。内置空间是python解释器运行时的空间,在启动python整个过程始终在其中运作,len , str, int bool, break等这这内置函数名都在内置空间。全局名称空间是py文件运行时的变量名称 ,局部空间是自定义函数内的变量名称。

      在调用一个值是,需要一个变量名来绑定,通过变量名可以调用该值。对于变量名的查找,python有自己的规定。程序执行顺序是,内置---->全局--->局部。查找名称的顺序则是反着来的且与查找位置有关。如果在局部需要调用该值,查找该值的名称的顺序是先从局部--->全局--->内置。如果在全局调用该值,那么查找改制变量名的顺序是先从全局--->内置。

      

       名称空间中的变量名有作用域。主要有全局作用域,和局部作用域,全局作用域包含内置空间变量名和全局空间变量名,在全局作用都有效。局部作用域就是在局部空间的变量名,在局部空间有效。

      在局部要修改全局作用域变量内的值。需要使用global, nonlocal

    # 在局部修改全局作用域的值
    # 修改一个可变类型
    lis = []
    def func():
        lis.append('meKing')
    print(lis)
    >>>['meking']
    
    # 修改一个不可变类型
    a = 10
    def func():
        global a  # 在局部声明,变量来自全局空间。(变量必须为不可变类型)
        a = 20
    func()
    print(a)
    >>>20
    # 在局部的局部内内修改局部变量(变量为不可变类型)
    def func():
    a = 20
    def f1():
    nonlocal a
    a = 30
    f1()
    print(a)
    func()

     4 闭包函数

      闭包函数定义在函数内部,引用外部函数的全局作用域变量名。

    # 闭包函数
    def outter():
        def inner():     # 定义在函数内部的函数
            print('这是inner函数‘)
        return inner
    rec = outter()      # 内部函数inner引用全局作用域的变量名rec

      函数传参两种方式

    # 函数传参的第一种方式
    def func():
         x = 1
         y = 2
        def innner()
            print(x, y)
        return inner
    func()
    
    # 闭包函数传参的第二种方式
    def fun1(x , y):
        def inner1():
            print(x, y)
        return inner
    fun1(1, 2)
    # 这两种传参的效果是一样的,但是方式二在参数变动时需要修改,明显比方式一更有优势

    闭包函数传参应用

    # 
    import requests      # requsets,爬虫的一个库
    f = requests.get('https://www.jd.com')    # 爬取京东网页数据
    if f.status_code == 200:
        print(len(f.text))       # 打印网页字符串长度
    
    # 如果要多次爬取,我们这样输入,很麻烦。
    # 
        
    def index():
         f = requests.get(url)    
         if f.status_code == 200:
               print(len(f.text))
    indx(url)
    
    # 如果要多次爬,且有不同的网站,这也有点麻烦
    # 
    import requests  
    def intto(url):
         def index():
            f = requests.get(url)    
             if f.status_code == 200:
                  print(len(f.text))
          return index
    get_jd = intto('京东地址')
    get_baidu = intto('百度地址’)
    get_jd()
    get_baidu()
    # 这样爬取次数和,不同内容都比较方便

     装饰器

       在不改变原函数的基础上给原函数添加一个新功能。这就需要装饰器。装饰器的特点对外扩展功能开发,对内修改封闭。在使用装饰器原则是,不改变源码,不改变被装饰对象。

    # 简单的python装饰器
    def intto(func):
        def inner()
            print('这是内层函数inner')
            func()
        return inner
    index = intto(index)
    def index():
        print('这是index函数')
    index()
    >>>这是内层函数inner
    >>>这是index函数

      语法糖

      装饰器有一个简便的用法。那就是语法糖。是用@装饰函数,程序会将最近的下一个函数名做变量名送如装饰函数中运行,函数返回的内部定义函数的函数名,下一个最近的函数的函数名会接受。在调用原函数的函数名,实质是在调用装饰函数内定义的函数。

    def intto(func):
        def inner()
            print('这是内层函数inner')
            func()
        return inner
    @intto     # 等价于:index = intto(index)
    def index():
        print('这是index函数')
    index()

      装饰器使用时,我们打印indexd的时候会出现这样一个信息<function intto.<locals>.inner at 0x00000236268BBB70>。显示index其实是inner函数。装饰的函数还是不能和真的一样。可以用python中的一个方法。

    from functools import wraps
    def intto(func):
        @wraps(func)  
        def inner():
            print('这是内层函数inner')
            func()
        return inner
    @intto     # 等价于:index = intto(index)
    def index():
        print('这是index函数')
    print(index)
    >>><function index at 0x000002A602178400> # 和原函数一模一样。如假包换。
     1 # 无参装饰器
     2 from functools import wraps
     3 def intto(func):
     4     @wraps(func)  
     5     def inner(*args, **kwargs):
     6         print('被装饰函数执行之前操作!')
     7         res = func(*args, **kwargs)    # 被装饰函数执行
     8         print('被装饰函数执行之后操作!')
     9         return res
    10     return inner
    11 @intto
    12 def index():
    13     print('被装饰函数')
    14 
    15 # 有参装饰器
    16 from functools import wraps
    17 def outer(data):
    18     def intto(func):
    19         @wraps(func)
    20         def inner(*args, **kwargs):
    21             print('被装饰函数执行之前操作!', data)
    22             res = func(*args, **kwargs)    # 被装饰函数执行
    23             print('被装饰函数执行之后操作!')
    24             return res
    25         return inner
    26     return intto
    27 @outer('参数')
    28 def index():
    29     print('被装饰函数')
    有参与无参装饰器

    5 函数递归

      函数的的递归就是函数在调用阶段直接或间接调用自己。在python中函数的递归有最大的递归深度, 在997到998之间。在查看递归深度可以使用sys模块,import sys,在打印sys.getrecursionlimit(),即可查看递归深度。当函数递归按理论上讲可以无限递归,但是这中递归没有任何意义,反而会占用大量内存资料,影响计算机的使用。所以跑python需要着这种递归深度。还可扩大递归深度,也是用sys模块,sys.setrecursionlimit(n),n是设置的递归深度。

      有意义的函数递归应该包含回溯和递推。回溯是一次次重复的过程,但是重复就应该使问题复杂度下降,逐渐到达最终结束条件。递归:将结果往回推到结果。

    # 将列表中的数字打印出来
    l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]]
    def index(lis):
        for i in lis:
            if type(i) is int:     # 是数字就打印
                print(i)
            else:
                index(i)   # 否者调用函数index
    index(l1)

      算法之二分法。算法解决问题是方法。数学王子高斯,在小学时老师让全班同学计算从1到100的和。当大家都在奋笔疾书取算时,高斯已经算出来了。他发现所有的数,1+100=101,2+99=101...首位相加都是一样的,这样的数有50个,就很快算出来5050。对于计算机也一样,算法的好坏,使计算机执行效率更高。就拿着来说计算1到1亿的和,使用while循环,和使用数列计算公式,明显感觉数列计算公式更加快捷。二分法是算法中的一种,在一个升序或降序数列中。寻找一个数,常规查找是一个一个顺序查找,这样可以找到,如果这个数在最后面,但无疑需要很大工作量。这个就可以用二分法了。被查找值与数列中间的值作比较,如果被查招数大于中间数,就切分列表,往中间数升序方向切分,否则,降序方向切分,切分后的列表在如此,如果找到便结束。这样就算法的过程就减少了很多。

    # 查找列表中某个值
    l1 = [i for i in range(1, 101)]
    def fine(l1, a):
        print(l1)
        if not l1:    # 如果列表为空,退出
            print('不在此列表')
            return
        j = len(l1)//2
        if a > l1[j]:
            l1 = l1[j+1:]
            fine(l1, a)
        elif a < l1[j]:
            l1 = l1[0:j]
            fine(l1, a)
        else:
            print('fine it', a)
    fine(l1, 98)   # 列表l1, 查找98

     

    # 列表生成式
    li = [i for i in range(100) if i //2 == 0]  # 0到99之间所有偶数元素,组成的列表
    li1 = list('abcdef')
    li2 = [i for i in li1 if i != 'b']   # 'a'到'f'的元素,且没有'b'
    #  字典生成式
    li1 = list('abcdef')
    dict_1 = {k:v for k,v in enumerate(li1)}
    print(dict_1)
    6 匿名函数及应用
      匿名函数和普通函数一样有固定的语法:lambda 参数:运算方法。结果便是返回值。lambda是关键字和普通函数的def相同,是固定的也是必须的的。函数的参数可以是任意类型单个或多个值。运算方法的结果便是返回值。匿名函数只写一行。
    x = 1
    lambda_1 = lambda x : x+1 
    print((lambda_1)(1))  # 和函数调用相同,在后面加括号,此函数需要一个参数,传入1
    >>>2
     匿名函数的应用
    # 匿名函数和max(),min()
    dict_1 = {'a': 4, 'b': 3, 'c': 5, 'd': 2}
    print(max(dict_1))  # 对字典经行排序,但max函数是查值遍历方式查最大值,但是只能访问到字典的键,无法访问字典的值。所以一键大小来排
    print(max(dict_1, key=lambda key: dict_1[key]))
    >>>d
    >>>c
    # python中A到Z对应数字是65到90,a到z对于数字是97到122
    dict_1 = {'a': 4, 'b': 3, 'c': 5, 'd': 2}
    print(min(dict_1))
    print(min(dict_1, key=lambda key: dict_1[key]))
    # 匿名函数与filter 过滤可迭代对象的一些值
    l1 = [i for i in range(9) if i > 4]
    print(filter(lambda x: x != 7, l1))  # 这是一个生成器
    print(list(filter(lambda x:x != 7, l1)))  # 遍历l1中的值,但条件为假直接跳过,开始下次遍历
    # 匿名函数与reduce
    from functools import reduce
    li = [i for i in range(5)]
    print(reduce(lambda x, y: x + y, li))   # 第一次将数列前两个数送入x, y;得到x+y结果送入参数中,与li下一个参数相加,
                            # 如此,指导列表中元素没有位置。得到列表元素和
    >>>10
    
    
    
    
    
    # 匿名函数与map
    # map 映射
    li = [i for i in range(5)]
    print(map(lambda x: x+1, li))   # 利用map遍历,遍历对象就是列表li,每次遍历一个值送给x,匿名函数返回x+1的值。这是一个生成器
    print(list(map(lambda x: x+1, li)))
    >>><map object at 0x0000011DCB849390>
    >>>[1, 2, 3, 4, 5]
    # zip 拉链
    l1 = [i for i in range(9) if i > 4]
    l2 = list('abcdefg')
    rec1 = zip(l2,l1)
    l3 = dict(rec1)
    print(l3)
    >>>{'a': 5, 'b': 6, 'c': 7, 'd': 8}

     6 迭代器与生成器

      迭代器是常见的一种可以迭代取值的工具,更新重复但每次更新都是基于上一次的结果。在python中可迭代对象的类型有,字符串,列表,元组,字典,集合和文件对象。

      判断是否是可迭代对象,这个可根据双下iter来判断。迭代器对象可根据双下next来判断

    # 可迭代对象,双下iter来判断
    str_1 = 'abcdefg'
    str_1.__iter__()    # 可迭代对象
    str_1 = 'abcdefg'
    s = str_1.__iter__()
    s.__next__()     # 迭代器对象

      在python中迭代器对象一定是可迭代对象,但可迭代对象不一定是迭代器对象。文件对象是迭代器对象。

    # 双下iter和双下next的使用
    str_1 = 'abcdefg'
    s = str_1.__iter__()   # 传成迭代器对象
    print(s.__next__())
    print(s.__next__())
    print(s.__next__())
    print(s.__next__())
    
    >>>a
    b
    c
    d

      for循环与迭代器

      for循环就是经in后面的可迭代对象用__iter__转成可迭代对象。再使用__next__迭代取值。当取到最后一个值,经行异常处理。

    str_1 = '123456789'
    for i in str_1:
        print(i, end=', ')
    
    def func(n):
        rec = n.__iter__()
        while True:
            try:                 # 异常捕获
                print(rec.__next__())
            except StopIteration:
                break
    func(str_1)

      小结:可迭代对象内置有__iter__方法,迭代器对象既内置有__iter__也有__next__方法。迭代取值是不依赖索引取值,在内存之占一份空间,对内存资源占小。但是取值的时候只能一个个取,不能取指定元素,取完会报错StopIteration。

      生成器,自定义的迭代器。自定义的迭代器需要用到关键字yield。当函数执行到yield时,会暂停,使用双下next是打印出来,会打印yield后面的值,为空默认为None.

    def func():     
        for i in range(1, 101):
                yield f'{i}号球衣'
    g = func()            # 生成器
    print(g.__next__())   # 发衣服
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    # for i in range(1, 10, 2): print(i) 实际执行过程
    def func(start, end, step):
        while start < end:
            yield start
            start += step
    g = func(1, 10, 2)
    while True:
        try:
            print(g.__next__())
        except StopIteration:
            break

       yield可以传值。需要使用send函数。

    def func():
        while True:
            color = yield
            print(f'{color}衣服')
    g = func()
    g.__next__()  # 使程序运行到yield
    g.send('红色')  # 给yield赋值
    g.send('黄色')
    红色衣服
    黄色衣服

        yield与return都在函数中。他们都有返回值,并且返回多个值时都是以元组的方式。区别也要很重要。函数执行到return会立即结束。但执行到yield会暂停,且yield还可以传值。

      生成器表达式。例:s = (i for i in range(10))。这里的s就是一个生成器。可以查看s只是一个生成器地址。

      生成器的取值不会不会主动,需要用双下next来取值。

  • 相关阅读:
    通过避免下列 10 个常见 ASP.NET 缺陷使网站平稳运行 from MSDN
    编写自己的dojo扩展zt
    Adding an IE7 Browser Template for use by Web Tests
    MAC地址与IP地址绑定策略的破解zt
    .net 中string 的应用特点(转贴)让我豁然开朗
    全国最佳医院排名(供参考)
    小心你的Page_Load重复执行(转贴)
    A780知识总汇zt
    [Quoted] Writing HighPerformance Managed Applications : A Primer
    [网络摘录学习]常用的Linux系统监控命令
  • 原文地址:https://www.cnblogs.com/huaiXin/p/11155161.html
Copyright © 2020-2023  润新知