这样的二维字典,是用户-电影-评分字典
通过这个方式获取二维字典第一个key:next(iter(your_dict))
userCF.recommend(next(iter(trainSet)))
[k for k in dic] ,用推导式直接拿出所有键,或者用 dic.keys() 也可以
a = {1:1,2:3,4:5}
print(list(a.keys()))
怎么将一个二维字典的第一个key,作为参数传入函数中?
假如你的字典是example_dict:
那么你的第一个key: example_dict.keys()[0]
第二个key: example_dict.keys()[1]
字典的第一个第二维的key:
example_dict.values()[0].keys()[0]
sorted_list = [item.upper() for item in list(d.keys())]
5. python新式类和经典类的区别
a.在python里凡是继承了object的类,都是新式类;
b…
6. python中内置的数据结构有哪些
整型int、长整型long、浮点型float、复数complex、字符串str、
列表list、元组tuple、字典dict、集合set
python3中没有long,只有无限精度的int
7. 可变类型和不可变类型
super()如果不写参数的话,那么默认就是super(当前类, self)。
9. Python中类方法、类实例方法、静态方法有何区别
类方法:是类对象的方法,在定义时需要在上方使用@classmethod进行装饰,形参为cls,表示类对象,类对象和实例对象都可调用;
类实例方法:是类实例化对象的方法,只有实例对象可以调用,形参为self,指代对象本身;
静态方法:是一个任意函数,在其上方使用@staticmethod进行装饰,可以用对象直接调用,静态方法实际上跟该类没有太大关系;
10. Python单例
import threading
class Singleton(object):
_instance_lock = threading.Lock() # 如果不加锁,那么单例功能会有失效的情况。
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"): # 如果该类“不“含有实例化对象
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
# 用父类(object)的new方法创建一个该类(cls==Singleton)的实例。
Singleton._instance = object.__new__(cls)
return Singleton._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1,obj2)
def task(arg):
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
11. 请描述抽象类和接口类的区别和联系
1.抽象类:规定了一系列的方法,并规定了必须由继承类实现的方法。由于有抽象方法的存在,所以抽象类不能实例化。
可以将抽象类理解为毛坯房,门窗,墙面的样式由你自己来定,所以抽象类与作为基类的普通类的区别在于约束性更强。
2.接口类:与抽象类很相似,表现在接口中定义的方法,必须由引用类实现,但他与抽象类的根本区别在于用途:
与不同个体间沟通的规则,你要进宿舍需要有钥匙,这个钥匙就是你与宿舍的接口,你的舍友也有这个接口,
所以他也能进入宿舍,你用手机通话,那么手机就是你与他人交流的接口。
3.区别和关联:
a.接口是抽象类的变体,接口中所有的方法都是抽象的,而抽象类中可以有非抽象方法,抽象类是声明方法的存在而不去实现它的类;
b.接口可以继承,抽象类不行;
c.接口定义方法,没有实现的代码,而抽象类可以实现部分方法;
d.接口中基本数据类型为static而抽象类不是;
12. 编写函数的4个原则
1.函数设计要尽量短小;
2.函数声明要做到合理、简单、易于使用;
3.函数参数设计应该考虑向下兼容;
4.一个函数只做一件事情,尽量保证函数语句粒度的一致性;
13. 什么是lambda函数?有什么好处?
lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数;
1.lambda函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下;
2.匿名函数,一般用来给filter,map这样的函数式编程服务;
3.作为回调函数,传递给某些应用,比如消息处理;
14. 什么是闭包
在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。
15. Python中的yield
yield类似return会停止,但是不会结束。yield作为可迭代的 generator(生成器)对象,
每次迭代的时候会在yield语句后停止。
def simple_generator():
x = 2
yield x2
yield x3
yield x**4
generator_object = simple_generator()
[item for item in generator_object]
#[4, 8, 16]
16. Python实现私用变量的效果
多进程:适合CPU密集操作(cpu指令比较多,如位多的浮点运算)。
线程:cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在。一个进程至少有一个线程,叫做主线程。
而多个线程共享内存(数据共享,共享全局变量),从而极大的提高了程序的运行效率。
多线程:适合IO密集性操作(读写数据操作比较多的,比如爬虫);
协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。
协程调度时,将寄存器上下文和栈保存到其它地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,
直接操作栈基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
三者关系:进程里面有线程,线程里面有协程。
线程是并发,进程是并行。
并行:同一时刻多个任务同时运行;
并发:不会在同一时刻同时运行,存在交替执行的情况。
18. Python异步的使用场景
锁是Python提供的对线程控制的对象。有互斥锁,可重入锁,死锁。
锁的好处:确保某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行;能解决资源竞争下的原子操作问题。
锁的坏处:阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率大大下降。
20. Python的线程同步
setDaemon(False),当一个进程启动之后,会默认产生一个主线程,因为线程时程序执行的最小单位。
当设置多线程时,主线程会创建多个子线程。在Python中,默认情况下就是setDaemon(False),
主线程执行完自己的任务以后就退出。此时子线程会继续执行自己的任务,直到自己的任务结束。
setDaemon(True),这时子线程为守护线程,主线程一旦执行结束,则全部子线程被强制终止。
join(线程同步),join所完成的工作就是线程同步,即主线程任务结束以后,进入堵塞状态,
一直等待所有的子线程结束以后,主线程再终止。
当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。
所以说,如果有10个子线程,全部等待时间就是每个timeout的累加和。
如果没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,
但是子线程依然存活,并且持续运行,直到子线程全部结束,程序退出。(孤儿进程)
import threading
import time
def thread():
time.sleep(2)
print(’—子线程结束—’)
def main():
t1 = threading.Thread(target=thread)
t1.setDaemon(True) # 设置子线程守护主线程
t1.start()
t1.join(timeout=1) # 线程同步,主线程堵塞1s,然后主线程结束,子线程继续执行;
# 如果不设置timeout参数就等子线程结束后主线程再结束;
# 如果设置了setDaemon=True和timeout=1主线程等待1s后会强制杀死子线程,然后主线程结束。
print(’—主线程结束—’)
main()
21. 死锁
定义:若干子线程在系统资源竞争的时候,都在等待对方对某部分资源解除占用状态,结果谁也不愿意先解锁,程序无法执行下去。
GIL锁:全局解释器锁;
作用:限制多线程同时执行,保证同一时间只有一个线程执行,所以cpython里的多线程其实是伪多线程。
python里常常使用协程技术来代替多线程,协程是一种更轻量级的线程。
进程和线程的切换是由系统决定,而协程由开发者决定,而模块gevent下切换是遇到了耗时操作时才会切换。
22. 多线程交互访问数据,如何避免重读。
创建一个已访问数据列表,用于存储已经访问过的数据,并加上互斥锁,
在多线程访问数据的时候先查看数据是否在已访问的列表中,若存在就跳过。
23. 线程安全、互斥锁
每个对象都对应于一个可称为”互斥锁“的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
同一进程中的多线程之间共享系统资源,多个线程同时对一个对象进行操作,一个线程操作尚未结束,另一线程已经对其进行操作,
导致最终结果出现错误,此时需要对被操作对象添加互斥锁,保证每个线程对该对象的操作都得到正确的结果。
24. 同步、异步、阻塞,非阻塞
同步:多个任务之间有先后执行顺序,一个执行完下个才能执行。
异步:多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务结果(回调操作)。
阻塞:如果卡住了调用者,调用者不能继续往下执行,指的就是调用者发生阻塞。
非阻塞:如果不会卡住,可以继续执行,指的就是非阻塞。
同步、异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
25. 什么是僵尸进程、孤儿进程
孤儿进程:父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init进程(进程号为1)所收养,
并由init进程对他们的完成状态进行收集。
僵尸进程:进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait/waitpid获取子进程的状态信息,
那么子进程的进程描述符仍然保存在系统中的这些进程。
避免僵尸进程的方法:
import threading
import time
g_num = 0
def test1(num):
global g_num
for i in range(num):
mutex.acquire() # 上锁
g_num += 1
mutex.release() # 解锁
print("---test1---g_num=%d" % g_num)
def test2(num):
global g_num
for i in range(num):
mutex.acquire() # 上锁
g_num += 1
mutex.release() # 解锁
print("---test2---g_num=%d" % g_num)