python常见的面试题目
- 1、python 有几种数据类型
- 2、python中的变量和C语言中的变量的不同点
- 3、python中可变对象有哪些,不可变对象有哪些,实际的区别是什么
- 4、python中 is 和 == 的区别
- 5、python中的列表和字典的增删改查方式
- 6 、列表和元组的区别是什么
- 7、列表推导式
- 8、字典推导式
- 9、集合推导式
- 10、给程序传递参数
- 11、拆包
- 12、fun(*args,**kwargs)中的 args,*kwargs作用是什么
- 13、通过*号,拆包
- 14、通过**号,拆包
- 14、匿名函数 lambda 的使用
- 15、python文件读写怎么实现的
- 16、连接字符串的方法
- 17、 encode 和decode的作用
- 18、python的变量作用域有哪几个
- 19、 python中闭包是什么,怎么理解
- 20、 python中装饰器是什么,怎么理解
- 21、 if __name__ == '__main__'在python中作用是什么
- 22、 python中super函数是怎么用的
- 23、 python中super的作用是什么
- 24、 python 的dir和type两种方法的作用
- 25、 python 的self是什么
- 26、 python 的__init__方法是什么
- 27、 python with的作用 ,怎么实现和with一样的效果
1、python 有几种数据类型
- 1、数字
- 整形 (int)
- 浮点型 (float)
- 2、布尔 ( bool)
- false
- true
- 3、字符串 (string)
- 4、 列表 (list)
- 5、元组 (turple)
- 6、字典 (dict)
- 可使用type () 函数来获取数据的类型名
# 使用type(100) 获取数据100的类型
print(type(100))
print(type(100.0001))
print(type("hello world"))
2、python中的变量和C语言中的变量的不同点
- 如果学过C语言,就知道,在C语言中,变量好比一个盒子,给变量赋值就相当于把你要保存的东西,放到这个盒子里。但是在python中,一个变量就相当于一张贴纸,需要什么东西的时候, 就把这个贴纸贴到这个东西上面。这个产生的一个不同点就是,python是引用的内存中的数据.
3、python中可变对象有哪些,不可变对象有哪些,实际的区别是什么
- 可变对象
- 列表 ,字典,集合
- 不可变对象
- int,float, str , 元组
- 要知道有什么区别 ,要从各自概念入手
- 1、python 中的变量都是对象的引用,我们可以理解成python的变量指向了这个被引用的对象在内存里的位置 。这个不可变和可变,其实说的是这个被引用的对象在内存的位置是不可变,还是可变
比如a=3, a是变量,3是被引用的对象。这个3是int型,所以是不可变对象。既然这么说,python中下面的赋值操作,这个值不是变了么?
a=3
a=6
实际这个变的是变量的引用 ,而不是被引用的对象
a=3 内存中生成了一个3,a 指向了这个3的内存
a=6 内存中在别的地方又生成了一个6,a 重新指向6的内存 ,
- 2、可变就是改变了这个被引用的对象,但是这个对象在内存中位置还是不变的,即变量指向内存的位置是不变的
- 3、不可变 就是改变了这个被引用的对象,但是这个对象 在内存中的位置改变了,即变量指向内存的位置变了。
- 4、可以通过查看id命令来查看内存变化,先看不可变的,可以看出重新赋值后,id值变了
- 内存变化
- 5、再来看可变的,变量引用的地址没变
4、python中 is 和 == 的区别
- is 是检查变量指向的对象的内存地址是否相同(内存地址可以通过id()来查看) 。
- == 是检查对象的数值是否相同
5、python中的列表和字典的增删改查方式
- 列表的增删改查
- 增
- append ,末尾追加一个, a.append(3) 在列表最后插入一个元素3
- extend , 扩展,把两个列表合并在一起
- insert ,插入,区别于append, 是在指定位置插入需要的列表 a.insert(1, 3) ,在位置1插入3
- 删
- pop , a.pop() 删除最后一个元素 ,并且取出来。类似于出栈
- del , 根据下标进行删除 a.del [1],把下标是1的元素给删了
- remove , 根据元素的值进行删除 a.remove[3],把a列表的 3 这个元素给删了
- 改
- 列表[下标] = 新数据 通过这个格式来修改,a[1]=99,把下标为1的位置的数值改成99
- 查
- in 或者 not in .使用 (数据 in 列表)查找数据在不在
- a.count[1] ,统计列表里1的个数有多少
a = [3, 4, 5]
if 3 in a:
print('3在a里面')
else:
print('3不在a里面')
- 字典的增删改查
dict1 = {
'name': 'Duo' ,
'age': 14,
'tel': '123456'
}
dict2 = {
'name': 'Lin' ,
'age': 14,
'tel': '654321'
}
- 字典
- 增
- 字典名[‘key’] = value, 如果没有原本字典没有这个key,则添加这个key:value.如果有就是修改这个key。dict1[‘address’]=‘shanghai’
- update. dict1.update(dict2) ,把dict2中的键值对合并到dict1里,如果有重复的key,则用dict2值的覆盖dict1里的
- 删
- del 去删除某个键值对,del 字典名[‘key’] , 比如:del dict1[‘tel’] ,键值对不存在则删除这个键值对的操作会报错。
- pop 去删除某个键值对,pop.dict1[‘key’] 键值对不存在一样会报错,pop.dict1[‘key’.‘没有这个键值对返回的内容’]
- del 去删除整个字典, del 字典名,比如 del dict2
- clear 清除整个字典 dict2.clear()
- 改
- 字典名[‘key’] = value, 如果没有原本字典没有这个key,则添加这个key:value.如果有这个key就是修改
- 查
- print(字典名[‘key’] ) 但是如果没有这个key程序会报错,所以推荐用get
- 字典名.get [‘key’,’如果没找到默认返回的值’], 比如:b=dict2.get (‘address’,’ addr not fond ') 当dict2中没有address这个关键字,则返回 addr not fond
6 、列表和元组的区别是什么
- 列表是可变类型,元组是不可变类型。
- 如果函数返回多个值,这些值最终会被包装成元组,而不是列表,这样可以防止,有人对函数的返回值,进行恶意的修改。
7、列表推导式
- 推导式一 [ f(x) for x in 可迭代对象 ]
numbers = [1, 2, 3, 4, 5]
result= [x**2 for x in numbers]
print(result) # 输出: [1, 4, 9, 16, 25]
- 推导式二 [ f(x) for x in 可迭代对象 过滤元素x的条件 ]
numbers = [1, 2, 3, 4, 5]
result= [x**2 for x in numbers if x % 2 == 0]
print(result) # 输出: [4, 16]
等价于下面的代码
list = []
numbers = [1, 2, 3, 4, 5]
for x in numbers:
if x % 2 == 0:
list.append(x**2)
print(list) # 输出: [4, 16]
- 推导式三 [ f(x,y) for x in 可迭代对象 for y in 可迭代对象 ]
num1 = [1, 2, 3, ]
num2 = ['a', 'b', 'c']
result = [(i, j) for i in num1 for j in num2]
print(result)
# [(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (3, 'a'), (3, 'b'), (3, 'c')]
等价于
num1 = [1, 2, 3, ]
num2 = ['a', 'b', 'c']
list = []
for i in num1:
for j in num2:
list.append((i,j))
print(list)
8、字典推导式
- 字典推导式和列表推导式差不多,但是外壳是用的大括号 ,可以搜索一下
- { f(x) for x in 可迭代对象}
a= {x:(x+1) for x in range(1,11) if x % 2 == 0}
print(type(a))
print (a)
9、集合推导式
- 集合和字典同理,如下,唯一的区别是 大括号前面的内容是x
- a = {x for x in range(1, 11) if x % 2 == 0}
a = {x for x in range(1, 11) if x % 2 == 0}
print(type(a)) # 看以看出是set 类型
print (a)
10、给程序传递参数
- 在Linux环境下,使用【 python3 test.py 参数一 参数二 】 这种方式去调用文件的时候,文件内通过sys.argv[]的方法去获取到参数一和参数二
import sys
a=sys.argv[0]
b=sys.argv[1]
c=sys.argv[2]
d=sys.argv[3]
print(a)
print(b)
print(c)
print(d)
11、拆包
- 拆包是指 快速将一个容器(如列表、元组、字典等)中的元素解析出来并赋值给多个变量的过程
- 列表拆包
a, b = [3, 4]
print(a) #3
print(b) #4
- 元组拆包
a, b = (3, 4)
print(a) #3
print(b) #4
- 集合拆包
a, b = {3, 4}
print(a) #3
print(b) #4
- 字典拆包
方法 一
a, b = {"name": "ming", "age": "99"}
print(a) # name
print(b) # age
方法二
dict1 = {"name": "ming", "age": "99"}
for k, v in dict1 .items():
print((k, v))
"""
打印结果是
('name', 'ming')
('age', '99')
"""
12、fun(*args,**kwargs)中的 args,*kwargs作用是什么
- *args 接受任意多个实际参数 fun(1,2,3)
- **kwargs接收任意多个以关键字参数赋值的实际参数fun(a=1,b=2,c=3)
- *args只是个名字,换成任意的字符都可以,关键是前面的星号。有了这个星,函数调用时就可以传递任意多个参数,所有传入的参数将被放入到一个元组中,即放入args中,因此args的类型也是tuple元组.
def func(*args):
print(args, type(args)) # 打印出agrs 的类型
sum_num = 0
for item in args:
sum_num += item
return sum_num
print(func(3))
print(func(3, 4, 5))
- **kwargs 以关键字参数的形式进行参数传递,最终这些key-value对将组装成字典,kwargs的类型
是dict。
def func(**kwargs):
print(kwargs, type(kwargs))
for course, pirce in kwargs.items():
print(course, pirce)
func(name='西游记', pirce=99)
13、通过*号,拆包
- 传入列表,元组,集合的时候, 可以通过*号拆包 ,分成一个个的。
def demo(a, b, c):
print(a + b + c)
nums1 = [11, 22, 33]
demo(*nums1) # 此时的*的作用就是拆包,此时*nums相当于11, 22, 33 即test(11, 22, 33)
nums2 = [11, 22, 33]
demo(*nums2)
nums3 = (11, 22, 33)
demo(*nums3)
14、通过**号,拆包
- 使用**可以对字典进行拆包,拆包的结果是命名参数
def demo(name, age, addr):
print(name)
print(age)
print(addr)
info = {
"name": "zhou",
"age": 19,
"addr": "shanghai"
}
# 传入(**info) 相当于传入 (name="zhou", age=19, addr="shanghai")
demo(**info) # 等于 demo(name="zhou", age=19, addr="shanghai")
14、匿名函数 lambda 的使用
- 匿名函数的格式是 【lambda 形参1, 形参2, 形参3: 表达式】,表达式的结果的值,最后返回给lambda
# 定义了一个匿名函数,然后让变量add_2_nums指向它
add_nums = lambda x, y: x + y
# 调用add_nums指向的匿名函数,即调用add_2_nums()就是调用匿名函数。
print("10+20=%d" % add_nums(10, 20))
15、python文件读写怎么实现的
- 使用open命令,打开文件,第一个参数填的是文件地址,如果在同级目录下,直接写文件名,第二个参数是打开模式,比如r 代表的时以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。第三个参数是
- r 代表的时以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
- w 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件
- a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写
- rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
# 写入文件,如果文件已存在则覆盖
with open('filename.txt', 'w') as file:
file.write('Hello, world!') # 写入内容
# 追加到文件,如果文件已存在则在末尾添加内容
with open('filename.txt', 'a') as file:
file.write('\nThis is an appended line.') # 追加内容
# 打开文件
with open('filename.txt', 'r') as file:
# 读取文件内容
content = file.read() # 读取整个文件内容
# 或者逐行读取
lines = file.readlines() # 读取所有行,返回一个列表,每行是一个元素
# 现在可以处理文件内容了
print(content)
# 或者
for line in lines:
print(line, end='') # end='' 避免自动添加换行符,因为readlines()已经包含了每行的换行符
16、连接字符串的方法
- 1、使用+号, 字符串a+字符串b 连接a和b
str1 = "Hello"
str2 = "World"
str3 = str1 + " " + str2
print(str3) # 输出:Hello World
- 2、使用join 连接
- join 的方法是separator.join(iterable)
- separator: 用于分隔序列中元素的字符串。
- iterable: 一个可迭代的对象,如列表、元组或字符串集合等,传递给 join() 方法的参数必须是一个可迭代的对象,其元素也应该是字符串类型。
words_str += f'Value: {i + 1}'
str_list = ["Hello", "World"]
str_joined = "_".join(str_list)
print(str_joined) # 输出:Hello_World
- 3、使用格式化连接字符串
name = "zhou"
age = 99
formatted_str = "My name is {} and I am {} years old.".format(name, age)
print(formatted_str) # 输出:My name is zhou and I am 99 years old.
- 注意点:目前的python是用+号和join 的速度基本是一样的,所以不用刻意选用join方法来连结。
17、 encode 和decode的作用
- encode(编码):str –> bytes 。字符串是我们人类可以理解的, 转成电脑可以理解的,即把字符串编写成0101这种码流,所以也叫编码
- decode(解码):bytes – > str 反过来,把电脑可以理解的,变成人类可以理解的,就叫解码
18、python的变量作用域有哪几个
- 作用域指的是变量、函数和其他对象在程序中可以被访问的区域。Python中有四种主要的作用域:
- 局部作用域(Local):在函数或方法内部定义的变量具有局部作用域。它们只能在函数或方法内部被访问。
- 嵌套局部作用域(Enclosing Locals):一个函数内部又定义了一个函数,这样就产生了嵌套,而内层函数可以访问外层函数的局部变量。
- 全局作用域(Global):在函数或方法之外定义的变量具有全局作用域。它们可以在整个程序中被访问,如果是在函数内部,可以通过 【global 变量名】来把变量变成全局变量,从而拥有全局作用域。我们导入的模块就是一个全局作用域
- 内置作用域(Built-in):内置函数和异常具有内置作用域,不需要导入可以直接使用。比如sum,min,max ,AttributeError
# 通过下面的代码可以 查看预定义了哪些内置变量或函数
import builtins
print(dir(builtins))
# 如果定义变量或者函数的时候,不规范,就会出现问题
a = 3
b = 5
sum = a + b
print(sum)
lst = [1, 2, 3]
print(sum(lst))
# 这个会又报错 TypeError: 'int' object is not callable, 因为自己定义了sum的变量,把内置的sum函数给覆盖了
- Python遵循“LEGB”规则来确定变量的查找顺序:Local(局部) -> Enclosing locals(嵌套局部) -> Global(全局) -> Built-in(内置)。
19、 python中闭包是什么,怎么理解
以下面函数做例子
def func_out(msg): # 相对的 外部函数
def func_in(): # 相对的 内部函数
print(msg) # 打印
return func_in# 返回的内部函数的引用
demo= func_out ('hello world!')
demo()
1、python中闭包的条件
- 条件一 :一个函数嵌套一个函数,这样就形成了一个 嵌套局部作用域 ,即内部函数可以引用外部函数的变量。
- 条件二:当外部函数返回内部函数的名字的时候,就形成了一个最简单的闭包。
2、如何理解闭包及闭包的作用
- 因为当调用了外部函数( func_out(‘hello world!’) )时,返回的是内部函数名 func_in。demo = func_out (‘hello world!’) 等价于demo=func_in, 这个命令就是给fun_in 起了另一个名字demo
这个fun_in 里还保存着 hello world这个参数变量。原本hello world这个参数作为局部变量,当fun_out这个函数调用后,这个变量就会被销毁了,但是通过在内部函数fun_in 中调用了meg,再通过return返回内部函数的名字(fun_in),就把这个变量保存到内部函数中。这个就是闭包的作用。原本当函数运行后,函数内部的局部变量就消失了,通过闭包,却保存了这个局部变量,专业一点说就是当闭包执行完后,仍然能够保持住当前的运行环境。
20、 python中装饰器是什么,怎么理解
21、 if name == 'main’在python中作用是什么
- 作用总结就是 更好的调试模块,避免被被人引用出现问题。运行下面的程序,查看结果
(1)demo.py
def func():
print("hello world")
print('demo中__name__ =', __name__)
解释一下:
一个python文件就是一个模块,而__name__ 是这个模块的名字的变量。 可以看出__name__ 的值是__main__,如果别的文件中导入这个demo.py这个模块 , 在别的文件里,它的__name__的值 就不是__main__, 而是等于demo,就是被导入的文件名称去掉.py 剩余的名字。如下图所示,还有一点要注意的是,demo1模块导入demo模块,运行的demo1模块时,引入的demo模块居然也执行了。
举个生活中的例子就是
- 你在家就是父母的儿子,女儿(在自己的模块里就叫 main)。
- 在去别人家就叫自己的原本的名字(上面例子里是demo,这个是变化的) ,而且会主动介绍一下自己(被人引用的时候,别人运行时,自己也会运行)
所以 if name == ‘main’ : 下运行程序,可以保证是只在当前模块(demo)下运行, 当这个模块(demo)被别的模块(demo1)引用的时候 ,
demo模块下 if__name__==‘main’ 下运行的程序,不会被运行。
22、 python中super函数是怎么用的
- 1、先说普通继承
class A:
def __init__(self):
self.attr_a = 1
print('执行A的初始化函数')
class B(A):
def __init__(self):
A.__init__(self)
self.attr_b = 2
b = B()
print('---------------------------------')
print(b.attr_a, )
print('---------------------------------')
print(b.attr_b)
结果是
- 2、再说用super继承
直接看区别,使用super().方法,就能直接调用到基类的方法了。
23、 python中super的作用是什么
- super()函数用于调用父类(或称为基类、超类)的方法。
- 但是super函数主要是为了解决python菱形继承导致基类方法重复调用的问题
- 菱形继承举个例子,A 是基类,B 和 C 都继承了A, 最后D 继承B和C, 这样就形成了菱形继承。
- D 的初始化函数(init)里调用了B和C的初始化函数,而B和C的初始化里又分别调用了A的初始化函数,那么最终A的初始化函数会被执行两次,这个会导致很多问题。如下
class A:
def __init__(self):
self.attr_a = 1
print('执行A的初始化函数')
class B(A):
def __init__(self):
A.__init__(self)
self.attr_b = 2
print('执行B的初始化函数')
class C(A):
def __init__(self):
A.__init__(self)
self.attr_c = 3
print('执行C的初始化函数')
class D(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
self.attr_d = 4
print('执行D的初始化函数')
d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)
结果如下:
可以看出,类A的初始化函数被执行了两次 。这种会导致很多不可控的问题。
如果是用的super 去调用继承的话
class A:
def __init__(self):
self.attr_a = 1
print('执行A的初始化函数')
class B(A):
def __init__(self):
super().__init__()
self.attr_b = 2
print('执行B的初始化函数')
class C(A):
def __init__(self):
super().__init__()
self.attr_c = 3
print('执行C的初始化函数')
class D(B, C):
def __init__(self):
super().__init__()
self.attr_d = 4
print('执行D的初始化函数')
d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)
结果如下,
在D的初始化函数中,只使用了一行代码super().init(), 就将两个父类B和C的初始化函数都执行了,
而且不会重复执行A的初始化函数,这些都是super帮助我们完成的
24、 python 的dir和type两种方法的作用
python的变量是没有类型的,变量只是对象的引用,你可以使用type函数来查看一个变量的类型,这有助于你理 解程序,但如果使用了第三方库,第三方库返回的对象就是你不熟悉的对象,如果没有详细的文档,你甚至不知道这个对象有什么属性,有什么方法,这个时候就可以使用dir函数来查看,dir会返回对象t所拥有的属性和方法名称,其中有很多都是以双下滑线开头的,我们要关注那些不带双下划线的。
dir() 函数返回一个包含对象所有有效属性名的列表。这些属性包括方法、模块和类变量、函数等。对于模块对象,返回的列表会包含该模块的所有函数、类和变量。对于类对象,返回的列表会包含类的所有方法和属性。对于实例对象,返回的列表会包含它的所有方法和属性,以及它所属的类的所有方法和属性。
# 定义一个类
class MyClass:
def __init__(self):
self.my_attribute = "Hello"
def my_method(self):
print("This is a method")
# 创建类的实例
my_instance = MyClass()
# 使用dir()查看实例的属性
print(dir(my_instance))
# 也会看到继承自object类的属性和方法
# 获取整数类型的type
print(type(10)) # 输出: <class 'int'>
# 获取字符串类型的type
print(type("Hello")) # 输出: <class 'str'>
# 获取上面定义的MyClass的type
print(type(MyClass)) # 输出: <class 'type'>
# 获取MyClass实例的type
print(type(my_instance)) # 输出: <class '__main__.MyClass'>
25、 python 的self是什么
self 就是对当前对象的引用,即指向当前的实例对象。当我们定义一个类的方法时,self 是第一个参数,当你实例化这个类后,通过这个实类调用类里面的方法,这个时候,self就指向了这个实例,从而可以调用类内部的方法和属性
- 定义实例方法的时候,我们生成了一个实例对象A。之所以第一个形参一定是self就是因为,当我们调用实例方法【 A.say_hello()】的时候, Python解释器会自动把self指向A. 然后self作为第一个参数,就是A作为第一个参数。
- 实例对象.实例方法()就相当于实例方法(实例对象)
class MyClass:
def __init__(self, name):
self.name = name # 设置实例属性
def say_hello(self):
print(f"Hello, my name is {self.name}!") # 访问实例属性并使用它
# 创建 MyClass 的一个实例,并传入 'Alice' 作为 name 参数
A = MyClass('Alice')
# 调用 say_hello 方法,这个时候,self就指向A.即self就是A.
A.say_hello() # 输出: Hello, my name is Alice!
26、 python 的__init__方法是什么
- 创建对象后,Python会自动调用一个特殊的方法名字叫__init__,一般情况下我们会在这个方法中完成对象属性的设置,即起到了一个初始化的作用
class Cat(object):
def __init__(self):
print("我是__init__方法")
cat = Cat() # 此时就会自动调用
27、 python with的作用 ,怎么实现和with一样的效果
1、 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上,with语句可以确保在代码块执行完毕后,资源被正确地关闭或清理,即使在代码块执行过程中发生异常也是如此。
with open('file.txt', 'r') as f:
content = f.read()
# 在这里处理文件内容
# 文件在这里已经被自动关闭
- 在这个例子中,open(‘file.txt’, ‘r’)返回一个文件对象,该对象是一个上下文管理器。当with语句开始时,文件被打开;当with-block结束时,文件被自动关闭,无需手动调用f.close()。即使with-block中的代码引发了异常,文件也仍然会被正确关闭。
- 通过使用with语句,我们可以编写更清晰、更健壮的代码,减少因忘记关闭资源而导致的潜在问题 ,下面我们看下这个进化过程。
2、如果不用with 的话
def m1():
f = open("file.txt", "w")
f.write("python之禅")
f.close()
如上所示,如果在调用 write的过程中,出现了异常进而导致后续代码无法继续执行,close 方法无法被正常调用,因此资源就会一直被该程序占用者释放,可以改良一下
def m2():
f = open("file.txt", "w")
try:
f.write("python之禅")
except IOError:
print("oops error")
finally:
f.close()
改良版本的程序是对可能发生异常的代码处进行 try 捕获,使用 try/finally 语句,该语句表示如果在 try 代码块中程序出现了异常,后续代码就不再执行,而直接跳转到 except 代码块。而无论如何,finally 块的代码最终都会被执行。因此,只要把 close 放在 finally 代码中,文件就一定会关闭。这个实际效果就是 用with打开
3、使用with的话,效果如下
def m3():
with open("file.txt", "r") as f:
f.write("Python之禅")
open 方法的返回值赋值给变量 f,当离开with代码块的时候,系统会自动调用f.close()方法, with 的作用和使用 try/finally 语句是一样的