找回密码
 会员注册
查看: 22|回复: 0

python笔试面试八股(自用版)

[复制链接]

2万

主题

0

回帖

7万

积分

超级版主

积分
71625
发表于 2024-9-9 14:07:11 | 显示全部楼层 |阅读模式
1解释型和编译型语言的区别解释是翻译一句执行一句,更灵活,eg:python;解释成机器能理解的指令,而不是二进制码编译是整个源程序编译成机器可以直接执行的二进制可运行的程序,再运行这个程序比如c++2简述下Python中的字符串、列表、元组和字典和集合在Python中,字符串、列表、元组、字典和集合是常用的数据结构,每种结构都有其独特的特性和用途。字符串(String):’’""字符串是由字符组成的序列。在Python中,字符串是不可变的,这意味着一旦创建了一个字符串,就不能修改它。字符串可以用单引号('')或双引号("")包围。示例:'hello'或"world"列表(List):[]列表是一个有序的元素集合,元素可以是任意类型(整数、浮点数、字符串、另一个列表等)。列表是可变的,可以添加、删除或修改其中的元素。列表使用方括号([])创建。示例:[1,2,3,'apple',[4,5]]元组(Tuple):()元组与列表类似,也是一个有序的元素集合,但元组是不可变的。元组使用圆括号(())创建,但空元组可以用单独的一个逗号创建,如t=()或t=,。由于元组不可变,它们在某些情况下比列表更高效。示例1,2,3,'banana')字典(Dictionary):{}字典是一个无序的键值对集合。每个键在字典中都是唯一的,并与一个值相关联。字典使用大括号({})创建,键和值之间用冒号(分隔。字典是可变的,可以增加、删除或修改键值对。示例:{'name':'Alice','age':30}集合(Set):{}集合是一个无序的、不重复的元素集合。集合使用大括号({})创建,但注意,空集合必须使用set()函数创建,而不是{}(这会创建一个空字典)。集合支持数学运算,如并集、交集、差集等。示例:{1,2,3,4,5}有序:元组列表唯一的:集合、字典不可变:元组3简述上述数据类型的常用方法字符串:切片:[1:3]格式化:print(“Hello,{}!Todayis{}.”.format(“Alice”,“Monday”))连接a.join(b)替换‘ddd’.repalce(‘d’,‘a’)分割.split(',')#用逗号分割列表切片添加元素.append().extend()删除dellist[0]#下标list.pop()#最后一个元素list.remove('c')#元素排序sort反转reverse字典清空.clear()遍历keyforkeyindict新建.formkeys(keyname,valuves)4简述Python中的字符串编码UTF-8是隶属于Unicode的可变长的编码方式。在Python中,以Unicode方式编码的字符串,可以使用encode()方法来编码成指定的bytes,也可以通过decode()方法来把bytes编码成字符串。>>>"你好".encode('utf-8')b'\xe4\xbd\xa0\xe5\xa5\xbd'>>>b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')"你好"12345一行代码实现数值交换a,b=b,a6is和==的区别is是判断对象的id内存地址是否一致,==判断值可以理解为是和等于的区别7Python函数中的参数类型Python函数的参数类型可以分为几种,包括:位置参数(PositionalArguments):这些参数必须按顺序提供,并且不能使用参数名来指定。默认参数(DefaultArguments):函数定义时,可以为参数指定默认值。如果没有为这些参数提供值,则使用默认值。关键字参数(KeywordArguments):这些参数在调用函数时使用参数名指定,这允许以任何顺序传递参数。可变位置参数(VariablePositionalArguments):变的是数量使用*表示,可以接收任意数量的位置参数,这些参数被存储在元组中。可变关键字参数(VariableKeywordArguments):使用**表示,可以接收任意数量的关键字参数,这些参数被存储在字典中。类型注解(TypeHints):Python3.5+引入了类型注解,允许开发者指定参数预期的数据类型,但这不会对类型进行检查,只是作为提示。下面是一些示例来说明这些参数类型:#类型注解defcalculate(a:int,b:int,operator:str)->int:ifoperator=='+':returna+belifoperator=='-':returna-bresult=calculate(5,3,'+')123456789在实际编程中,使用默认参数和可变参数可以增加函数的灵活性。关键字参数和类型注解则可以提高代码的可读性和可维护性。类型注解在现代Python开发中越来越受欢迎,尤其是在大型项目和团队协作中,它们帮助工具和IDE进行类型检查,从而减少错误。8*arg和**kwarg作用可变位置和可变关键字,只数量可变。*arg会把位置参数转化为tuple,**kwarg会把关键字参数转化为dict。>>>deftest(*arg,**kwarg):...ifarg:...print("arg:",arg)...ifkwarg:...print("kearg:",kwarg)...>>>test('ni','hao',key='world')arg'ni','hao')kearg:{'key':'world'}123456789109获取当前时间>>>importtime>>>importdatetime>>>print(datetime.datetime.now())2022-09-1219:51:24.314335>>>print(time.strftime('%Y-%m-%d%H:%M:%S'))2022-09-1219:51:24123456710PEP8规范PEP8是Python的官方编码风格指南,它提供了关于如何编写清晰、可读性强的Python代码的指导。以下是PEP8中一些关键的规范:缩进:4使用4个空格进行缩进。行宽:每行代码尽量不超过79个字符,这样可以在不同的设备上查看代码时不需要水平滚动。空行:2在函数定义之间使用两个空行。在类定义之间也使用两个空行,但在类的方法定义之间使用一个空行。导入:1每个导入应该独占一行。应该将import分为三部分:标准库导入、相关第三方导入、本地应用/库特定导入。变量命名:小下划,大是类使用小写字母和下划线分隔的方式命名变量和函数(snake_case)。使用首字母大写的方式命名类(CamelCase)。表达式和语句:不要在一行内写过多的语句。避免使用复杂的表达式,尽量保持简单。编码:代码应该默认使用UTF-8编码。错误和异常:使用raise来引发异常,而不是raiseException()。代码注释:对复杂的操作进行注释,解释为什么代码要这么做。类型注解:从Python3.5开始,可以使用类型注解来提高代码的可读性和健壮性。函数和方法:函数参数应该以单个空格分隔。函数应该完成一个单一的任务。命名空间:避免使用全局变量。布尔上下文:在布尔上下文中,不要使用ifx:这样的语句,除非x明显是一个布尔值。序列:使用列表推导式来创建列表。[expressionforiteminiterableifcondition],其中iterable:一个可迭代对象,比如列表、元组、字典等。even_numbers=[xforxinrange(20)ifx%2==0]#[0,2,4,6,8,10,12,14,16,18]squares_dict={x:x**2forxinrange(5)}#{0:0,1:1,2:4,3:9,4:16}元组:单元素元组应该包含一个尾随逗号,例如(a,)。字典:键值对应该使用等号=分隔,多个键值对之间用逗号分隔。比较:使用==来检查对象的相等性,使用is来检查对象的同一性。字符串:使用一致的方式表示字符串,通常是单引号'或双引号"。PEP8只是一个指南,并不是强制的规则。但在Python社区中,遵循PEP8可以使得代码风格统一,提高代码的可读性。此外,可以使用工具如flake8或pylint来检查代码是否符合PEP8的规范。Python的深浅拷贝(🧡🧡,被问到了,一问一个不吱声大哭)先了解一下引用,通过一个名字来用一个对象,举例:a=[1,2],此时a就是列表[1,2]这个对象的引用。如果b=a,b是列表[1,2]这个对象的另一个引用,当我改变a的值,b也会变。所以,变量(名)是对象的引用,b这个新变量并没有创建新的实例,而是指向同一个对象的新引用。了解了引用,再来看浅拷贝。浅拷贝:copy.copy拷贝前后的列表只有外层独立,内里嵌套列表还是共享的,你变他也变。对于内层只复制了元素的引用,没有复制元素本身,两个都指向同一个对象。而外层对象是一个新的对象,这个新的列表顶层对象包含了对子列表对象的引用,比如下面的:[1,2,3,[1,2]]是新对象[1,2,3,[子列表对象的引用即1,2]]>>>importcopy>>>list1=[1,2,3,[1,2]]>>>list2=copy.copy(list1)>>>list2.append('a')>>>list2[3].append('a')>>>list1[1,2,3,[1,2,'a']]>>>list2[1,2,3,[1,2,'a'],'a']12345678910深拷贝:copy.deepcopy拷贝前后完全独立,深深断联,互不相干。因为复制的是元素本身,生成的是新对象。>>>importcopy>>>list1=[1,2,3,[1,2]]>>>list3=copy.deepcopy(list1)>>>list3.append('a')>>>list3[3].append('a')>>>list1[1,2,3,[1,2]]>>>list3[1,2,3,[1,2,'a'],'a']12345678910深拷贝比浅拷贝更消耗资源,因为它需要创建更多的对象。12[lambdax:i*xforiinrange(4)]🧡🧡首先,lambda匿名函数,为啥用?只有一行的函数,省去定义过程;不需要重复使用的,用完立即释放。其次,闭包。定义是:在内部函数里,引用了外部函数局部作用域的变量,使外层函数已经执行完毕。闭包可以访问创建时的环境状态。闭包函数是指当前函数用到上一层函数的局部作用域的变量时,触发了闭包规则的函数。注意只有在内部函数被调用时才去引用外部变量,没被调用时变量命名空间还不存在哩。回看[lambdax:i*xforiinrange(4)],i是外层作用域,lambdax:ix是内层函数,在构建列表推导式时,对于每一个i都创建一个ix,就是[ix,ix,ix,ix]此时i=3,所以内部的i*x还没开始计算,也就是lambdax内部还没被调用,i的递归只是创建了4个lambda表达式。每个lambda表达式中的i只是对外部变量的引用>>>defnum():...return[lambdax:i*xforiinrange(4)]#返回的是一个函数列表[3x,3x,3x,3x]...>>>[m(1)forminnum()]#对于函数列表中的每一个函数,赋值参数为1[3,3,3,3]123456想要解决,确保了每个lambda表达式捕获了i的一个独立副本,变局部作用域为闭包作用域,局部作用是执行完毕就会被销毁,闭包作用域是外部已经执行完毕了,内部还可以访问外部的变量的值。>>>defnum():...return[lambdax,i=i:i*xforiinrange(4)]1213打印九九乘法表>>>foriinrange(1,10):...forjinrange(1,i+1):...print(f"{i}*{j}={i*j}",end="")...print()...1*1=12*1=22*2=43*1=33*2=63*3=94*1=44*2=84*3=124*4=165*1=55*2=105*3=155*4=205*5=256*1=66*2=126*3=186*4=246*5=306*6=367*1=77*2=147*3=217*4=287*5=357*6=427*7=498*1=88*2=168*3=248*4=328*5=408*6=488*7=568*8=649*1=99*2=189*3=279*4=369*5=459*6=549*7=639*8=729*9=81123456789101112131415print函数默认是会换行的,其有一个默认参数end;range左闭右开,打印一个下三角。14filter、map、reduce的作用reduce递归遍历了每个元素,返回一个值,用一行代码解决求和、最大值、15.为什么不建议函数的默认参数传入可变对象默认参数是可变的,那调用第二次传入的参数就是第一次调用完的结果,效果会叠加如下defappend_to_element(element,append_to=[]):element.append(append_to)returnelement#第一次调用函数,预期的行为print(append_to_element("newitem"))#输出:['newitem']#第二次调用函数,非预期的行为print(append_to_element("anotheritem"))#输出:['newitem','anotheritem']12345678910为了让每次调用都相互独立,不要用可变变量为默认参数,默认改为none,当是默认none时再创建一个[]defappend_to_element(element,append_to=None):ifappend_toisNone:append_to=[]element.append(append_to)returnelement1234516.面向对象中__new__和init区别(🧡🧡)new是类方法,用于创建一个实例对象,对其进行内存分配。参数是cls(类名)创建完实例对象之后,init作为实例方法,对实例对象进行初始化一些属性和参数。参数是self(实例名)在面向对象编程中,__new__和__init__是两个特殊的方法,它们在创建对象时有不同的用途和行为:举例说明:假设我们有一个简单的类MyClass:classMyClass:def__new__(cls,*args,**kwargs):#一般new不需要重写,可以在这里执行一些逻辑,例如改变创建的对象类型print("Creatingobjectwith__new__")instance=super().__new__(cls)#创建对象,保留父类的方法,避免重复returninstancedef__init__(self,value):#在这里设置对象的初始状态print("Initializingobjectwith__init__")self.value=value#创建MyClass的实例obj=MyClass(10)1234567891011121314输出将是:Creatingobjectwith__new__Initializingobjectwith__init__12在这个例子中,__new__首先被调用并创建了MyClass的一个新实例。然后,__init__被调用,设置value属性。重写__new__的例子:classBaseClass:def__new__(cls,*args,**kwargs):print("BaseClass__new__called")returnsuper().__new__(cls)def__init__(self,value):self.value=valueclassSubClass(BaseClass):def__new__(cls,*args,**kwargs):print("SubClass__new__called,changingobjecttype")instance=super().__new__(BaseClass)#创建BaseClass的实例returninstancedef__init__(self,value):super().__init__(value)#初始化BaseClass的__init__print(f"SubClassinitializedwithvalue:{self.value}")#创建SubClass的实例sub_obj=SubClass(20)1234567891011121314151617181920输出将是:SubClass__new__called,changingobjecttypeBaseClass__new__calledSubClassinitializedwithvalue:20123在这个例子中,我们重写了SubClass的__new__方法,使其创建了BaseClass的实例而不是SubClass的实例。这演示了__new__方法如何控制对象的创建过程。通常,__new__方法在大多数情况下不需要重写,除非你有特殊的对象创建逻辑。而__init__方法则更常用于初始化对象的状态。17.三元运算规则执行1if条件else执行2>>>>>>a,b=1,2>>>h=a-bifa>belsea+b>>>h31234518.生成随机数用np.random也可以!>>>importrandom>>>random.random()0.7571910055209727>>>random.randint(1,100)23>>>random.uniform(1,5)#random.uniform(a,b)返回一个随机浮点数N,使得a>>list1=['zhangfei','guanyu','liubei','zhaoyun']>>>list2=[0,3,2,4]>>>list(zip(list1,list2))[('zhangfei',0),('guanyu',3),('liubei',2),('zhaoyun',4)]123420.range和xrange的区别只有Python2中才有xrange()和range(),Python3中的range()其实就是Python2中xrange()。即都用range21.with方法打开文件的作用打开文件在进行读写的时候可能会出现一些异常状况,如果按照常规的f.open()写法,我们需要try,except,finally,做异常判断,并且文件最终不管遇到什么情况,都要执行f.close()关闭文件,with方法帮我们实现了finally中f.close()。所以,能在代码执行完毕后,资源能够被正确地关闭或释放,即使在代码执行过程中发生异常也是如此。withopen("hello.txt","a")asf:f.write("helloworld!")12总结:文件会遇到异常,也都需要关闭,用with打开不论是否遇到异常,都能正确关闭。22.字符串转列表s.split(‘,’)>>>s="1,2,3,4,5,6,7,8,9">>>s.split(",")['1','2','3','4','5','6','7','8','9']123字符串split返回列表23.字符串转整数list(map(lambdax:int(x),s.split(",")))先转为列表,再用map遍历转int24.删除列表中的重复值先变成set集合再list,变过去再变回来,集合去重list(set(mylist))25.字符串单词统计统计字母个数用collection的counter>>>fromcollectionsimportCounter>>>mystr='sdfsfsfsdfsd,were,hrhrgege.sdfwe!sfsdfs'>>>Counter(mystr)Counter({'s':9,'d':5,'f':7,',':2,'w':2,'e':5,'r':3,'h':2,'g':2,'.':1,'!':1})1234567891011121314统计单词个数,先变为列表,在计算列表长度>>>mystr2="hello,Nicetomeetyou!">>>len(mystr2.split(""))5123426.列表推导,求奇偶数[xforxinrange(20)ifx%2==1]27.一行代码展开列表对于list1中的每个元素i(子列表),遍历其所有元素j,并将这些元素收集到一个新的列表中:list1=[[1,2,3],[4,5,6],[7,8,9]][jforiinlist1forjini]28.实现二分法查找函数//向下取整到最接近的整数非递归defbinary_search(data,item):left=0right=len(data)-1whileleft0:mid=n//2ifdata[mid]==item:returnTrueelifdata[mid]>item:returnbinary_search(data[:mid],item)else:returnbinary_search(data[mid+1:],item)returnFalse123456789101112不管怎样,都是返回等于,更新是中间值-1和中间值+129.合并两个元组到字典(zip一对一打包)先zip再dict>>>a=("zhangfei","guanyu")>>>b=(66,80)>>>dict(zip(a,b))##{'zhangfei':66,'guanyu':80}1234530.给出如下代码的输入,并简单解释>>>a=(1,2,3,[4,5,6,7],8)>>>a[3]=212✘:()是元组,元组不能修改,不可变>>>a=(1,2,3,[4,5,6,7],8)>>>a[3][2]=2>>>a(1,2,3,[4,5,2,7],8)1234✔:列表可修改,就()元组不行32.列表推导式[]、字典推导式{}和生成器表达式()列表推导式是方括号[],返回一个列表list[kforkinrange(10)]字典推导式是花括号还有键和值,返回一个字典dic>>>dic={k:2forkin["a","b","c","d"]}>>>dic{'a':2,'b':2,'c':2,'d':2}>>>type(dic)dict12345生成器是圆括号(),用next访问元素ge=(iforiinrange(20))>>>ge_listat0x000001C3C127AAC8>#由一个生成器表达式()创建,并存储在内存地址0x000001C3C127AAC8处next(ge)123433.简述read、readline、readlines的区别read()读取整个文件readline()读取下一行,使用生成器方法readlines()读取整个文件到一个迭代器,需要一行一行遍历才能输出#假设有一个名为'example.txt'的文件,内容如下:#Line1#Line2#Line3withopen('example.txt','r')asfile:#使用read()方法读取整个文件content=file.read()print(content)#重置文件指针到开始位置file.seek(0)#使用readline()方法逐行读取print(file.readline())#输出:'Line1\n'print(file.readline())#输出:'Line2\n'#再次重置文件指针到开始位置file.seek(0)#使用readlines()方法读取所有行lines=file.readlines()forlineinlines:print(repr(line))#输出:'Line1\n','Line2\n','Line3\n'12345678910111213141516171819202122232434.打乱一个列表andom.shuffle>>>importrandom>>>list=list(range(1,10))>>>random.shuffle(list)>>>list[3,9,1,4,6,2,8,7,5]1234535.反转字符串‘luobodazahui’[::-1]表示以-1的步长向前遍历,相当于从后往前遍历一遍,也就是反转。而列表可以直接用reverse36.单下划线和双下划线的作用37.新式类和旧式类在python里凡是继承了object的类,都是新式类Python3里只有新式类(又是一个版本的问题)38.Python面向对象中的继承有什么特点继承是一种创建新类的方式,在Python的面向对象编程中,继承具有以下特点:基类(父类)与子类(子类):在继承关系中,被继承的类称为基类或父类,继承基类的类称为子类。子类会继承基类的属性和方法。属性与方法继承:子类会继承基类的所有属性和方法,因此在子类中可以访问基类的属性和方法。根据继承方式的不同(如单继承、多重继承),子类可以继承多个基类的属性和方法。扩展与覆盖:子类可以在继承基类的基础上进行扩展,添加新的属性和方法。同时,子类也可以覆盖(重写)基类的方法以实现不同的功能。当子类中定义了与基类同名的方法时,子类会优先调用自己的方法。super()函数:在子类中,可以使用super()函数来调用基类的方法。这在子类需要在重写方法的基础上扩展基类功能时非常有用。使用super()函数可以确保基类的方法按照方法解析顺序(MRO)正确地调用。方法解析顺序(MRO):Python中使用C3线性化算法来解决多重继承的顺序问题。MRO是一个包含类自身及其所有基类的有序列表,它决定了类继承体系中调用方法的顺序。可以使用ClassName.mro()或super()函数查看MRO列表。抽象基类(ABC):Python中的抽象基类用于定义接口规范,它强制子类实现特定的方法。抽象基类可以通过abc模块的ABCMeta元类和abstractmethod装饰器来实现。下面是一个简单的继承示例:classAnimal:def__init__(self,name):self.name=namedefspeak(self):passclassDog(Animal):defspeak(self):returnf'{self.name}saysWoof!'classCat(Animal):defspeak(self):returnf'{self.name}saysMeow!'animals=[Dog("Max"),Cat("Molly")]foranimalinanimals:print(animal.speak())12345678910111213141516171819在这个示例中,Dog和Cat类都继承了Animal类,并分别覆盖了speak()方法。39.super函数的作用用于调用父类(超类)的方法或初始化父类(在__init__中)classParent:def__init__(self,value):self.value=valuedefshow(self):print(f"Parentvalue:{self.value}")classChild(Parent):def__init__(self,value,extension):super().__init__(value)#初始化父类的__init__self.extension=extensiondefshow(self):super().show()#调用父类的show方法print(f"Childextension:{self.extension}")#创建Child类的实例child=Child(10,'extrainfo')child.show()1234567891011121314151617181940.类中的各种方法在类中,我们可以定义各种不同类型的函数,主要包括以下几种:实例方法:这是类中最常见的函数类型,它们需要通过实例来调用,第一个参数默认为self,代表实例本身,可以访问和修改实例的属性。classMyClass:definstance_method(self,a,b):returna+b123类方法:类方法是定义在类上的函数,通过@classmethod装饰器来修饰,它们的第一个参数默认为cls,代表类本身,可以访问和修改类属性,但不能访问实例属性。classMyClass:class_variable=123@classmethoddefclass_method(cls):cls.class_variable+=1returncls.class_variable1234567静态方法:静态方法是定义在类上的函数,通过@staticmethod装饰器来修饰,它们不需要特定的第一个参数,不能访问类或实例的任何属性。classMyClassstaticmethoddefstatic_method(a,b):returna*b1234属性方法:属性方法可以让类的一个方法变成只读属性,或者为属性的读写提供特定的方法。通过@property装饰器实现。classMyClass:def__init__(self,value):self._value=value@propertydefvalue(self):returnself._value@value.setterdefvalue(self,new_value):ifisinstance(new_value,int):self._value=new_valueelse:raiseValueError("Valuemustbeaninteger")1234567891011121314魔法方法:这些方法以双下划线开头和结尾,由Python自动调用,用于实现类的内部机制。比如__init__,__del__,__str__,__eq__等。classMyClass:def__init__(self,value):self.value=valuedef__str__(self):returnf"MyClasswithvalue{self.value}"def__eq__(self,other):ifisinstance(other,MyClass):returnself.value==other.valuereturnFalse1234567891011以上就是类中常见的几种函数类型。41.如何判断是函数还是方法与类和实例无绑定关系的function都属于函数(function)与类和实例有绑定关系的function都属于方法(method)42.isinstance的作用以及与type()的区别(🧡🧡)区别:type()不会认为子类是一种父类类型,不考虑继承关系;isinstance()会认为子类是一种父类类型,考虑继承关系。classA(object):passclassB(A):pass>>>a=A()>>>b=B()>>>print(isinstance(a,A))True>>>print(type(a)==A)True>>>print(isinstance(b,A))#考虑继承True>>>print(type(b)==A)#不考虑继承False12345678910111213141516171843.单例模式与工厂模式单例模式和工厂模式是两种常用的软件设计模式,它们在软件设计中扮演着不同的角色,具有各自的特点和适用场景。以下是两种模式的详细介绍:单例模式定义:单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。特点:唯一性:单例模式保证一个类在整个应用程序中只有一个实例。全局访问点:通过单例模式,可以提供一个全局访问点来访问该类的唯一实例。适用场景:适用于创建一个对象需要消耗过多资源,或者需要保证对象唯一性的场景,如数据库连接池、线程池等。实现方式:单例模式有多种实现方式,包括懒汉式、饿汉式、双重检查锁和登记式等。工厂模式定义:工厂模式是一种设计模式,它通过一个工厂类来封装和抽象对象的创建过程,使得客户端代码不需要直接进行对象的实例化。特点:封装性:工厂模式封装了对象创建的细节,降低了系统各部分之间的耦合度。接口一致性:所有创建的对象通常都实现自同一个接口或继承自同一个基类,增加了代码的灵活性。适用场景:适用于需要生成复杂对象,或者需要灵活应对不同条件创建不同实例的场景,如数据库访问、日志记录等。实现方式:工厂模式有多种实现方式,包括简单工厂模式、工厂方法模式和抽象工厂模式。区别目的:单例模式主要用于控制类的实例数量,确保只有一个实例;而工厂模式主要用于封装对象的创建过程,提高代码的可维护性和可扩展性。实现方式:单例模式通过类的静态方法和私有构造函数来实现;工厂模式通过工厂类来创建对象实例。适用场景:单例模式适用于需要保证对象唯一性的场景;工厂模式适用于需要灵活创建不同对象实例的场景。通过以上分析,我们可以看到单例模式和工厂模式在设计模式中各有其独特的用途和优势,选择哪种模式取决于具体的应用场景和需求。44.查看目录下的所有文件importosprint(os.listdir('.'))#其中'.'表示当前工作目录。这个函数会返回一个列表,包含了当前目录下所有的文件和目录名。1245.计算由1到5组成的互不重复的三位数foriinrange(1,6): forjinrange(1,6): forkinrange(1,6): ifi!=jandj!=kandk!=i: print(f"{i}{j}{k}")1234546.去除字符串首尾空格.strip(删除字符串两端的空白字符或者指定字符>>>"helloworld".strip()'helloworld'12347.去除字符串中间的空格>>>"helloyouaregood".replace("","")'helloyouaregood'>>>"".join("helloyouaregood".split(""))'helloyouaregood'123448.字符串格式化方式方法一:使用%操作符print(“Thisisfor%s”%“Python”)print(“Thisisfor%s,and%s”%(“Python”,“You”))方法二:str.format(在Python3中,引入了这个新的字符串格式化方法)print(“Thisismy{}”.format(“chat”))print(“Thisis{name},hopeyoucan{do}”.format(name=“zhouluob”,do=“like”))方法三:f-strings(在Python3-6中,引入了这个新的字符串格式化方法)name=“luobodazahui”print(f"hello{name}")49.将"helloworld"转换为首字母大写"HelloWorld"1对字符串.title()函数str1=“helloworld”str1.title()2.对单词capitalize()函数"".join(list(map(lambdax:x.capitalize(),str1.split(""))))3对字符.upper()"".join(list(map(lambdax:x[0].upper()+x[1:],str1.split(""))))map()函数将这个函数应用到分割后的单词列表的每个元素上50.一行代码转换列表中的整数为字符串>>>list1=[1,2,3]>>>list(map(lambdax:str(x)forxinlist1))#或者[lambdax:str(x)forxinlist1]列表推导式['1','2','3']12351.Python中的反射(🧡🧡)27号基于字符串的事件驱动!利用字符串的形式对模块的内存进行修改getattr,hasattr,setattr,delattr对模块的修改都在内存中进行,并不会影响文件中真实内容。52.metaclass元类(🧡🧡)type就是创建object类对象的类,obeject是type的实例,创建一个类其实是type的__call__运算符的重载正常的MyClass定义,和手工去调用type运算符的结果是一样的classX:a=1X=type('X',(object,),dict(a=1))1234那元类是干嘛的呢?是type的子类,通过替换type中的__call__运算符重载机制,可以实现父类对子类的属性进行操作。classMyMeta(type):def__new__(cls,*args,**kwargs):print('===>MyMeta.__new__')print(cls.__name__)returnsuper().__new__(cls,*args,**kwargs)def__init__(self,classname,superclasses,attributedict):super().__init__(classname,superclasses,attributedict)print('===>MyMeta.__init__')print(self.__name__)print(attributedict)print(self.tag)def__call__(self,*args,**kwargs):print('===>MyMeta.__call__')obj=self.__new__(self,*args,**kwargs)self.__init__(self,*args,**kwargs)returnobjclassFoo(object,metaclass=MyMeta):tag='!Foo'def__new__(cls,*args,**kwargs):print('===>Foo.__new__')returnsuper().__new__(cls)def__init__(self,name):print('===>Foo.__init__')self.name=name#----------------------输出----------------------#===>MyMeta.__new__#MyMeta#===>MyMeta.__init__#Foo#{'__module__':'__main__','__qualname__':'Foo','tag':'!Foo','__new__':,'__init__':,'__classcell__':}#!Foo>>>print('teststart')>>>foo=Foo('test')>>>print('testend')#teststart#===>MyMeta.__call__#===>Foo.__new__#===>Foo.__init__#testend12345678910111213141516171819202122232425262728293031323334353637383940414243444546创建一个类时,(1)先在属性中查找是否有metaclass属性,(2)没有,就在父类中查找(3)没有就在模块中查找(4)再没有,就用type来创建对象。注意,通过metaclass,必须返回一个类returnobj同时,可以实现在创建时,就对子类的属性进行操作。(一般父类是不可以对子类的属性操作的哦)defMyMetaFunction(classname,superclasses,attributedict):attributedict['year']=2019returntype(classname,superclasses,attributedict)classFoo(object,metaclass=MyMetaFunction):tag='!Foo'def__new__(cls,*args,**kwargs):print('===>Foo.__new__')returnsuper().__new__(cls)def__init__(self,name):print('===>Foo.__init__')self.name=name>>>foo=Foo('test')===>Foo.__new__===>Foo.__init__>>>print('name:%s,tag:%s,year:%s'%(foo.name,foo.tag,foo.year))name:test,tag:!Foo,year:201912345678910111213141516171819202122先有元类,再有类,再有实例。53.sort和sorted的区别sort改变原列表。sorted返回一个新的对象54.Python中的GILGIL是Python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行Python程序的时候会占用Python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。进程(Process)定义:进程是操作系统进行资源分配和调度的一个独立单位。它是应用程序运行的实例,拥有独立的内存空间。地址空间:每个进程有自己的地址空间,这包括代码段、数据段和堆栈等。全局数据:进程拥有自己的全局变量和静态变量。独立性:进程之间相互独立,一个进程的崩溃不会直接影响到其他进程。资源占用:进程间通信(IPC)和进程切换开销较大,因为它们需要操作系统进行协调。创建和销毁开销:进程的创建和销毁需要较多的资源和时间。线程(Thread)定义:线程是进程中的一个实体,是CPU调度和执行的单位,是程序执行的最小单位。地址空间:同一进程内的线程共享进程的地址空间,包括代码段和数据段。全局数据:线程共享相同的全局变量和静态变量。轻量级:线程的创建、同步和销毁的开销比进程小。并发性:线程使得多任务并发执行成为可能,它们可以并行处理任务。资源共享:线程之间可以轻松共享数据,但这也可能导致数据同步问题。进程与线程的区别:资源占用:进程拥有独立的资源,线程共享进程的资源。执行:进程是程序的执行流程,线程是进程中执行的子流程。创建开销:进程的创建和销毁开销较大,线程相对较小。通信:进程间通信需要使用IPC机制,线程间可以直接访问共享内存。独立性:进程间独立,线程间共享。错误影响:进程的一个错误通常不会影响其他进程,但线程的错误可能影响整个进程。上下文切换:线程间的上下文切换比进程快,因为它们共享同样的内存空间。理解示例:进程可以比作一个工厂,每个工厂拥有自己的资源和生产流程。线程可以比作工厂中的工人,他们共享工厂的资源,协同工作以完成生产任务。55.产生8位随机密码(🧡🧡)random.choice选择,string.printable生成字符串>>>importrandom>>>importstring>>>"".join(random.choice(string.printable[:-7])foriinrange(8))#从string.printable中移除最后7个字符1234生成器表达式和列表推导式(listcomprehension)都是简洁地创建新数据结构的方法,但它们之间存在一些关键区别:内存使用:列表推导式会立即生成一个新的列表,这意味着它会占用与列表大小成正比的内存。对于大型数据集,这可能导致内存不足。而生成器表达式不会立即生成值,而是返回一个生成器对象。这个对象在迭代过程中逐个产生值,因此它的内存占用很小,无论它表示的序列有多大。语法:生成器表达式的语法与列表推导式非常相似,只是在圆括号而不是方括号内编写。例如:列表推导式:[exprforiteminiterableifcondition]生成器表达式:(exprforiteminiterableifcondition)返回类型:列表推导式返回一个列表,而生成器表达式返回一个生成器对象(generator类型)。生成器对象实现了迭代器协议,可以使用next()函数或for循环进行迭代。可迭代性:生成器表达式返回的生成器对象只能迭代一次。当所有值都被迭代完后,生成器对象就会耗尽。要再次迭代,需要重新创建一个新的生成器对象。而列表推导式返回的列表可以多次迭代。以下是一个简单的例子,展示了列表推导式和生成器表达式的用法:#列表推导式squares=[random.randint(1,100)**2for_inrange(5)]print(squares)#生成器表达式squares_gen=(random.randint(1,100)**2for_inrange(5))forsquareinsquares_gen:print(square,end="")```1234556.输出原始字符>>>print('hello\nworld')helloworld>>>print(b'hello\nworld')b'hello\nworld'>>>print(r'hello\nworld')hello\nworld1234567b前缀表示字节字符串(bytestring),即b’hello\nworld’是一个包含字节的不可变序列。这种字符串用于处理二进制数据。r前缀表示原始字符串(rawstring),在这种字符串中,转义字符不会被处理。57.简述any()和all()方法all可迭代对象中的所有元素是否都为Trueany函数用于判断可迭代对象中是否至少有一个元素为True0nonefalse都是false58.反转整数是否是整数,是否一位数,是否负数defreverse_int(x):ifnotisinstance(x,int):returnFalseif-10pivot]returnquick_sort(left)+middle+quick_sort(right)#示例arr=[64,34,25,12,22,11,90]sorted_arr=quick_sort(arr)print("Sortedarrayis:",sorted_arr)12345678910111213输出结果:Sortedarrayis:[11,12,22,25,34,64,90]1快速排序的平均时间复杂度为O(nlog(n)),最坏情况下的时间复杂度为O(n^2)。但在实际应用中,快速排序通常比其他O(nlog(n))算法更高效,因为它的内部循环可以在大部分架构上更有效地利用缓存。为了避免最坏情况的发生,可以使用随机方法选择基准元素。70.requests简介71.比较两个json数据是否相等72.读取键盘输入input()defforinput():input_text=input()print("yourinputtextis:",input_text)>>>forinput()>?2yourinputtextis:2123456773.enumerate()的用法74.pass语句占位,不做操作,为了保持结构完整性defforpass(n):ifn==1:passelse:print('not1')>>>forpass(1)1234567875.正则匹配邮箱76.统计字符串中大写字母的数量·ifi.isupper()77.json序列化时保留中文ensure_ascii=False78.简述继承79.什么是猴子补丁(🧡🧡)猴子补丁(MonkeyPatch)和装饰器(Decorator)都是Python中用于修改或增强已有对象功能的技术,但它们的用途、实现方式以及适用场景有所不同猴子补丁(MonkeyPatch):猴子补丁是在运行时动态地修改类或模块的行为。通过直接修改类或模块的属性,可以添加、修改或删除现有的方法、属性等。猴子补丁的主要优点是可以在不修改原始代码的情况下调整行为,这在调试、测试和扩展第三方库时非常有用。然而,猴子补丁可能导致代码难以维护和理解,因为它改变了对象的内部实现。另外,使用猴子补丁时需要谨慎,因为在某些情况下,它可能导致意外的副作用或不可预见的错误。以下是一个猴子补丁的示例,用于修改字符串类的upper方法:defcustom_upper(self):returnself[::-1].upper()str.upper=custom_uppertext="hello"print(text.upper())#输出"OLLEh"1234567装饰器(Decorator):装饰器是一种设计模式,用于在不修改原始函数或类的基础上,为其添加新功能或者修改现有功能。装饰器本质上是一个接受函数或类作为参数的高阶函数,它返回一个新的函数或类,以实现对输入对象功能的扩展或修改。装饰器语法使用@decorator_name语法糖,并放在要修饰的函数或类定义之前。以下是一个使用装饰器记录函数执行时间的示例:importtimedeftimer_decorator(func):defwrapper(*args,**kwargs):start_time=time.time()result=func(*args,**kwargs)end_time=time.time()print(f"{func.__name__}took{end_time-start_time:.2f}secondstoexecute.")returnresultreturnwrapper@timer_decoratordefsome_function():time.sleep(1)some_function()12345678910111213141516总结:猴子补丁是在运行时动态修改对象的行为,而装饰器是通过高阶函数在编译时修改或增强对象的功能。猴子补丁主要适用于对模块或类的内部实现进行修改,而装饰器主要用于修改或增强函数或类的功能,而不改变其内部实现。装饰器提供了更好的封装、可维护性和可读性,而猴子补丁可能导致代码变得难以理解和维护。尽量使用装饰器来实现功能扩展,而避免使用猴子补丁,除非确实需要在运行时修改对象的行为。80.help()函数和dir()函数81.解释Python中的//,%和**运算符82.主动抛出异常raisedeftest_raise(n):ifnotisinstance(n,int):raiseException("notainttype")else:print("good")>>>test_raise(8.9)Traceback(mostrecentcalllast):File"D:\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py",line3331,inrun_codeexec(code_obj,self.user_global_ns,self.user_ns)File"",line1,intest_raise(8.9)File"",line3,intest_raiseraiseException("notainttype")Exception:notainttype1234567891011121314151683.tuple和list转换tuple()list()>>>tuple1=(1,2,3,4)>>>list1=list(tuple1)>>>print(list1)>>>tuple2=tuple(list1)>>>print(tuple2)1234584.简述断言Python的断言就是检测一个条件,如果条件为真,它什么都不做;反之它触发一个带可选错误信息的AssertionError。85.什么是异步非阻塞86.什么是负索引87.退出Python后,内存是否全部释放88.Flask和Django的异同89.创建删除操作系统上的文件90.简述logging模块91.统计字符串中字符出现次数92.正则re.complie的作用93.tryexceptelse/finally的意义94.反转列表95.字符串中数字替换>>>importre>>>str1='我是周萝卜,今年18岁'>>>re.sub(r"\d+","20",str1)'我是周萝卜,今年20岁'1234596.读取大文件(🧡🧡)97.输入日期,判断这一天是这一年的第几天98.排序99.将字符串处理成字典100.下面代码的输出结果将是什么?补充被问的101python协程异步协程线程进程都属于并发;并发是在一个处理器上轮流处理任务,强调资源的共享和分配;并行是在多个处理器上同时处理任务,强调硬件资源的利用。asyncio:异步函数库request:同步函数库详细见metagpt异步编程102python子类不用super调用父类属性不用super一般是不可以调用父类的方法的,但是子类执行行,父类执行__new__函数(创建实例),所以想不用super调用父类可以写到__new__里问题参考自python八股
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-10 05:55 , Processed in 0.418470 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表