栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

python关于函数的零碎知识点

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

python关于函数的零碎知识点

  • return后面的值如果有逗号,则默认会将返回值转换成元组再返回。
def func():
    return 1,2,3

value = func()
print(value) # (1,2,3)
  • 关于地址
v1 = [11,22,33]
v2 = v1
print( id(v1),id(v2) )
#指向同一块地址

v1 = [11,22,33]
v2 = [11,22,33]
print( id(v1),id(v2) )
#指向不同地址


# 对于不可变类型如str等 python内部优化存储在缓存中
v1 = 3
v11 = 3
print(id(v1),id(v11))
#指向同一块地址
  • Python的参数默认传递的是内存地址
def func(data):
    print(data, id(data))  # xxx  140247057684592

v1 = "xxx"
print(id(v1))  # 140247057684592

func(v1)

Python参数的这一特性有两个好处:

  • 节省内存

  • 对于可变类型且函数中修改元素的内容,所有的地方都会修改。可变类型:列表、字典、集合。

# 可变类型 & 修改内部修改
def func(data):
    data.append(999)
    
v1 = [11,22,33]
func(v1)

print(v1) # [11,22,33,666]
# 特殊情况:可变类型 & 重新赋值
def func(data):
    data = ["卢本伟","alex"] #data指向的地址从[11,22,33]改变为["卢本伟","alex"]
    
v1 = [11,22,33]
func(v1)

print(v1) # [11,22,33]
# 特殊情况:不可变类型,无法修改内部元素,只能重新赋值。
def func(data):
	data = "alex"
    
v1 = "卢本伟"
func(v1)

其他很多编程语言执行函数时,默认传参时会将数据重新拷贝一份,会浪费内存。

提示注意:其他语言也可以通过 ref 等关键字来实现传递内存地址。

  •  global关键字

默认情况下,在局部作用域对全局变量只能进行:读取和修改内部元素(可变类型),无法对全局变量进行重新赋值。

如果想要在局部作用域中对全局变量重新赋值,则可以基于 global关键字实现,例如:

COUNTRY = "中国"
CITY_LIST = ["北京","上海","深圳"]

def download():
    url = "http://www.xxx.com"
	
    global CITY_LIST
    CITY_LIST =  ["河北","河南","山西"]
    print(CITY_LIST)
    
    global COUNTRY
    COUNTRY = "中华人民共和国"
    print(COUNTRY)

def upload():
    file_name = "rose.zip"
    print(COUNTRY)
    print(CITY_LIST)
    
download()
upload()

其实,还有一个nolocal关键字,用的比较少,此处作为了解即可。  

name = 'root'


def outer():
    name = "武沛齐"

    def inner():
        nonlocal name
        name = 123

    inner()
    print(name)


outer()
print(name)
name = 'root'


def outer():
    name = 'alex'

    def func():
        name = "武沛齐"

        def inner():
            nonlocal name
            name = 123

        inner()
        print(name)

    func()
    print(name)


outer()
print(name)
'''
123
alex
root
'''

 

name = 'root'


def outer():
    name = 'alex'

    def func():
        nonlocal name
        name = "武沛齐"

        def inner():
            nonlocal name
            name = 123

        inner()
        print(name)

    func()
    print(name)


outer()
print(name)

'''
123
123
root
'''

当然,如果你不想让外部的变量和函数内部参数的变量一致,也可以选择将外部值拷贝一份,再传给函数。

import copy


# 可变类型 & 修改内部修改
def func(data):
    data.append(999)


v1 = [11, 22, 33]
new_v1 = copy.deepcopy(v1) # 拷贝一份数据
func(new_v1)

print(v1)  # [11,22,33]
  • 函数的返回值是内存地址
def func():
    data = [11, 22, 33]
    return data

v1 = func()
print(v1) # [11,22,33]

上述代码的执行过程:

  • 执行func函数

  • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址。

  • return data 返回data指向的内存地址

  • v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)

  • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

所以,最终v1指向的函数内部创建的那块内存地址。

def func():
    data = [11, 22, 33]
    return data

v1 = func()
print(v1) # [11,22,33]

v2 = func()
print(v2) # [11,22,33]

上述代码的执行过程:

  • 执行func函数

  • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址 1000001110。

  • return data 返回data指向的内存地址

  • v1接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)

  • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

所以,最终v1指向的函数内部创建的那块内存地址。(v1指向的1000001110内存地址)

  • 执行func函数

  • data = [11, 22, 33] 创建一块内存区域,内部存储[11,22,33],data变量指向这块内存地址 11111001110。

  • return data 返回data指向的内存地址

  • v2接收返回值,所以 v1 和 data 都指向 [11,22,33] 的内存地址(两个变量指向此内存,引用计数器为2)

  • 由函数执行完毕之后,函数内部的变量都会被释放。(即:删除data变量,内存地址的引用计数器-1)

所以,最终v2指向的函数内部创建的那块内存地址。(v2指向的11111001110内存地址)

 

  • 函数的参数问题

# 在函数内存中会维护一块区域存储 [1,2,666,666,666] 100010001
def func(a1,a2=[1,2]):
    a2.append(666)
    print(a1,a2)

# a1=100
# a2 -> 100010001
func(100) # 100  [1,2,666]

# a1=200
# a2 -> 100010001
func(200) # 200 [1,2,666,666]

# a1=99
# a2 -> 1111111101
func(99,[77,88]) # 66 [77,88,666]

# a1=300
# a2 -> 100010001
func(300) # 300 [1,2,666,666,666] 

大坑

# 在内部会维护一块区域存储 [1, 2, 10, 20,40 ] ,内存地址 1010101010
def func(a1, a2=[1, 2]):
    a2.append(a1)
    return a2

# a1=10
# a2 -> 1010101010
# v1 -> 1010101010
v1 = func(10)
print(v1) # [1, 2, 10]

# a1=20
# a2 -> 1010101010
# v2 -> 1010101010
v2 = func(20)
print(v2) # [1, 2, 10, 20 ]

# a1=30
# a2 -> 11111111111        [11, 22,30]
# v3 -> 11111111111
v3 = func(30, [11, 22])
print(v3) #  [11, 22,30]

# a1=40
# a2 -> 1010101010
# v4 -> 1010101010
v4 = func(40)
print(v4) # [1, 2, 10, 20,40 ] 

深坑

# 内存中创建空间存储 [1, 2, 10, 20, 40] 地址:1010101010
def func(a1, a2=[1, 2]):
    a2.append(a1)
    return a2

# a1=10
# a2 -> 1010101010
# v1 -> 1010101010
v1 = func(10)


# a1=20
# a2 -> 1010101010
# v2 -> 1010101010
v2 = func(20)

# a1=30
# a2 -> 11111111111   [11,22,30]
# v3 -> 11111111111
v3 = func(30, [11, 22])

# a1=40
# a2 -> 1010101010
# v4 -> 1010101010
v4 = func(40)

print(v1) # [1, 2, 10, 20, 40]
print(v2) # [1, 2, 10, 20, 40]
print(v3) # [11,22,30]
print(v4) # [1, 2, 10, 20, 40] 
  • 动态参数

动态参数,定义函数时在形参位置用 *或** 可以接任意个参数。

def func(*args,**kwargs):
    print(args,kwargs)
    
func("宝强","杰伦",n1="alex",n2="eric")

在定义函数时可以用 *和**,其实在执行函数时,也可以用。

        形参固定,实参用*和**

def func(a1,a2):
    print(a1,a2)
    
func( 11, 22 )
func( a1=1, a2=2 )

func( *[11,22] )
func( **{"a1":11,"a2":22} )

        形参用*和**,实参也用 *和**(有坑)

def func(*args,**kwargs):
    print(args,kwargs)
    
func( 11, 22 )
func( 11, 22, name="武沛齐", age=18 )

# 小坑,([11,22,33], {"k1":1,"k2":2}), {}
func( [11,22,33], {"k1":1,"k2":2} )

# args=(11,22,33),kwargs={"k1":1,"k2":2}
func( *[11,22,33], **{"k1":1,"k2":2} ) 

# 值得注意:按照这个方式将数据传递给args和kwargs时,数据是会重新拷贝一份的(可理解为内部循环每个元素并设置到args和kwargs中)。

例如:

def func(*args,**kwargs):
    print(args,kwargs)
    
params = {"k1":"v2","k2":"v2"}
func(params)    # ({"k1":"v2","k2":"v2"}, ) {}
func(**params)  # (), {"k1":"v2","k2":"v2"}

所以,在使用format字符串格式化时,可以可以这样:

v1 = "我是{},年龄:{}。".format("武沛齐",18)
v2 = "我是{name},年龄:{age}。".format(name="武沛齐",age=18)


v3 = "我是{},年龄:{}。".format(*["武沛齐",18])
v4 = "我是{name},年龄:{age}。".format(**{"name":"武沛齐","age":18})
  • 函数名可以做参数,注意是函数名,加括号后相当于执行函数了。
def send_message(phone,content):
    """发送消息"""
    pass


def send_image(img_path, content):
    """发送图片"""
    pass


def send_emoji(emoji):
    """发送表情"""
    pass


def send_file(path):
    """发送文件"""
    pass


function_dict = {
    "1": [ send_message,  ['15131255089', '你好呀']],
    "2": [ send_image,  ['xxx/xxx/xx.png', '消息内容']],
    "3": [ send_emoji, [""]],
    "4": [ send_file, ['xx.zip'] ]
}

print("欢迎使用xx系统")
print("请选择:1.发送消息;2.发送图片;3.发送表情;4.发送文件")
choice = input("输入选择的序号") # 1

item = function_dict.get(choice) # [ send_message,  ['15131255089', '你好呀']],
if not item:
    print("输入错误")
else:
    # 执行函数
    func = item[0] # send_message
    param_list = item[1] #  ['15131255089', '你好呀']
    
    func(*param_list) # send_message(*['15131255089', '你好呀'])
  • 将函数名赋值给其他变量,函数名其实就个变量,代指某函数;如果将函数名赋值给另外一个变量,则此变量也会代指该函数,例如:
def func(a1,a2):
    print(a1,a2)

xxxxx = func

# 此时,xxxxx和func都代指上面的那个函数,所以都可以被执行。
func(1,1)
xxxxx(2,2)
  • 对函数名重新赋值,如果将函数名修改为其他值,函数名便不再代指函数,例如:
def func(a1,a2):
    print(a1,a2)

# 执行func函数
func(11,22)

# func重新赋值成一个字符串
func = "lbw"

print(func)
def func(a1,a2):
    print(a1+a2)
    
func(1,2)

def func():
    print(666)
    
func()

注意:由于函数名被重新定义之后,就会变量新被定义的值,所以大家在自定义函数时,不要与python内置的函数同名,否则会覆盖内置函数的功能,例如:

# len内置函数用于计算值得长度
v1 = len("武沛齐")
print(v1) # 3

# len重新定义成另外一个函数
def len(a1,a2):
    return a1 + a2

# 以后执行len函数,只能按照重新定义的来使用
v3 = len(1,2)
print(v3)

  • 局部作用域和全局作用域变量同名

以内部为主 内部没有,去上一级/全局寻找

a = 222
b = 333

def fuc():
    b = 123
    c = 456
    print(a, b, c)

fuc()
print(b, '全局')

'''
222 123 456
333 全局
'''

def func(*args, **kwargs):
    print(args, kwargs)
    return "完毕"


v1 = func(11, 22, 33)
print(v1)

v2 = func([11, 22, 33])
print(v2)

v3 = func(*[11, 22, 33])
print(v3)

v4 = func(k1=123, k2=456)
print(v4)

v5 = func({"k1": 123, "k2": 456})
print(v5)

v6 = func(**{"k1": 123, "k2": 456})
print(v6)

v7 = func([11, 22, 33], **{"k1": 123, "k2": 456})
print(v7)

v8 = func(*[11, 22, 33], **{"k1": 123, "k2": 456})
print(v8)
'''
(11, 22, 33) {}
完毕
([11, 22, 33],) {}
完毕
(11, 22, 33) {}
完毕
() {'k1': 123, 'k2': 456}
完毕
({'k1': 123, 'k2': 456},) {}
完毕
() {'k1': 123, 'k2': 456}
完毕
([11, 22, 33],) {'k1': 123, 'k2': 456}
完毕
(11, 22, 33) {'k1': 123, 'k2': 456}
完毕
'''
Process finished with exit code 0

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/323943.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号