什么时函数?

通俗的讲,函数就是写一段代码实现了某个小功能,然后把这些代码集中到一块,起一个名字,下次可以根据这个名字再次使用。

函数有什么作用?

  1. 方便代码的重用。
  2. 分解任务,简化程序逻辑。
  3. 是代码更加模块化。

函数有哪几类?

  1. 内建函数(Python自带函数)
  2. 第三方函数(第三方公司或者第三方个人开发出来的函数)
  3. 自定义函数

参数传输的方式:

多个参数

使用位置实参:直接用形参和实参一一对应使用关键字参数:参数名称=参数(关键字参数)不需要严格按照顺序使用容器作为实参:可以将一个列表或者字典作为一串参数传入函数。

不定长参数

1.在参数前面加一个*号代表不定长参数,函数中将会把这个变量作为元组来处理。(默认用*args)之所以将这个变量当作元组处理而不作为列表处理,是因为在函数体中我们要尽可能直接改变参数。2.在参数前面加俩个*号,以字典的方式来使用函数。这种方式定义的函数必须使用关键字参数进行传递。(默认使用**kwrgs)

这里有一个装包和拆包的概念,所谓装包就是将单独的个体整合成一个整体集合,例如使用*args和**kwrgs;而拆包则是将一个整体拆分为单独的个体。读取*args和**kwargs。

缺省参数:

缺省参数指的是参数在大多数情况下都是默认的情况,缺省参数在定义的时候需要使用关键字参数的方式传递,下面的形参sombody就是一个缺省参数。

def hit( sombody = "呼呼") :
    print("我想打",sombody)ha
hit("nim")

函数参数的一些注意点:

首先要明确在函数中什么时值传递,什么是引用传递。

值传递:仅仅是将数据的副本传递过去,传递过去的值的地址跟原数据不一致,修改副本不会引起原来数据的变化。

引用传递:所谓引用传递就是地址传递,通过相同的地址操控同一份地址,在函数中改变形参会引起实参的变化。

一定要注意在Python中函数一般 都是引用传递。(地址传递)

如果要使用原数据的副本进行函数操作,可以使用切片的方法进行拷贝,传递过去的就是一份原数据的副本。

如果是不可变的数据类型,在函数中进行修改一定会改变它的地址;如果是可变数据类型,采用简单的添加删除不会修改地址,而直接重新赋值会出现新的地址。

函数的返回值:

当我们需要接收函数的处理结果时,就必须使用return来接收这个结果。一定注意:return只会执行一次,后面的代码不会再被执行。

return的结果可以时元组,列表,字典。

函数的表述信息:

当我们在写一个函数时一定要写一个函数的描述信息,写在开头用三个引号括起来。

在使用中可以使用help(函数名)来查看函数的功能。

函数描述信息必须包含的内容:

  1. 说明当前函数的功能。
  2. 说明函数参数的信息含义,数据类型,有没有默认值,有的话说明默认值。
  3. 说明函数的返回结果。

函数的高级功能:

偏函数:

什么时偏函数?当一个函数的默认参数大多数情况下时时不变的,但是有希望在指定的情况下改变其默认值,以此生成新的函数就是偏函数。我们可以通过functools模板的partial函数来改变函数的默认参数。

下面是一个使用偏函数的例子:

import functools


def test(a, b, c, d=2):
    print(a + b + c + d)


test(1, 2, 3)
newTest = functools.partial(test, c=2)
newTest(1,1)

高阶函数:

当一个函数的参数接收的是另一个函数,那么这个函数就是一个高阶函数。

下面是一个高阶函数的例子,其中的sorted()就是一个高阶函数

l = [{"name":"s2","age":18} , {"name":"sz2","age":19} , {"name":"kc","age":20}]

def getKey(x):
    return x["age"]

result = sorted(l , key = getKey)
print(result)

注意点:在将函数作为参数时使用的只是函数的名称,也就是说不用带上函数参数列表(括号)

返回函数:

返回参数指的是函数内部返回的数据是另外一个函数,把这样的操作称之为“返回参数”。

def getFun(flag) :
    def sum( a, b , c) :
        return a + b + c
    def jianfa( a, b, c) :
        return a - b - c
    if flag == "+" :
        return sum
    elif flag == "-" :
        return jianfa

function = getFun("+")
print(function(1, 2, 3))

匿名函数:

匿名函数称之为lambda函数,顾名思义就是指没有名字的函数,匿名函数只适合用于简单操作的函数。

使用的格式:lambda 参数1,参数2....:表达式(只能写一个表达式)表达式的结果就是匿名函数的返回值。总之先使用lambda作为统一函数名,再加上一个表达式,表达式的结果就是返回值。

下面是一个使用匿名函数的例子

result = (lambda x, y: x + y)(1, 2)
print(result)

l = [{"name": "s2", "age": 18}, {"name": "sz2", "age": 19}, {"name" :"kc","age": 20}]
result = sorted(l, key = lambda x: x["age"])
print(result)

闭包函数:

在函数嵌套的前提下,内层函数引用了外层函数变量(包括参数),而外层函数又把n内层函数当作返回值进行返回。

这个内层函数加上所引用的外层变量称之为闭包。

def test():
    a = 10

    def test2():
        print(a + 7)
    return test2


newFun = test()
newFun()


def line_config(content, length):
    def line():
        print("-"*(length//2) + content + "-"*(length//2))
    return line


line1 = line_config("还哦",40)
line1()

line2 = line_config("还有我",80)
line2()

注意点:

在使用闭包函数时,如果要修改外层函数,必须在变量前面加上nonlocal声明,否则会被当作闭包内新定义的变量。

当函数被执行时里面的代码才会执行,在定义时是不会被执行的。

函数装饰器:

利用其它函数取装饰原本的函数。

装饰器适合做重复性,冗余度非常大的代码段落。一些基础业务逻辑代码的冗余度非常大,导致代码的复用性比较差,代码的维护性比较差。当我们要修改代码时,尽量在重用性非常高的地方进行修改,这时候装饰器的优势非常大。

函数的使用要遵循单一职责,函数内容单一优先实现函数名的功能。

下面是一些使用函数装饰器的案例:

def checklogin(func) :
    """
    这是一个要用来做装饰器的函数,这个函数可以让其它函数增加登陆验证的操作
    """
    def inner() :
        """
        这是一个闭包函数,用来接收其它函数功能,使他们的功能和登陆验证结合起来
        """
        print("正在登陆验证....")
        func()
    return inner

@checklogin    # 装饰器的写法,相当于对下面的函数进行更新,是下面的发说说函数增加一个登陆验证操作
def fss() :
    print("发说说!")
# fss = checklogin(fss)

@checklogin   # 装饰器的写法,相当于对下面的函数进行更新,是下面的发图片函数增加一个登陆验证操作
def ftp():
    print("发图片!")
# ftp = checklogin(ftp)

fss()
ftp()

案例2:装饰器叠加:从上到下进行叠加;从下到上进行叠加。

def print_line(funce2) :
    """
    这是一个用来做装饰器的函数,给其它函数增加打印------的功能
    """
    def inner() :
        print("-" * 30)
        funce2()
    return inner

def print_star(funce2) :
    """
    这是一个用来做装饰器的函数,给其它函数增加打印*****的功能
    """
    def inner() :
        print("*" * 30)
        funce2()
    return inner


@print_star    #使用上面的俩个装饰器连续修饰,从下往上看。
@print_line
def print_name() :
    print("I am Linjunhan !")

案例3:对有参数的函数进行装饰

def zsq(func) :
    """
    这是一个用来做修饰器函数,用来打印-------信息
    """
    def inner(*args ,**kwargs) :
        print("-" * 30)
        func(*args ,**kwargs)
    return inner

@zsq 
def pnum(num) :
    print(num)

@zsq
def pnum2(num1,num2) :
    print(num1,num2)

案例4:对有返回值的函数进行修饰。

def zsq(func):
    def inner(*args, **kwargs):
        print("-" * 30)
        res = func(*args, **kwargs)
        return res
    return inner


@zsq  # pnum = zsq(pnum)
def pnum(num1, num2, num3):
    return num1 + num2 + num3


print(pnum(1, 2, 3))

案例5:带有装饰的修饰器 ,通过@修饰器(参数)的方式调用这个函数,并传递参数;并把返回值再次当作修饰器来使用。

def zsqs(char):
    def zsq(func):
        def inner():
            func()
            print(char * 30)

        return inner
    return zsq


@zsqs("*")  # 利用函数调用zsq修饰器。
def f1():
    print("666666")

f1()

生成器(特殊的迭代器):

生成器具有迭代器的特征:

惰性计算数据,节省内存,一个一个拿出来用。

能够记录数据,并通过next()函数,访问下一个函数。

具备可迭代性。

创建方式:把列表推导式[]改为()

生成器函数:

利用表达式创建:

l = (i for i in range(1, 100000) if i % 2 == 0)
print(next(l))
print(next(l))
print(next(l))

创建方式2:

def test():
    print("xxx")
    yield 1
    print("a")

    yield 2
    print("b")

    yield 3
    print("c")

    yield 4
    print("d")

    yield 5
    print("e")


g = test()
print(g)

超出范围,迭代停止。

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

f = fib(10)
print('fib(10):', f)
for x in f:
print(x)

# 超出范围,迭代停止
def test2() :
    print("xxxx")
    res1 = yield 1
    print(res1)

    res2 = yield 2
    print(res2)

    res3 = yield 3
    print(res3)


g = test2()

# print(g.__next__())   ##采用.__next__()的方法来访问迭代器
#利用生成器的.send方法,这个方法有一个参数,时用来指定上一次被挂起的yield的返回值,如果第一次调用,参数必须为空。
# print(g.send())
print(g.__next__())
print(g.send("6666"))
g.close()    # 生成器的关闭方法

 递归函数(在函数内部再次调用函数)

def jiecheng(n):
    """
    这个递归函数用计算参数n的阶乘
    :param n:
    :return:
    """
    if n == 1:
        return 1
    return n * (n - 1)
print(jiecheng(3))