校招python常见⾯试知识点归纳
1、*arg、**kargs的⽤法?
*args是可变参数,args接受的是⼀个元组,**kargs是关键字参数,接受的是⼀个字典。
2、python的基本数据类型?
Number(数字)、String(字符串)、List(列表)、Tuple(元组)、set(集合)、Dict(字典)
不可变对象有:数值类型,int ,float,字符串,元组
可变对象:列表,字典,集合
可变对象:对象所指的值可以改变,改变时,值指向的内存单元不变,还是指向原来的地址,没有新开辟⼀块内存。
不可变对象:对象所指向的内存中的值不能被改变,当改变这个变量的时候,原来指向的内存中的值不变,变量不再指向原来的值,⽽是开辟⼀块新的内存,变量指向新的内存。
3、内置的数据结构有哪些?
tuple,list,dict,set
set和dict的区别在于有没有存储key对应的value,两者都不可以放⼊可变对象。
4、装饰器?
由于函数也是⼀个对象,⽽且函数对象可以被赋值给变量,所以变量也可以调⽤该函数。
在代码运⾏期间动态增加功能的⽅式,称之为装饰器。
5、list.sort()⽅法和内置函数sorted的区别
list.sort()⽅法会就地排序列表,也就是说不会将原列表复制⼀份。
sorted会新建⼀个列表作为返回值。
两者都有两个可选的关键字参数 reverse和key。
list的数据结构
列表是通过数组和链表实现的容器序列,容器序列存放的是他们所包含的仍以类型的对象的引⽤。
6、什么是可迭代对象?迭代器?
实现了⽅法__iter__的对象是可迭代的,实现了⽅法__next__的对象是迭代器。
通过对可迭代对象调⽤内置函数iter也可以实现⼀个迭代器。
可⽤dir函数查看对象的所有内置⽅法。
7、列表⽣成式?
列表⽣成式是⼀个可以⽣成列表的特定语法形式的表达式。可以帮助我们把⼀个序列或者其他可迭代类型的中的元素过滤或者加⼯,然后在新建⼀个列表。
8、⽣成器
构建⽣成器的两种⽅法:
a)使⽤类似列表⽣成式的⽅法,将列表换成元组。、
b)使⽤包含yield的函数完成。
⽣成器是⼀种使⽤普通函数语法定义的迭代器。
⽣成器有两个单独的部分组成:⽣成器的函数和⽣成器的迭代器。⽣成器的函数有def语句定义的,其中包含yield。⽣成器的迭代器是这个函数返回的结果。
9、装饰器
装饰器的作⽤就是为已经存在的对象添加新的功能。
装饰器是可调⽤对象,其参数是另⼀个函数(被装饰的函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另⼀个函数或可调⽤对象。
装饰器的⼀⼤特点是:能把被装饰的函数替换成其他函数,装饰器在加载模块时⽴即执⾏。
10、setdefault 处理不到的键
类似get,它也获取与指定键相关联的值,除此之外,当字典中不存在键时,为字典中添加指定的键值对。
11、dict和defaultdict的区别
在查dict中没有的键时,dict会抛出⼀个keyerror
defaultdict则会让__getitem__返回⼀个默认值。
12、进程、线程和协程的区别
⼀、概念
1、进程:进程是具有⼀定独⽴功能的程序关于某个数据集合上的⼀次运⾏活动,进程是系统进⾏资源分配和调度的⼀个独⽴单位。每个进程都有⾃⼰的独⽴内存空间,不同进程间通过进程间通信来通信。
2、线程:线程是进程的⼀个实体,是CPU调度和分配⼀个基本单位,它是⽐进程更⼩的能独⽴运⾏的基本单位。线程⾃⼰基本上不拥有系统资源,只拥有⼀点在运⾏中必不可少的资源,但是它可与同属⼀个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要靠内存,上下⽂切换很快,资源开销较少,但⽐进程不够稳定容易丢失数据。
3、协程:协程是⼀种⽤户态的轻量级线程,协程的调度完全由⽤户控制。
⼆、区别与联系
1、进程与线程⽐较
线程是进程内的⼀个执⾏单位,也是进程内可调度实体。区别:
1)地址空间:线程是进程内的⼀个执⾏单元,进程内⾄少有⼀个线程,他们共享进程的地址空间,⽽进程有⾃⼰独⽴的地址空间。
2)资源拥有:进程是资源分配和拥有的单位,同⼀进程内的线程共享进程的资源。python单例模式
3)线程是处理器调度的基本单位,但进程是系统调度。
4)⼆者都是处理多任务的⽅法,均可并发执⾏。
5)每个独⽴的线程有⼀个程序运⾏的⼊⼝、顺序执⾏序列和程序的出⼝吗,但是线程不能够独⽴执⾏,必须依存在应⽤程序中,由应⽤程序提供多个线程执⾏控制。
2、协程和线程的⽐较
1)⼀个线程可以有多个协程,⼀个进程也可以单独拥有多个协程。
2)线程进程都是同步机制,⽽协程是异步
3)协程能保留上⼀次调⽤时的状态,每次过程重⼊时,就相当于上⼀次调⽤的状态。
13、构造函数
构造函数也叫初始化函数,在类创建后⾃动调⽤它们,⽆需先访问函数再调⽤函数下的内容
例如 class FooBar:
def init(self): self.somevar = 42 f = FooBar f.somevar
14.del、remove、pop的区别
del根据位置删除元素,不返回任何值
pop根据位置弹出元素,没有参数就从数组末尾弹出元素,返回的是数组
remove根据值删除元素,默认删除从左到右第⼀个元素
15、数组和链表的区别
数组;数组存储值必须提前声明空间,因为数组存储是连续的,也因此数组查询的时间复杂度是O(1)
插⼊和删除的复杂度是O(n);
链表:不⽤连续存储,链表中每个位置都记录着下⼀个元素的位置信息。链表查询时间复杂度是O(n)
插⼊和删除复杂度是O(1)
16、python如何进⾏内存管理
在python中,使⽤了引⽤计数这⼀技术实现内存管理。当引⽤计数为0的时候,⾃动垃圾回收机制
就会回收这个对象。引⽤计数有循环引⽤的问题。
分代回收机制,主要⽤于解决循环引⽤的问题
17、python 的内存池机制
在Python中,许多时候申请的内存都是⼩块的内存,这些⼩块内存在申请后,很快⼜会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象⼀级的内存池机制。这就意味着Python在运⾏期间会⼤量地执⾏malloc和free的操作,频繁地在⽤户态和核⼼态之间进⾏切换,这将严重影响Python的执⾏效率。为了加速Python的执⾏效率,Python引⼊了⼀个内存池机制,⽤于管理对⼩块内存的申请和释放。
Python提供了对内存的垃圾收集机制,但是它将不⽤的内存放到内存池⽽不是返回给操作系统。
18、python 中的重载
函数重载的主要是为了解决两个问题:
可变的参数类型
可变的参数个数
⼀个基本的设计原则是:仅仅当两个函数除了参数烈性和参数个数不同以外,其功能应该是完全相同的,此时才使⽤函数重载,如果两个函数的功能其实不同,那么不应该使⽤重载,⽽应当使⽤⼀个名字不同的函数。
因为python可以接受任意类型的参数,如果函数的功能相同,那么python不⽤处理本⾝就可以实现可变的参数类型。
对于可变的参数的个数,python的处理⽅法是缺省参数
在调⽤函数时,通常会传递参数,函数内部的代码保持不变,针对 不同的参数处理不同的数据。有位置传参、关键字传参、默认值参数、多值参数等。缺省参数就是含有默认值的参数。
19、新式类和旧式类
python3中所有的类都是新式类,新式类继承是根据C3算法从左到右⼴度优先,旧式类继承从左到右深度优先(MRO:⽅法解析顺序);⼀个旧式类的深度优先的例⼦
按照经典类的查顺序从左到右深度优先的规则,在访问d.foo1()的时候,D这个类是没有的…那么往上查,先到B,⾥⾯没有,深度优先,访问A,到了foo1(),所以这时候调⽤的是A的foo1(),从⽽导致C重写的foo1()被绕过.
20、__new__和__init__的区别
1. __new__是⼀个静态⽅法,⽽__init__是⼀个实例⽅法;
2. __new__⽅法会返回⼀个创建的实例,⽽__init__什么都不返回;
3. 只有在__new__返回⼀个cls的实例时,后⾯的__init__才不能被调⽤;
4. 当创建⼀个新实例时调⽤__new__,初始化⼀个实例时⽤__init__
21、单例模式
class A (): def foo1(self ): print "A"class B (A ): def foo2(self ): pass class C (A ): def foo1(self ): print "C"class D (B , C ): pass d = D ()d .foo1()# A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
单例模式⼀种常见的设计模式。它的核⼼结构中只包含⼀个被称为单例类的特殊类。通过单例模式可以保证系统中的⼀个类只有⼀个实例且易被外界访问,从⽽⽅便对实例个数进⾏控制并节约系统资源。如果希望在系统中某个类的对象只能存在⼀个,单例模式是最好的解决⽅案。
1、使⽤__new__⽅法:
2、共享属性
创建实⼒的时候把所有的__dict__指向同⼀个字典,这样它们具有相同的属性和⽅法。
3、装饰器版本
4、import⽅法
作为python的模块是天然的单例模式
class Single (object ): _instance = None def __new__(cls , *args , **kw ): if cls ._instance is None : cls ._instance = object .__new__(cls , *args , **kw ) return cls ._instance if __name__ == "__main__": a = Single () b = Single () print (id (a )==id (b ))
1
2
3
4
5
6
7
8
9
10
11
12class Borg (object ): _state = {} def __new__(cls , *args , **kw ): ob = super (Borg , cls ).__new__(cls , *args , **kw ) ob .__dict__ = cls ._state return ob class MyClass2(Borg ): a = 1
1
2
3
4
5
6
7
8
9def singleton (cls ): instances = {} def getinstance (*args , **kw ): if cls not in instances : instances [cls ] = cls (*args , **kw ) return instances [cls ] return getinstance @singleton class MyClass : ...
1
2
3
4
5
6
7
8
9
10
11class My_Singleton (object ): def foo (self ): pass my_singleton = My_Singleton ()# to use from mysingleton import my_singleton my_singleton .foo ()
1
2
3
4
5
6
7
8
9
10
22、Python 的作⽤域
python中,⼀个变量的作⽤域总是由代码中被赋值的地⽅所决定。
当python遇到⼀个变量的话他会按照这样的顺序进⾏搜索:
本地作⽤域(Local)→当前作⽤域被嵌⼊的本地作⽤域(Enclosing locals)→全局/模块作⽤域(Global)→内置作⽤域(Built-in)
23、闭包
闭包是指延伸了作⽤域的函数,其中包含函数定义体中引⽤、但是不在定义体中定义的⾮全局变量。也就是说闭包可以访问定义体之外的定义的⾮全局变量。
例⼦:计算移动平均值,每次输⼊⼀个数,返回当前数和之前输⼊的所有数的平均值。
我们⾸先看⼀下不使⽤闭包,我们通常是如何实现这个功能的。
使⽤闭包
注意看使⽤闭包的时候,我们利⽤了⼀个嵌套函数,外层函数返回内部函数。不⽤闭包的时候,我们利⽤self.series存储历史值。使⽤闭包的时候,虽然series定义在本地作⽤域,看似每次调⽤Averager的时候,series都会重新被赋值为[],其实不然。闭包的作⽤就在于此,使⽤闭包的时候,series是⼀个⾃由变量(未在本地作⽤域绑定的变量),闭包函数能够引⽤⾃由变量,并使⾃由变量始终保存在内存中。总结起来就是闭包只有在使⽤嵌套函数时使⽤,闭包是⼀个保留定义函数时存在的⾃由变量的绑定,虽然作⽤域不可⽤了,但是仍能使⽤这些绑定。
这⾥需要注意的是,这⾥⾃由变量series不能在内部函数中重新复制,我们这⾥因为series是列表是可变的数据类型,因此对它进⾏改变不会有问题。但如果我们改⼀下:class Averager : def __init__(self ): self .series = [] #给实例对象绑定⼀个属性series 来存储每次输⼊的数 def __call__(self , new_values ): self .series .append (new_values ) total = sum (self .series ) print (total /len (self .series ))if __name__ == "__main__": avg = Averager () avg (10) #10.0 avg (11) #10.5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def Averager (): series = [] def averager (new_values ): series .append (new_values ) total = sum (series ) print (total /len (series )) return averager # ************if __name__ == "__main__": avg = Averager () avg (10) #10.0 avg (11) #10.5
1
2
3
4
5
6
7
8
9
10
11
12
13
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论