python 面试题第一弹
1. 如何理解Python中的深浅拷贝
浅拷贝(Shallow Copy)创建一个新的对象,该对象的内容是原始对象的引用。这意味着新对象与原始对象共享相同的内存地址,因此对于可变对象来说,如果修改了其中一个对象,另一个对象也会受到影响。浅拷贝通常使用copy
模块的copy()
函数或者对象的copy()
方法来完成。
下面是一个浅拷贝的示例:
import copy original_list = [1, 2, [3, 4]]
copied_list = copy.copy(original_list) print(original_list) # [1, 2, [3, 4]]
print(copied_list) # [1, 2, [3, 4]] # 修改原始列表中的元素
original_list[0] = 10
original_list[2][0] = 30 print(original_list) # [10, 2, [30, 4]]
print(copied_list) # [1, 2, [30, 4]]
在上面的示例中,copy.copy()
函数创建了original_list
的浅拷贝copied_list
。当我们修改original_list
时,copied_list
中的嵌套列表也会受到影响。
深拷贝(Deep Copy)创建一个新的对象,该对象的内容是原始对象及其所有嵌套对象的副本。这意味着新对象在内存中是完全独立的,对其中一个对象的修改不会影响另一个对象。深拷贝通常使用copy
模块的deepcopy()
函数或者对象的deepcopy()
方法来完成。
下面是一个深拷贝的示例:
import copy original_list = [1, 2, [3, 4]]
deep_copied_list = copy.deepcopy(original_list) print(original_list) # [1, 2, [3, 4]]
print(deep_copied_list) # [1, 2, [3, 4]] # 修改原始列表中的元素
original_list[0] = 10
original_list[2][0] = 30 print(original_list) # [10, 2, [30, 4]]
print(deep_copied_list) # [1, 2, [3, 4]]
在上面的示例中,copy.deepcopy()
函数创建了original_list
的深拷贝deep_copied_list
。即使我们修改original_list
,deep_copied_list
中的嵌套列表也不会受到影响。
需要注意的是,深拷贝可能会比浅拷贝更耗费时间和内存,因为它需要递归地复制所有嵌套对象。因此,在处理大型对象或嵌套层级很深的对象时,需要谨慎使用深拷贝。
总结起来,浅拷贝创建一个新对象,该对象与原始对象共享部分内存,而深拷贝创建一个完全独立的新对象,它复制了原始对象及其所有嵌套对象的内容。根据需求选择适当的拷贝方式可以帮助我们正确地处理对象并避免意外的副作用。
2. 谈谈 is 和 == 的区别:
在Python中,is
和==
是用于比较对象的运算符,它们具有不同的功能和用途。
is
运算符用于比较两个对象的身份标识,即它们是否指向同一个内存地址。如果两个对象具有相同的身份标识,即它们是同一个对象,那么is
运算符返回True
;否则,返回False
。
==
运算符用于比较两个对象的值是否相等。它会比较两个对象的内容,而不关心它们是否指向同一个内存地址。如果两个对象的值相等,==
运算符返回True
;否则,返回False
。
下面是一个示例,展示了is
和==
运算符的区别:
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = list1 print(list1 is list2) # False,list1和list2不是同一个对象
print(list1 is list3) # True,list1和list3是同一个对象 print(list1 == list2) # True,list1和list2的值相等
在上面的示例中,list1
和list2
虽然具有相同的值,但它们是不同的对象,因此list1 is list2
返回False
。另一方面,list1
和list3
指向同一个对象,因此list1 is list3
返回True
。而list1 == list2
返回True
,因为它们的值相等。
需要注意的是,对于简单的值类型(如整数、字符串等),is
和==
的结果通常是一致的。但对于可变对象(如列表、字典等),is
和==
的结果可能不同,因为可变对象的身份标识可能相同,但值不同。
总结起来,is
运算符用于比较两个对象的身份标识,即它们是否指向同一个内存地址;而==
运算符用于比较两个对象的值是否相等。在编写代码时,需要根据具体的需求选择适当的运算符。如果要比较对象的值,应使用==
运算符;如果要比较对象的身份标识,应使用is
运算符。
3. 说说闭包和装饰器的概念:
**闭包(Closure)**是指在一个函数内部定义的函数,并且内部函数可以访问外部函数的变量。闭包可以捕获和保持外部函数的状态,即使外部函数已经执行完毕,内部函数仍然可以使用那些被捕获的变量。闭包在需要保持某些状态或者提供数据隐藏时非常有用。
下面是一个闭包的例子:
def outer_function(x):
def inner_function(y):
return x + y
return inner_function closure = outer_function(10)
result = closure(5)
print(result) # 输出 15
在上面的例子中,outer_function
是外部函数,它接受一个参数x
并返回一个内部函数inner_function
。内部函数inner_function
可以访问外部函数outer_function
的参数x
,即使在outer_function
执行完毕后仍然有效。
**装饰器(Decorator)**是一种特殊的闭包,用于修改或增强函数的功能而不修改函数本身的定义。装饰器通常用于添加额外的代码,例如日志记录、性能分析、输入验证等。装饰器可以在不修改原函数代码的情况下,对函数进行包装和扩展。
下面是一个简单的装饰器的例子:
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} executed.")
return result
return wrapper @logger
def add(a, b):
return a + b result = add(2, 3)
print(result) # 输出 5
在上面的例子中,logger
是一个装饰器函数,它接受一个函数作为参数,并返回一个新的函数wrapper
。wrapper
函数在调用被装饰的函数之前和之后打印日志信息。
通过使用@logger
语法,我们将装饰器应用到add
函数上。当调用add
函数时,实际上是调用了被装饰后的wrapper
函数,从而实现了日志记录的功能增强。
实际应用中,闭包和装饰器有许多用例。以下是一些示例:
- 计时器:使用装饰器记录函数的执行时间。
- 认证和权限控制:使用装饰器验证用户身份和控制访问权限。
- 缓存:使用闭包实现函数的结果缓存,以避免重复计算。
- 日志记录:使用装饰器将函数的调用和返回值记录到日志文件中。
- 输入验证:使用装饰器对函数的输入参数进行验证和过滤。
4. 用装饰器实现一个日志记录的例子:
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling function: {func.__name__}")
print(f"Arguments: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} executed.")
print(f"Result: {result}")
return result
return wrapper @logger
def add(a, b):
return a + b result = add(2, 3)
5. 可变对象和不可变对象有哪些:
**不可变对象(Immutable objects)**是指创建后不能被修改的对象。当对不可变对象进行操作时,会创建一个新的对象。以下是一些常见的不可变对象:
- **数字(Numbers)**:包括整数(int)、浮点数(float)、复数(complex)等。
- **布尔值(Booleans)**:True和False。
- **字符串(Strings)**:一旦创建,字符串的值就不能被修改。
- **元组(Tuples)**:元组是一种有序且不可变的集合。
以下是不可变对象的一些特点:
- 不可变对象的值在创建后不能被修改,对其进行操作会创建一个新的对象。
- 不可变对象在多线程环境下是线程安全的,因为其状态不可变。
- 不可变对象可以作为字典的键或集合的元素,因为它们的哈希值不会变化。
**可变对象(Mutable objects)**是可以修改的对象,即可以改变对象的值或状态。以下是一些常见的可变对象:
- **列表(Lists)**:列表是有序且可变的集合,可以通过索引进行修改。
- **字典(Dictionaries)**:字典是无序的键值对集合,可以通过键进行修改。
- **集合(Sets)**:集合是无序且唯一的元素集合,可以进行添加、删除等操作。
以下是可变对象的一些特点:
- 可变对象的值可以在创建后被修改,对其进行操作会直接修改原始对象。
- 可变对象在多线程环境下需要进行同步操作,以避免并发修改导致的问题。
- 可变对象不能作为字典的键或集合的元素,因为其值的变化可能导致哈希值的变化。
6. 什么是值传递和引用传递:
**值传递(Pass-by-Value)**是指将实际参数的值复制一份,传递给函数或赋值给新变量。在这种情况下,函数或新变量操作的是复制后的值,对原始变量的修改不会影响到原始值。
**引用传递(Pass-by-Reference)**是指将实际参数的引用或地址传递给函数或赋值给新变量。在这种情况下,函数或新变量操作的是原始变量所在的内存地址,对变量的修改会直接影响到原始值。
在Python中,参数传递是通过引用传递的方式进行的。也就是说,函数或方法的参数传递的是对象的引用,而不是对象本身的副本。这意味着,如果在函数内部对引用的对象进行修改,会影响到原始对象。
下面是一个示例:
def modify_list(lst):
lst.append(4) my_list = [1, 2, 3]
modify_list(my_list)
print(my_list) # 输出 [1, 2, 3, 4]
在上面的例子中,我们定义了一个modify_list
函数,它接受一个列表作为参数并向列表中添加一个元素。当我们调用modify_list(my_list)
时,实际上是将my_list
的引用传递给modify_list
函数。在函数内部,我们通过引用对列表进行修改,添加了一个新元素。这导致原始列表my_list
也被修改,输出结果为[1, 2, 3, 4]
。
在实际使用中,我们需要根据需求选择值传递还是引用传递。一般来说,如果希望在函数内部修改原始对象,可以使用引用传递。如果希望保持原始对象不变,可以使用值传递或传递对象的副本。
需要注意的是,在Python中,虽然参数传递是通过引用传递的方式,但对于不可变对象(如整数、字符串、元组),因为其值无法修改,所以表现类似于值传递。而对于可变对象(如列表、字典、集合),因为其值可以修改,所以表现类似于引用传递。
值传递例子:
def modify_value(value):
value = value + 1 x = 10
modify_value(x)
print(x) # 输出 10
在上面的例子中,我们定义了一个modify_value
函数,它接受一个整数参数value
。在函数内部,我们对value
进行加1操作。然而,即使在函数内部对value
进行了修改,原始变量x
的值并没有改变。这是因为整数是不可变对象,函数调用时发生的是值传递,传递的是x
的值的副本,而不是x
本身
python 面试题第一弹的更多相关文章
- python面试题第一份
阅读目录 1 Python的函数参数传递 2 Python中的元类(metaclass) 3 @staticmethod和@classmethod 4 类变量和实例变量 5 Python自省 6 字典 ...
- python数据类型(第一弹)
作为一门计算机编程语言,python与其它语言一样,设有若干种数据类型,准确掌握各种数据类型的常用方法是精通python的必要条件,也是熟练使用各数据类型.最大限度发挥它们功能的基本条件. pytho ...
- 03.Python网络爬虫第一弹《Python网络爬虫相关基础概念》
爬虫介绍 引入 之前在授课过程中,好多同学都问过我这样的一个问题:为什么要学习爬虫,学习爬虫能够为我们以后的发展带来那些好处?其实学习爬虫的原因和为我们以后发展带来的好处都是显而易见的,无论是从实际的 ...
- Python网络爬虫第一弹《Python网络爬虫相关基础概念》
爬虫介绍 引入 之前在授课过程中,好多同学都问过我这样的一个问题:为什么要学习爬虫,学习爬虫能够为我们以后的发展带来那些好处?其实学习爬虫的原因和为我们以后发展带来的好处都是显而易见的,无论是从实际的 ...
- 03,Python网络爬虫第一弹《Python网络爬虫相关基础概念》
爬虫介绍 引入 为什么要学习爬虫,学习爬虫能够为我们以后的发展带来那些好处?其实学习爬虫的原因和为我们以后发展带来的好处都是显而易见的,无论是从实际的应用还是从就业上. 我们都知道,当前我们所处的时代 ...
- JS面试题第一弹
1.javascript的typeof返回哪些数据类型 alert(typeof [1, 2]); //object alert(typeof 'leipeng'); //string ...
- python公司面试题集锦 python面试题大全
问题一:以下的代码的输出将是什么? 说出你的答案并解释. class Parent(object): x = 1 class Child1(Parent): pass class Child2(Par ...
- 【Python五篇慢慢弹】快速上手学python
快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...
- 【Python五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸
类的继承案例解析,python相关知识延伸 作者:白宁超 2016年10月10日22:36:57 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给 ...
- 【Python】【面试必看】Python笔试题
前言 现在面试测试岗位,一般会要求熟悉一门语言(python/java),为了考验求职者的基本功,一般会出 2 个笔试题,这些题目一般不难,主要考察基本功.要是给你一台电脑,在编辑器里面边写边调试,没 ...
随机推荐
- 没想到还有这种骚操作~如何使用Golang实现无头浏览器截图?
前言 在Web开发中,有时需要对网页进行截图,以便进行页面预览.测试等操作. 而使用无头浏览器来实现截图功能,可以避免手动操作的繁琐和不稳定性. 这篇文章将介绍:使用Golang进行无头浏览器的截图, ...
- es笔记五之term-level的查询操作
本文首发于公众号:Hunter后端 原文链接:es笔记五之term-level的查询操作 官方文档上写的是 term-level queries,表义为基于准确值的对文档的查询,可以理解为对 keyw ...
- linux 条件语句和逻辑判断
目录 一.条件判断 二.逻辑判断 三.if和case 四.七个实验 一.条件判断 1.test测试 test [ 条件表达式 ] -e:测试目录是否存在 -d:测试是否为目录 -f:是否为文件 ...
- Galaxy Release_20.09 发布,新增多个数据上传组件
Galaxy Project(https://galaxyproject.org/)是在云计算背景下诞生的一个生物信息学可视化分析开源项目. 该项目由美国国家科学基金会(NSF).美国国家人类基因组研 ...
- 800名科学家Nature联名发文主张废除p值!
每年,全球有数百万学生修读统计学课程.随着世界上的数据量越来越大,统计学已成为越来越受欢迎的话题.如果大多数学生都从这门课中记住一点,那可能就是"统计显著性"和"p 值& ...
- java利用jni调用dll方法
准备工作: 需要用到的插件jni4net:这个需要去官网下载:https://sourceforge.net/projects/jni4net/files/ (1) jni4net 是一个开源 ...
- JavaScript学习笔记 - 语法篇 - 一句废话没有版
写在前面: 绝不废话!放心食用 JavaScript语法很简单,可以直接在控制台调试理解 目录 1.变量和常量 2.数据类型 3.字符串 3.1 模板字符串 3.2 字符串的部分常用函数 4.数组 5 ...
- WWDC2023 Session系列:探索XCode15新特性
一.版本说明 XCode 15 beta 发布于 2023 年 6月5日, 可支持 macOS 13.3 或以上版本, 你可以按需下载需要的平台. 二.新增特性 1.代码智能提示 (Code comp ...
- OSI七层协议剩余、socket模块、半连接池
传输层之TCP与UDP协议 TCP与UDP都是用来规定通信方式的 通信的时候可以随心所欲的聊 也可以遵循一些协议符合要求的聊 随心所欲的聊:文字 图片 视频 遵循一些协议:开头带尊称 首行空两个 只准 ...
- 【TVM模型编译】1. onnx2relay.md
上一篇介绍了onnx模型在tvm中优化的总体流程. 在这一篇中,介绍onnx模型到relay模型的转换流程,主要涉及了以下几个方面: onnx算子到relay算子转换 relay算子实现 这一篇介绍o ...