Python面试问题

1、Python的可变数据类型和不可变数据类型

Python的基本数据类型

        1)Number(数字)  (bool布尔类型、int整型、float浮点型、complex复数等都归为Number数字类型)、2)String(字符串) 、3)Tuple (元组) 、4)List(列表)、5)Dictionary (字典)、6)Set(集合)

不可变类型的变量:

        在第一次赋值声明的时候,会在内存中开辟一块空间,用来存储这个变量被赋予的值,变量被声明后,变量的值就与开辟的内存空间绑定,我们不能修改存储在内存中的值,当我们想给此变量赋新值时,会开辟一块新的内存空间保存新的值。

        不可变数据类型有:number、string、tuple

可变类型的变量:

        在第一次赋值声明的时候,也会在内存中开辟一块空间,用来存储这个变量被赋予的值。我们能修改存储在内存中的值,当该变量的值发生了改变,它对应的内存地址不发生改变。可变数据类型变量中的值变化,地址不会变。若对变量进行重新赋值,则变量的地址也会改变。

        可变数据类型为:list、dict、set

2、深拷贝和浅拷贝的区别

浅拷贝:

        指的是计算机重新分配一块内存,创建一个新的对象,但里面的元素是原对象中各个元素(子对象)的引用。

浅拷贝的问题

        1)对于可变类型的元素,通过浅拷贝创建的新对象B的元素会随着原对象A的元素改变而改变;对于不可变类型的元素则没有此问题。

        2)但是对于原对象A新追加的元素c,新对象B不会增加对元素c的引用;

list_A = [[1, 2], (30, 40)]
list_B = list(list_A)
list1.append(100)
print("list_A:",list_A)
print("list_B:",list_B)
# 输出
list_A: [[1, 2], (30, 40), 100]
list_B: [[1, 2], (30, 40)]


list_A[0].append(3)
print("list_A:",list_A)
print("list_B:",list_B)
# 输出
list_A: [[1, 2, 3], (30, 40), 100]
list_B: [[1, 2, 3], (30, 40)]

浅拷贝的创建方式:

  • 使用数据类型本身的构造器,如:list(),tuple(),dict()
  • 对于可变的序列,还可以通过切片操作符" : ",即使用 [:] 来完成浅拷贝
  • Python 提供了copy.copy() 函数,适用于任何数据类型,具体用法如下所示
import copy

set1 = {1, 2, 3}
set2 = copy.copy(set1)
print(set2)
print("set1 == set2 ?",set1 == set2)
print("set1 is set2 ?",set1 is set2)

深拷贝:

        是指重新分配一块内存,创建一个新的对象,并且将原对象中的元素以递归的方式,通过创建新的子对象拷贝到新对象中。因此,新对象和原对象没有任何关联

深拷贝的创建方式:

        Python 提供了 copy.deepcopy() 来实现对象的深度拷贝,适用于任何数据类型,具体用法如下:

import copy

list1 = [[1, 2], (30, 40)]
list2 = copy.deepcopy(list1)
list1.append({"name":"ziyi", "age": 30})
print("list1:",list1)
print("list2:",list2)
# 输出
list1: [[1, 2], (30, 40), {'name': 'ziyi', 'age': 30}]
list2: [[1, 2], (30, 40)]

# 可变元素追加子元素
list1[0].append(3)
print("list1:",list1)
print("list2:",list2)
#输出
list1: [[1, 2, 3], (30, 40), {'name': 'ziyi', 'age': 30}]
list2: [[1, 2], (30, 40)]

3、Python中的闭包的理解

闭包的概念:

        在函数内部(嵌套)定义另一个函数时,如果内层的函数引用了外层的函数的变量,内层函数作为外层函数的返回,此时相对于外层函数的外部而言,这两个内层和外层函数的整体就是闭包。

def outer_fun(pos=[0,0]):
    
    def inner_fun(direction, step):
        new_x = pos[0]+direction[0]*step
        new_y = pos[1]+direction[1]*step
        
        pos[0] = new_x
        pos[1] = new_y
        
        return pos
    
    return inner_fun

# player实际上就是闭包inner_fun函数的一个实例对象
player = outer_fun()
print(player([1,0],10))
print(player([0,1],20))
print(player([-1,0],10))

闭包的作用:

作用1:闭包是将外层函数内的局部变量和外层函数的外部连接起来的一座桥梁,此时相当于外层函数的外部可以调用外层函数内的局部变量。
作用2:将外层函数的变量持久地保存在内存中。

        原因:原因在于outer_fun是inner_fun的父函数,而inner_fun被赋给了一个全局变量,这导致inner_fun始终在内存中,而inner_fun的存在依赖于outer_fun,因此outer_fun也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收

闭包的注意点:

        由于闭包会使得函数中的变量都被保存在内存中,会增加内存消耗,所以不能滥用闭包,否则会造成程序的性能问题,可能导致内存泄露。

闭包的使用场景:

        1、在需要既可以长久的保存变量又不会造成全局污染的场景,可以使用闭包。因为局部变量无法共享和长久的保存,而全局变量可能造成变量污染

        2、函数上方带参数的装饰器,那么一般都会生成闭包。

4、Python中装饰器的理解

装饰器的概念:

        就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能的函数。

请看下面示例代码:

import time


# 装饰器
def timmer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        print("装饰器内部,start={}".format(start))
        res = func(*args, **kwargs)
        print("res={}".format(res))
        stop = time.time()
        print("stop - start=".format(stop - start))
        return res

    return wrapper

# 语法糖:让你开心的语法
# 就是在被装饰对象正上方的单独一行写@装饰器名字
@timmer # index=timmer(index)
def index(x, y, z):
    print("index函数内部")
    time.sleep(3)
    print('index %s %s %s' % (x, y, z))

# 执行被装饰的函数
index(x=1, y=2, z=3)

装饰器执行原理:

        上面这一行代码相当于执行了以下两行代码,因为在被装饰的函数前一行加上了@装饰的名字器:(@timmer)

# 等号左边是timmer装饰器实例化后的index对象;
# 等号右边是前面定义的index()函数,它作为装饰器函数timmer的一个参数
index=timmer(index) 
# 调用index对象
index(x=1, y=2, z=3)

# 从被装饰函数的执行结果看执行过程,具体如下:
# 执行结果
"""装饰器内部,start=1675656150.551987
index函数内部
index 1 2 3
res=None
stop - start=3.0070817470550537"""
# 执行过程
# 1、装饰器函数实例化:index=timmer(index)
# 2、实例化的对象index被调用执行:index(x=1, y=2, z=3)
# 3、调用index对象的wrapper方法,按照里面的代码块执行,这个代码块里面就会调用原来封装的index()函数

5、JSON和字典的互相转化

JSON转字典:

        load()方法是从json文件读取json,返回字典对象

        loads()方法是将字符串形式的json转化为字典对象

以下是具体使用案例

test_json.json文件:

{"name": "广州", "area": "2000wan平米", "population": 2000000, "city": ["东莞", "佛山", "珠海"]}
import json

# 先说load()方法
with open("test_json.json", "r", encoding="utf-8") as f:
    # load()方法是从json文件读取json,返回字典对象
    data = json.load(f)
    print("load()方法加载的文件的json转化为:{},\n类型是{}".format(data, type(data)))

# 输出
# load()方法加载的文件的json转化为:{'name': '广州', 'area': '2000wan平米', 'population': 2000000},
# 类型是<class 'dict'>


# loads()方法
# loads()方法是将字符串形式的json转化为字典对象
json_str1 = """{"name": "广州", "area": "2000平米", "population": 2000000, "city": ["东莞", "佛山", "珠海"]}"""
data3 = json.loads(json_str1)
print("loads()方法加载的文件的json转化为:data3={},\n类型是{}".format(data3, type(data3)))

# 输出
# loads()方法加载的文件的json转化为:data3={'name': '广州', 'area': '2000平米', 'population': 2000000, 'city': ['东莞', '佛山', '珠海']},
# 类型是<class 'dict'>

字典转JSON:

        json.dumps是对python的字典对象编码成JSON对象的函数,可以把字典转成JSON字符串。

import json


ob = {'name': '广州', 'area': '2000wan平米', 'population': 2000000, "city": ["东莞", "佛山", "珠海"]}

with open("test_json.json", "w", encoding="utf-8") as f:
    # dump()方法是将字典对象转换为JSON对象并写入json文件, ensure_ascii=False 代表中文不转义
    json.dump(ob, f, ensure_ascii=False)

# dumps()方法将字典对象转换为JSON字符串, ensure_ascii=False 代表中文不转义
result = json.dumps(ob, ensure_ascii=False)
print(result, type(result))

# 输出
# {"name": "广州", "area": "2000wan平米", "population": 2000000, "city": ["东莞", "佛山", "珠海"]}
# <class 'str'>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值