python基础知识 续

该笔记主要记录python函数相关内容,包括:

  • 函数概念
  • 函数参数和返回值
  • 匿名函数、偏函数
  • 闭包、生成器

以下为主要内容:

一、函数概念

函数,即将一段实现某功能的代码集中在一起,赋予特殊名字,再次使用该功能时,使用函数名字直接调用这个代码块。

函数作用:使代码模块化,逻辑清晰、代码重用;

函数分类:内建函数、自定义函数;

函数定义及参数:
  • 单个参数:def function(parament): {\n} body
  • 不定长参数:def function(*parament): {\n} body,其中的(*参数)表示函数参数是不定长的,函数体中可以直接以元组变量的方式使用该参数。
  • 不定长参数:def function(**parament): {\n} body,其中的(**参数)表示函数参数是不定长的,函数体中可以直接以字典变量的方式使用该参数。

示例:

# 示例1
def prin():
    print("this is body")
#调用
prin() #this is body

#示例2
def test(num):
    print(num**2)    
# 调用
test(2) #4

# 示例3,计算两数之和
def mySum(num1,num2):
    print(num1+num2)
mySum(2,3) # 5

不定长参数,函数调用示例:

# 方式一:元组,参数
def mySum(t):
    result=0;
    for v in t:
        result+=v;
    print(result)
mySum((2,3,4))  #参数是一个元组

# 方式二:不定长,参数
def mySum(*t):  #表示接受不定长参数
    result=0;
    for v in t:
        result+=v;
    print(result)
mySum(2,3,4)    #注意与方式一的区别

参数拆包

先看两个概念:

  • 装包:把传递的参数,包装成一个集合,称之为“装包”;
  • 拆包(解包):分解集合参数;

元组变量方式,拆包示例:

def mySum(a,b,c,d):
    print(a+b+c+d)

def test(*args):
    print(args)  #(1 2 3) ,是集合
    #拆包
    print(*args) # 1 2 3  ,是个体  
    
    #调用函数
    mySum(args) # error
	mySum(args[0],args[1],args[2],args[3])# 等同于 mySum(1,2,3,4),输出10
    
    #拆包方式:
    mySum(*args) # 10

    
test(1,2,3,4)

字典参数方式,拆包示例:

def mySum(a,b):
    print(a)
    print(b)
    
def test(**keys):
    print(keys) # {'a':1,'b':2}
    mySum(**keys)# 1  2 等同于mySum(a=1,b=2)
    
test(a=1,b=2)    # 与函数中的 a,b 必须对应
缺省参数

定义:def 函数名(变量1=默认值,变量2=默认值,...,):函数体,默认值即缺省参数,调用函数的时候,如果没有参数传递过来,就使用该默认值。

关于参数的一点补充:

先看两个概念:

  • 值传递:指传递过来的是一个数据的副本;
  • 引用传递:指传递过来的是一个变量的地址,通过该地址,可以直接操作原始数据;

但是,在python中,只有引用传递(地址传递),但不一定可以修改原始数据,代码验证:

# 如果id相同,则说明为引用传递

def change(num):
    print(id(num))

b=10
print(id(b))
change(b)

​```
输出:
1642...1168
1642...1168
id相同,说明变量num与变量b的内存地址是相同的。

​```

# 虽然引用传递,但不一定能修改原始数据。

def change(num):
    print(num)
    print(id(num))
    num=15 # 虽然引用传递,但不一定能修改原始数据。此处重新开辟空间。
    print(num)
    print(id(num))

b=10
change(b)  
print(b) #10 原始数据没有被改变    
    
函数返回值

看代码:

# 示例1
def muSum(a,b):
    resutl=a+b
    return result
res=mySum(5,6)
print(res)

# 示例2
def caculate(a,b):
    div=a-b;
    su=a+b
    return (div,su)

res=caculate(5,10) #返回结果是元组,所以对元组进行拆包
print(res[0]) 
print(res[1])
#或者
print(div)
print(su)

Note:

  • return 之后的语句不会被执行;
  • 如果要返回多个数据,可以将数据包装成一个集合;
函数使用描述

在编写第三方函数的时候,描述函数功能和使用方式等信息。在函数体最上面添加三个双引号对注释。

一般,函数描述需要有如下信息:

  • 函数功能;
  • 参数:类型,是否缺省,默认值;
  • 函数返回值

示例:

def caculate(a,b=1):
    #会默认生成一些函数说明
    """
    # 描述信息示例
    param a: 数值1,数值,不可选,没有默认值
    param b: 数值2,数值,可选,默认值:1
    return : 返回计算结果,元组:(和,差)
    """
    div=a-b;
    su=a+b
    return (div,su)

# 添加一个help
help(caculate) #不是函数调用,所以不需要写为help(caculate())

二、偏函数

写一个参数较多的函数时,有些是固定值,为了简化使用,可以创建一个新函数,指定要使用的函数的某个参数,这个新函数就是"偏函数"。

生成一个偏函数,需要调用模块:functools

示例:

import functools

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

newFunc=functools.partial(test,c=5) #函数名,不要加()     
newFunc(1,2)    # 9  即1+2+5+1
偏函数示例

偏函数的一个使用场景:将二进制字符串转为十进制数。

代码:

#二进制字符串,转为十进制
numStr="10010"
result=int(numStr,base=2) # 转为2进制
print(result)


# 偏函数的一个使用场景:将二进制字符串转为十进制数。

import functools
int2=functools.partial(int,base=2) # 指定int函数,偏向base参数

print(int2(numStr))

四、高阶函数

当一个函数的某一个参数接收的是另一个函数的时,则把这个函数成为“高阶函数”。如排序。

示例:

l=[{"name":ss,"age":18},{"name":kk,"age":19},{"name":cc,"age":20}]

def getKey(x):
    return x["age"]
result=sorted(l,key=getKey)
print(result)

三、返回函数

返回函数,指函数内部,它返回的是另外一个函数。常用于:根据不同的参数,进行不同的操作,做不同的计算。

看代码:

def getFun(flag):
    # 根据不同的flag,返回不同的操作函数
    def sum(a,b,c):
        return a+b+c
    def div(a,b,c):
        return a-b-c
    if(flag=="+")
    	return sum
    elif flag=="-"
    	return div
    
result=getFun("+")  
res=result(1,3,5)  # 函数
print(res) # 9
四、匿名函数(lambda函数)

语法:lambda para1,para2,...,表达式,需要注意的几点:

  • 不能直接return,只能写一个表达式;
  • 表达式的结果就是返回值;
  • 不建议过于复杂;

示例:

lambda x,y : x+y  #本身就是函数
lambda x,y : x+y  #后面加(parament)表示调用该函数

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


# 或者 
newFunc=lambda x,y : x+y
print(newFunc(4,5))

lambda表达式使用场景,以sorted函数为例:

l=[{"name":ss,"age":18},{"name":kk,"age":19},{"name":cc,"age":20}]

result=sorted(l,key=lambda x:x["name"])

print(result)

五、闭包

闭包,指

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

把内层函数和其引用的外层变量,称为闭包;

闭包示例1:

def test():
    a=10
    def test2():
        print(a) # 内层函数引用了外部变量
        
    return test2 # 将内层函数作为返回值   
        
newFunc=test()  # 是个函数了
newFunc() # 10

闭包示例2:

def line_config(content,length):
    print("-"*(length // 2 ) + content + "-"*(length //2 ))    #  // 整除
line_config("line",20)
line_config("line",20)
line_config("line",20)
# 冗余

#使用闭包
def line_config(content,length):
    def line():
    	print("-"*(length // 2 ) + content + "-"*(length //2 ))    #  // 整除
    return line
    
line1=line_config("line",20) # 函数

# 调用函数
line1()
line1()
line1()

Notes:

  • 闭包中,如果要修改引用的外层变量,需要使用nonlocal声明,否则会被当作新定义的变量;看示例1;

  • 闭包中引用了一个可能会发生变化的变量时,要注意。看示例2;

示例1:

def test():
    num=10
    print(num)
    def test2():
    #    num=66 #  新变量
    # 要修改num,需要:
    	nonlocal num
    	num=66
		print(num)
		return test2
    print(num)
result=test() 
result()
'''
10
66
10
'''

示例2

def test():
    a=1
    def test2()
    	print(a)
    a=2
    return test2   

newF=test() 
nuwf() # 问:是打印a=1,还是a=2 ?
# 2 

#解释:当函数被调用的时候,才会真正的确定,对应变量的值,在此之前,都是以变量标识名称而存在。

在函数闭包中,返回多个函数,可以使用列表,看示例3:

def test():
    func=[]  # 列表,存放返回的多个函数
    for i in range(1,4):
        def test2():
            print(i)
        func.append(test2)
    return func

newFuncs=test()
newFuncs() # 3 个 函数,而且地址各不同

newFuncs[0]()
newFuncs[1]()
newFuncs[2]() # 调用函数
'''
输出为:
3
3
3
解释在下一行
'''

解释:函数调用输出值都为3,原因同示例2:当函数被调用的时候,才会真正的确定,对应变量的值(这个示例里面,i值为3),在此之前,都是以变量标识名称而存在的。

可以使用参数作为函数内部变量,而不是闭包内调用外部参数,看示例4:

def test():
    func=[]  # 列表,存放返回的多个函数
    for i in range(1,4):
        def test2(num):
            def inner():
            	print(num)
            return inner
        func.append(test2(i))
    return func

newFuncs=test()
newFuncs[0]()
newFuncs[1]()
newFuncs[2]() # 调用函数

'''输出
1
2
3
'''
六、装饰器(设计模式之一)

先看示例:

#装饰器格式:
def checkLogin(func):
    def inner():
        print("登录验证")
        func() 			# 使装饰器可变,至关重要。
    return inner

# 2个功能性函数

@checkLogin  #装饰器
def fss():
    print("说说")
    
@checkLogin  # 等价于 ftp=checkLogin(ftp) ,先执行右边
def ftp():
    print("图片")
    
'''
装饰器语句等价于:
def ftp():
	print("图片")
	ftp=checkLogin(ftp)
'''

# 逻辑代码
btIndex=1
if(btIndex==1):
    fss()
else:
    ftp()

    
# 输出
'''
登录验证
图片
'''

Note:

  • 装饰器是直接执行;
  • 装饰器叠加时,从上到下装饰,但执行是从下往上执行;

对有参函数装饰:

# 定长参数
def orna(func):
    def inner(n1,n2):
        print("*"*30)
        func(n1,n2) 			# 使装饰器可变,至关重要。
    return inner

@orna
def pnum(n1,n2): # 则装饰器中,也要有参数。 
    print(n1,n2)
    
pnum(123,234)

# 不定长参数
def orna(func):
    def inner(*args,**keys):
        print("*"*30)
        print(args,keys)
        func(*args,**keys) 			# 使装饰器可变,至关重要。
    return inner

@orna
def pnum(n1,n2,n3): # 则装饰器中,也要有参数。 即保持一致
    print(n1,n2,n3)
    
pnum(123,234,n3=66)

'''
******
(123,234) {"n3":66}
'''

七、生成器

生成器,即一个特殊的迭代器,其拥有迭代器的特性:

  • 惰性计算数据,省内存;
  • 能够记录状态,并通过next()函数,访问下一个状态;
  • 具有可迭代性;

创建方式:

  • 生成器表达式:列表推导式[]修改为(),看示例1;
  • 生成器函数:函数中必须包含yield语句,该函数执行结果就是生成器;yeild可以阻断当前函数执行,当使用next()函数时,会继续向下执行,直到下一个yeild,看示例2

示例1:

l=[i for i in range(1,10000) if i%2==0]
print(l)
# [2,4,...]

# 不需要一次性生成所有数据,所以借助于生成器:

l=(i for i in range(1,10000) if i%2==0)
print(l)
# <generator object...>
# 生成器是特殊的迭代器,所以具有状态记录的特性
print(next(l))
# 或
for i in l:
    print(i)

示例2:

def test():
    yeild 1    # 1 为状态值 
    print("a")
    
    yeild 2
    print("b")
g=test()
print(g)
#<generator object...>
# 访问
print(next(g)) # 1
print(next(g)) # 1 a 2

def test():
    for i in range(1,9):
        yeild i

g=test()
print(g)
'''
输出
1
2
3
4
5
'''

生成器的几个方法:

send()方法:

  • send方法有一个参数,指定的是上一次被挂起的yeild语句的返回值;若用于第一次启动函数时使用,则可以传值None
  • 相比于__next()__,它可以额外的给yeild语句传值;
  • 第一次调用:send(None)

看代码:

def test():
    print("***")
    res1=yeild 1
    print(res1)
    
    res2=yeils 2
    print(res2)   
g=test()
print(g.__next()__()) # 开始执行函数,在 res1=yeild 1 挂起
print(g.__next()__())
''' 
*** 
1
None   #  print(res1) ,但没有得到res1的值
2
'''


# 看seed 方法:
def test():
    print("***")
    res1=yeild 1  # = "xxx"
    print(res1)
    
    res2=yeils 2
    print(res2)   
g=test()
print(g.send(None))
print(g.send("xxx"))
'''
***
1
xxx
2

'''

生成器关闭:close()方法:

def test():
    yeild 1    
    print("a")
    
    yeild 2
    print("b")
    
g=test()
print(g.__next()__())
print(g.__next()__())
g.close() #关闭生成器

补充

递归函数示例:

def jiecheng(n):
    if n==1:
        return 1
    else:
        return n*jiecheng(n-1)
    
result=jiecheng(5)
print(result)
# 120

函数作用域

几个概念:

  • 变量的作用域:python是静态作用域,即变量的作用域源于它在代码中的位置,在不同的位置,可能会有不同的命名空间;

  • 命名空间:作用域的体现形式,是一个具体的操作范围;

  • 局部变量:是在一个函数内部定义的变量,作用域为函数内部。查看方式:locals();

  • 全局变量:是在一个函数外部(或文件最外部定义的变量),作用域为整个文件;

未完,待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值