Python函数知识

 回顾一下函数的知识,我列出了函数知识的提纲,可以根据提纲回忆复习一下:

1.函数传参的方式——关键字传参和按顺序传参

2.默认参数

3.传参顺序——一般先位置传参再关键字传参

4.指定传位置参数——/

5.指定传关键字参数——*

6.参数打包成元组——在形参前加*

7.多参数返回解包操作

8.元组打包传参后面的参数必须用关键字参数

9.参数打包成字典——在形参前加**

10.解包元组,然后传参

11.解包字典,然后传参

12.LEGB规则——多层函数变量调用规则

13.global关键字——调用全局变量的关键字

14.nonlocal关键字——调用外层变量的关键字

15.

def myfunc1(s, vt, o):
    return "".join((o, vt, s))
print(myfunc1("我", "爱上", "Python"))
print(myfunc1(o="我", vt="爱上", s="Python"))
#    两种传参方式


def myfunc2(s, vt , o="Study"):
    return "".join((s, vt ,o))
print(myfunc2("我", "爱"))
print(myfunc2("我", "爱", "Pyhton"))
#    默认参数


def myfunc3(vt, s="苹果", o="我"):
    return "".join((o, vt, s))
print(myfunc3("吃了"))
print(abs(-1.5))
print(sum([1, 2, 3], start=4))
#!  print(abs(x = -1.5))是不被允许的,会报错
#!  同理,sum(start=4, [1, 2, 3])也是会报错的
#    关键字传参在位置传参后面


def abc1(a, /, b, c):
    print(a, b ,c)
abc1(1, 2, 3)
abc1(1, b = 2, c = 3)
#    函数形参有/,说明在/之前的参数在传参时必须是位置参数而不能是关键字参数


def abc2(a, *, b, c):
    print(a ,b ,c)
abc2(1, b = 2, c = 3)
abc2(a = 4, b = 5, c = 6)
#    函数形参有*,说明在*之后的参数传参时必须是关键字参数


def myfunc4(*args):
    print("有{}个参数".format(len(args)))
    print("第2个参数是:{}".format(args[1]))
    print(args)
    print(type(args))
myfunc4(1, 2, 3, 4, 5)
#    在参数前加*,可以将传入的位置参数打包成一个元组


def myfunc6():
    return 1, 2, 3
print(myfunc6)
x, y, z = myfunc6()
print(x, y, z)
#    多参数返回,解包操作


def myfunc8(*args, a, b):
    print(args, a, b)
myfunc8(1, 2, 3 ,a = 4, b = 5)
#    如果出现了打包成元组的操作,那么后面参数传参时必须用关键字参数传参,以区分元组打包传参


def myfunc9(**kwargs):
    print(kwargs)
myfunc9(a = 1, b = 2, c = 3)
#    参数前出现**,那么就是字典打包传参,传参时要按照:键=值的方式传参,那么就会在函数内新建一个字典,键值对就是我们传参时候设置的形式。


def myfunc10(a, *b, **c,d):
    print(a, b, c, d)
myfunc10(1, 2, 3, 4, x = 5, y = 6, d = 8)
#    综合运用,同理,字典打包传参后面的参数同样必须用关键字传参


def myfunc11(a, b, c, d):
    print(a, b, c, d)
args = (1, 2, 3, 4)
myfunc11(*args)
#    传参时用*代表解包元组


kwargs = {'a':1, 'b':2, 'c':3, 'd':4}
myfunc11(**kwargs)
#    使用**对传参时的字典进行解包,此时值会被保留下来,键会被舍弃


#*  LEGB规则,python变量引用顺序:从当前作用域开始寻找变量,如果没找到就往上一层作用域寻找,
#*  没找到就再上一层。
#TODO   具体步骤:当前作用域局部变量->外层作用域变量->再外层作用域变量->…->当前模块全局变量->pyhton内置变量


x = 880 #*  全局变量
def myfunc12():
    x = 770 #*局部变量
    print(x, id(x))
myfunc12()
print(x, id(x))

#TODO   使用global关键字,可以调用全局变量,甚至可以在函数内部创建全局变量
x = 250
def myfunc13():
    global x, y 
    #TODO   调用全局变量x,创建全局变量y
    x = 260
    y = 250
    print(x, y, id(x), id(y))
myfunc13()
print(x, y, id(x), id(y))

#TODO   使用nonlocal关键字,可以在嵌套的函数内部修改外层函数的变量,
#!  但是前提是外层函数定义了某个变量,不然使用nonlocal会因为找不到外层函数的变量而报错
def myfunc14():
    x = 250 
    #*  myfunc14内的变量x
    def myfunc15():
        nonlocal x  
        #TODO   调用myfunc14内的变量x,如果x未定义,则报错
        #!  倘若没有这句nonlocal,那么会在内层函数内新建一个x变量,但是外层函数的x依然没有得到改变
        #!  也就是说想要修改外层函数的变量,要用这些关键字,不然根据LEGB规则,即使同名,先使用的依然是内层函数的变量x
        x = 260
        print(x, id(x))
    myfunc15()
    print(x, id(x))
myfunc14()
#!  当然,不使用nonlocal关键字,也可以在内层函数中调用外层函数的变量,但是不能修改,参考下面的power函数,原理是LEGB规则

#*  什么是闭包?
#*  如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包
#*  闭包就像是一个流水线,而闭包的外层函数是一个工厂,通过给外层函数传递参数,来确定工厂的流水线
#TODO   考虑下面的例子,power是次方函数,接收参数exp,exp=2就是求2次方,exp=3就是求三次方,
#TODO   外层函数作为工厂,决定加工性质,而内层函数闭包作为流水线,将产品生产出来
#*  闭包,使得我们能够使用内层函数
def power(exp):
    def exp_of(base):
        return base ** exp
    return exp_of
square = power(2)
cube = power(3)
print(square(2), square(5), cube(2), cube(5))
#*  通过将工厂power赋一参数,得到流水线————内层函数,然后赋值给变量,
#*  这时,变量就是内层函数,也就是流水线,然后再进而给内层函数赋值,得到产品————结果

#*  内层函数具有记忆外层函数作用域的特性,因此可以用来记忆外层函数的变量
#*  通过nonlocal实现记忆外层函数变量的功能
def outer():
    x = 0
    y = 0
    def inner(x1, y1):
        nonlocal x, y
        x += x1
        y += y1
        print("现在,x = {}, y = {}".format(x, y))
    return inner
move = outer()
move(1, 2)
move(-2, 2)

#*  可以将函数作为参数传递给函数
def myfunc():
    print("正在调用myfunc...")
def report(func):
    print("我要开始调用函数了...")
    func()
    print("调用函数完毕")
report(myfunc)

#?  什么是装饰器?有一个目标函数,这个函数是我们想要调用的,
#?  装饰器就是创建一个闭包,然后对目标函数进行加工修饰,
#?  达到不改动目标函数的同时,增加函数的功能
#TODO   所以装饰器是通过闭包+函数作为参数来实现的
import time
def time_master(func):
    #*  闭包第一层函数参数用来接收外界函数
    def call_func():
        print("开始运行程序...")
        start = time.time()
        func()
        stop = time.time()
        print("结束程序运行...")
        print("一共耗费了{:.12f}秒".format(stop - start))
    return call_func    #*  返回内层函数

@time_master    #*通过@,我们将@下面的目标函数进行@内容的装饰,增加函数功能
#!  @time_master本质是:myfunc15 = time_master(myfunc15)
#!  所以,装饰器的本质就是将以定义好的函数myfunc15传入闭包内加工装饰成新的函数,
#!  然后返回给myfunc15自己,那么myfunc15本身就相当于给自己加了装饰。
def myfunc15():
    time.sleep(2)
    print("I love Python")
myfunc15()

#*  多重装饰,装饰顺序为从下至上
def add(func):
    def inner():
        x = func()
        return x + 1
    return inner
def cube(func):
    def inner():
        x = func()
        return x * x * x
    return inner
def square(func):
    def inner():
        x = func()
        return x * x
    return inner
@add
@cube
@square
def test():
    return 2
print(test())

#*  如果想给装饰器传入参数,那么我们可以给装饰器外层,即闭包外层再嵌套一个函数
#*  这个函数专门接收参数
def logger(msg):
    def time_counter(func):
        def call_func():
            start = time.time()
            func()
            stop = time.time()
            print("小{0}睡了{second:.2f}秒".format(msg, second = stop - start))
        return call_func
    return time_counter

@logger("A")
def funA():
    time.sleep(1)
    print("正在调用funA...")

@logger(msg = "B")
def funB():
    time.sleep(1)
    print("正在调用funB...")
funA()
funB()

squareX = lambda x : x * x
print(squareX(3))
print(type(squareX))
y = [lambda y: y * y, 2, 3]
print(y[0](y[1]), y[0](y[2]))
mapped = map(lambda x : ord(x) + 10, "Python")
print(list(mapped))

def counter():
    i = 0
    while i <= 5:
        yield i
        #*  yield将函数变成生成器函数
        #*  使用yield,将会暂停函数,但是函数的进程将会被记住,然后返回一个值,一次调用返回一次值
        i += 1
print("生成器:")
print(counter())
#*  当调用生成器函数,会返回生成器对象
for i in counter():
#*  从此我们知道,生成器实际上是一个迭代器,通过for的i每次调用生成器,
#*  相对于启动-关闭-启动-关闭...,由于for循环会自动调用next,因此在print i的时候
#*  会打印生成器的元素
    print(i)
c = counter()
print(next(c))
#TODO   通过next可以将生成器的元素打印出来
print("生成器不支持c[2]")
def fib():
    back1, back2 = 0, 1
    while 1:
        yield back1
        back1, back2 = back2, (back1 + back2)
f = fib()
print(next(f))
print(next(f))
print(next(f))
print(next(f))

def add(x, y):
    """两数做和
        x (int): 其中一个加数
        :param y:另外一个加数
        :param return:返回和
    """
    result = x + y
    print(f"两数相加的结果是:{result}")
    return result
add(1, 9)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值