面试题
- == 和is的区别
== 比较两个对象或值的的相等性
is运算符号用于检测两个对象是否属于一个内存对象 - python支持多重继承吗?
Python可以支持多重继承。多重继承意味着,一个类可以从多个父类派生
举个例子:
class Base:
def method(self):
print("base")
class First(Base):
def method(self):
print("First")
class Second(Base):
def method(self):
print("Second")
class Child(First, Second):
pass
obj = Child()
obj.method()
# 输出结果
First
解释:Child 类确实继承了两个父类:First和Second、在这种情况下,Python使用方法解析顺序(MRO)来决定当前调用一个方法时候应该使用哪个父类来时。Python的MRO遵循C3线性话算法,这意味着他会根据类定义是父类的顺序来确定调用哪个方法。在这个例子中,因为Child类首先继承来自First,然后在是Second,所以First类中的mehod方法会被调用,而Second类中的同名方法则被覆盖,除非显示的通过超类调用他。
这并不意味着Second中的method方法完全不可达。实际上你任然可以通过超类直接调用他,如果有必要的话。但是根据MRO,当你调用obj.method()的时候,解释器会按照‘Child-> First-> Second -> Base’的顺序查找第一个匹配的mehod方法,在找到First.method后,搜索就会停止,因此他是被调用的方法。
- 如何判断一个值是函数还是方法
用type进行判断如果是method则是方法,如果是function则是函数
- @classmethod方法和@staticmethod方法
在Python中“@classmethod和@staticmethod”是用于将定义类方法和静态方法的装饰器
@classmethod:
1.定义:@classmethod装饰器是用来将一个方法声明为类方法
2.第一个参数:类方法的第一个参数是指向当前类的引用,习惯上命名为cls。这意味着你可以通过这个引用来访问类属性或者其他的类方法
3.使用场景:类方法通常用于工厂方法,这些方法需要知道类的属性和其他类方法来创建该类的实例。由于他们对类的引用,所以他们可以被类和他的所有实例调用。
@staticmethod
1.定义: @staticmehod装饰器将一个方法声名为静态方法
2.参数:静态方法不接受指向类或者实例的引用作为第一个参数(他没有self和cls)。这意味着静态方法既不能访问类属性,也不能访问实例属性。
3.使用场景:静态方法通常作为实用函数,他的行为不能依赖于类或者实例的状态。他们可以通过类直接调用,也可以通过类的实例调用。
区别总结:
1.参数:@classmethod方法自动传递类引用作为第一个参数,通常命名为cls,,而@staticmethod方法不传递任何特殊参数(既不传递类引用也不传递实例引用)
2.用途:@classmethod由于有对类的引用,可以修改类的状态;@staticmethod则用作于类无关的工具函数或者实例函数
3.调用方式:两者都可以通过类名直接调用,也可以通过类的实例调用,但是类方法可以访问和修改类状态,静态方法则不行。
- 设计一个面向对象的完整示例
class Book:
def __init__(self,book_name, auther, isbn) -> None:
self.book_name = book_name
self.auther = auther
self.isbn = isbn
def __str__(self):
return f"Book name is {self.book_name},auther is {self.auther}, ISBN is {self.isbn}"
class Library:
def __init__(self) -> None:
self.books = []
def add_book(slef, book: Book)-> None:
slef.books.append(book)
print(f"Library add book{book.book_name} success")
def remove_book(self, book: Book) -> None:
if book in self.books:
self.books.remove(book)
print(f"Library remove book {book.book_name} sucess")
else:
print(f"{book.book_name} not in Library, Please re-enter book name")
def search_book(self, book_name:str) -> None:
search_list = [book for book in self.books if book_name == book.book_name]
if search_list:
for b in search_list:
print(b)
else:
print(f"Library dont have {book_name}")
def list_books(self):
for book in self.books:
print(book)
book1 = Book("book1","Mr.1","isbn1")
book2 = Book("book2","Mr.2","isbn2")
book3 = Book("book3","Mr.3","isbn3")
book4 = Book("book4","Mr.4","isbn4")
book5 = Book("book5","Mr.5","isbn5")
library = Library()
library.add_book(book1)
library.add_book(book2)
library.add_book(book3)
library.add_book(book4)
library.add_book(book5)
library.list_books()
library.search_book("book4")
library.remove_book(book4)
library.list_books()
- 字典操作中的 del和pop 的区别是什么
del 是直接删除字典的键,pop删除键返回键的值
- 合并两个元组为字典
a = ('a','b')
b = (1,2)
c = dict(zip(a,b))
print(c)
# 输出结果
{'a': 1, 'b': 2}
- 如何打乱一个列表的元素
import random
a = [i for i in range(0, 100)]
random.shuffle(a)
print(a)
- 找出两个列表中相同的元素和不同的元素
import random
a = [random.randint(0,100) for i in range(0,10)]
b = [random.randint(0,100) for i in range(0,10)]
print(a)
print(b)
c = set(a) & set(b)
d = set(a) ^ set(b)
print(f"相同的元素有: {c}")
print(f"不同的元素有: {d}")
- 一行代码将字符串反转
a = 'abcdefghijklmnopqrstuvwxyz'
或者
"".join([i for i in reversed(a)])
- 当退出Python 的时候,是否释放所有的内存分配
- 当python解释器退出的时候,通常会释放大部分分配给他的内存回操作系统。这包括有Python自身,python对象,数据结构等占用的内存。Python使用自动内存管理,包括引用计数和垃圾回收机制来跟踪和回收未使用的内存,所以在正常情况,当Python程序结束的时候,由解释器直接管理的内存应该会被清理和释放
- 垃圾回收
- 引用计数:Python的每个对象都有一个引用计数,用来跟踪有多少个指向该对象的引用。当一个对象的引用计数降到0的时候,意味着没有任何引用指向该对象,python就会自动释放这个对象占用的内存
- 垃圾回收机制:对于循环引用的情况,仅仅靠引用计数是无法回收内存的。python的垃圾回收器会周期性的搜索这样的循环引用,并回收他们占用的内存
- C扩展和外部库
- 然而,如果你的pytho程序使用了C扩展或者直接调用了C库(例如通过Ctypes或者Cffi)这部分的内存管理可能依赖于这些库或者扩展本身的行为。如果这些扩展或者库没有正确的管理内存,那么这部分的内存可能不会在python退出时释放
- 操作系统的角色
- 大多数现代操作系统在进程终止的时候会回收进程使用的所有资源,包括内存,文件描述符等。这意味着即使python或者其扩展在退出的时候没有释放内存,操作系统通常也会在进程结束的时候清理掉这些资源
- 总的来说,当python程序退出的时候,大部分由Python解释器管理的内存都会被释放,但是由第三方库或者C扩展分配却未正确释放的内存不会自动释放。不过,操作系统在进程结束的时候会回收分配给该进程的资源包括内存。