【学习笔记】python字典、函数和闭包

╄→гoц情女王★ 提交于 2020-01-18 13:41:54
小整数对象池

在终端编译时,python中存在一个范围为[-5,256]的小整数对象池,这些整数对象是提前建立好的,不会被垃圾回收
所以,将同一个小整数赋值给不同变量,这些变量指向的内存地址都是一样的
例:

>>> age = 8
>>> other_age = 8
>>> print(age is other_age)
# True

而大整数不存在对象池,将同一个大整数赋值给不同变量,这些变量指向的内存地址是不一样的
例:

>>> money = 2000000
>>> salary = 2000000
>>> print(money is salary)
# False

这个时候,如果直接打开一个文本编辑器去尝试,你会发现,咦,怎么print(money is salary)打印出来的值为True啊,不是应该是False吗?

这是因为在文本编辑器编译时,python解析器会逐行编译,当发现两个变量引用的同一个整数值为一样,则会将这些变量指向同一个内存地址,最后编译完成后,再统一回收,而我们上述代码,都是在终端下执行的,终端是每次执行一次,执行一次就创建一次内存地址,所以打印出来的值为False

对称差集
list1 = [5,1,2,9,0,3]
list2 = [7,2,5,7,9]

set1 = set(list1)
set2 = set(list2)

result = set1.symmetric_difference(set2) # 或者 set1 ^ set2
# {0, 1, 3, 7}
字典常用操作

将一个元组放进字典与将一个列表放进字典里效果是一眼的

dict1 = dict((('name','odd'),('age',20)))
print(dict1) # {'name': 'odd', 'age': 20}

dict2 = dict([('name','odd'),('age',20)])
print((dict2)) # {'name': 'odd', 'age': 20}

对字典进行遍历,直接遍历,只会打引出key值

dict1 = {'张三':100,'王五':90,'李四':80,'赵六':95}
# 这样会把key值打出来
for i in dict1:
    if dict1.get(i) > 90:
        print(i)            # 可以这样比较大于90分的人
# 张三

使用dict.items()才会把字典的键值对转为列表包含元组的形式

dict1 = {'张三':100,'王五':90,'李四':80,'赵六':95}
for key,value in dict1.items():
    print(key,value)
# 张三 100
# 王五 90
# 李四 80
# 赵六 95

使用dict.values()会以列表的形式将字典里的全部值装进去

student = {'001': ('蔡徐坤', 21), '002': ('易烊千玺', 19), '003': ('王俊凯', 20), '004': ('迪丽热巴', 25)}


def print_boy(persons):
    if isinstance(persons, dict):
        values = persons.values()
        print(values)
        for name, age in values:
            print('{}的年龄是:{}'.format(name, age))

print_boy(student)
# dict_values([('蔡徐坤', 21), ('易烊千玺', 19), ('王俊凯', 20), ('迪丽热巴', 25)])
# 蔡徐坤的年龄是:21
# 易烊千玺的年龄是:19
# 王俊凯的年龄是:20
# 迪丽热巴的年龄是:25

dict.get(key,[default])
这个函数得到字典给定键key及对应的值,如果没有找到该键的值,会返回None,如果设置了默认值,则会返回默认值
在字典中,dict[key]语句和get()函数作用相同,dict[key]找不到对应的key则会报keyerror错误

dict.pop(key,[default])
这个函数删除字典给定键 key 及对应的值,返回值为被删除的值。key 值必须给出。 否则,返回 default 值
在字典中,del 语句和 pop() 函数作用相同,pop() 函数有返回值,del找不到对应的key则会报keyerror错误,但是pop()加了默认值之后则不会

函数常用操作
关于参数

python的函数可以传递普通参数、可变参数与关键字参数
普通参数在定义时,直接使用变量名定义
可变参数在定义时,在变量名前加上*进行定义
关键字参数在定义时,在变量名前加上**进行定义
例:

 def func(a, b, *args, **kwargs):
     print(a, b)
     print(args)
     print(kwargs)

传入可变参数里的值python底层会使用一个元组对其进行包装,如果定义了可变参数,又没有对其进行传值,则也可以看到这个可变参数为一个空元组

而传入关键字参数里的值python底层会使用一个字典对齐先拆包再装包,如果定义了关键字参数,又没有对其进行传值,则也可以看到这个可变参数为一个空字典
例:(使用的是上面同一个函数)

student = {'001': ('蔡徐坤', 21), '002': ('易烊千玺', 19),
 '003': ('王俊凯', 20), '004': ('迪丽热巴', 25)}
func(1, 2, **student)
# 1 2
# ()
# {'001': ('蔡徐坤', 21), '002': ('易烊千玺', 19), '003': ('王俊凯', 20), '004': ('迪丽热巴', 25)}
func(1, 2, 3, 4)
# 1 2
# (3, 4)
# {}

如果指定关键字参数的关键字,则python底层会将关键字作为字典的key值,关键字的值作为字典的value值
例:(使用的是上面同一个函数)

func(1, 2, 3, x=10, y=20)
# 1 2
# (3,)
# {'x': 10, 'y': 20}

ps:当向可变参数只传一个参数时,python底层会将参数用一个元组包裹这个元素,并在这个元素后加逗号,如上所示的(3,),而不是直接打印出(3)

当向可变参数传入一个列表时,python底层会将这个列表视为一个元素,所以与传入一个参数时效果是一样的
例:(使用的是上面同一个函数)

func(1, 2, [3, 4, 5, 6])
# 1 2
# ([3, 4, 5, 6],)
# {}

向一个可变参数,传入一个列表类型的变量时,如果在这个列表变量前加上*号,则表示对该列表变量进行拆包后,再向这个可变参数进行传参

而向一个关键字参数,传入一个字典类型的变量时,如果在字典变量前加上**号,则表示对该变量进行拆包再装包后,再向这个关键字参数进行传参

值得注意的是:当一个函数即接受可变参数,又接受关键字参数时,只加一个*号则表示仅对该字典变量进行拆包,此时python底层会将该字典变量的key值作为参数传入可变参数内
综合例子:(使用的是上面同一个函数)

func(1, 10, list1, x=2, y=3)
# 1 10
# ([2, 5, 8],)
# {'x': 2, 'y': 3}
func(1, 10, *list1, **dict1) # 在前面加*会进行拆包
# 1 10
# (2, 5, 8)
# {'x': 3, 'y': 6, 'z': 9}
func(1, 10, *list1, *dict1)  # 如果是key word arguments,在前面只有一个*则会进行一次拆包操作
# 1 10
# (2, 5, 8, 'x', 'y', 'z')
# {}
匿名函数

在python中使用匿名函数可以简化函数的定义
格式为:lambda 参数1,参数2:运算(返回值)
例:

func = lambda a, b: a + b
print(func)  
# <function <lambda> at 0x000001BA14A3CEE0>
result = func(1, 2)
print(result)  
# 3

可以看到,当使用一个变量去接受这个匿名函数时,返回的类型为function<lambda>函数类型

匿名函数可以作为参数使用
例:

def func(a, b, callback):  # callback为匿名回调函数
    print(a, b)
    print(callback(a, b))

func(2, 5, lambda a, b: a * b)
# 2 5
# 10

匿名函数与内置函数的结合使用
与max,求字典的某个key对应的value的最大值,例:

list1 = [3, 5, 7, 1, 8, 9, 0]
list2 = [{'a': 10, 'b': 20}, {'a': 15, 'b': 12}, {'a': 11, 'b': 22}, {'a': 14, 'b': 20}]

result = max(list2, key=lambda x: x['a'])
print(result)
# {'a': 15, 'b': 12}

与map,对列表的相应项进行操作,例:

list1 = [3, 4, 7, 5, 6, 4, 0, 1]

result = map(lambda x: x + 2 if x % 2 != 0 else x, list1)
print(list(result))
# [5, 4, 9, 7, 6, 4, 0, 3]

与reduce,对列表每一项进行快速运算,例:

from functools import reduce

list1 = [3, 4, 7, 5, 6, 4, 0, 1]

result = reduce(lambda x, y: x + y, list1)
print(result)
# 30

ps:有关map()、reduce()函数使用可以看👉Python入门基础之map()、reduce()函数使用

与filler,对列表每一项进行过滤,例:

list1 = [3, 4, 7, 5, 6, 4, 0, 1]

result = filter(lambda x: x > 5, list1)
print(list(result))
# [7,6]

与sorted,对列表从大到小排列,例:

students = [
    {'name': '小宇', 'age': 21},
    {'name': '陈老师', 'age': 22},
    {'name': '老哥', 'age': 22},
    {'name': '黄总', 'age': 19}
]

result = sorted(students, key=lambda x: x['age'], reverse=True)
print(result)
# [{'name': '陈老师', 'age': 22}, {'name': '老哥', 'age': 22}, 
# {'name': '小宇', 'age': 21}, {'name': '黄总', 'age': 19}]
修改局部变量与全局变量

全局变量如果是不可变类型(如字符串、数字、布尔值、元组),在函数中修改则需要加 global 关键字
全局变量如果是可变类型(如字典、列表),在函数中修改则不需要加 global 关键字

同理,局部变量如果是不可变类型,在内部函数中修改则需要加 nonlocal 关键字
局部变量如果是可变类型,在内部函数中修改则不需要加 nonlocal 关键字
ps:内部函数为一个函数中的函数(既函数的嵌套)

locals() 查看本地(内部)的变量,以字典的形式输出
globals() 查看全局的变量,以字典形式输出(注意里面会有一些系统的键值对)

闭包

闭包,又称闭包函数或者闭合函数,其实和前面讲的嵌套函数类似,不同之处在于,闭包中外部函数返回的不是一个具体的值,而是一个函数。一般情况下,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。

闭包形成的条件:

  • 1.在外部函数中定义了内部函数
  • 2.外部函数有返回值
  • 3.返回值为内部函数名
  • 4.内部函数引用了外部函数的变量

格式大概为:

def 外部函数():
        外部函数变量 = x
        
        def 内部函数():
            内部函数变量 = y
            print(外部函数变量,内部函数变量)
        
        return 内部函数
        
变量 = 外部函数()
变量()  # 执行函数

例:

def func():
    a = 1

    def inner_func():
        b = 2
        print(a, b)

    return inner_func

x = func()
x() # 1 2

闭包的作用:

  • 1.闭包优化了变量,原来需要类对象完成的工作,闭包也可以完成
  • 2.由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,占用内存
  • 3.闭包的好处:使代码变得简洁,便于阅读代码
  • 4.闭包是理解装饰器的基础

闭包简单应用之计数器:

def counter():
    i = 0

    def add_one():
        nonlocal i
        i += 1
        print('当前是第{}次访问'.format(i))

    return add_one


count = counter()

count()  # 当前是第1次访问
count()  # 当前是第2次访问
count()  # 当前是第3次访问
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!