python面试题
python基础
-
Python的函数参数传递
类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。
-
staticmethod classmethod 区别
类方法有类变量cls传入,从而可以用cls做一些相关的处理。并且有子类继承时,调用该类方法时,传入的类变量cls是子类,而非父类。 对于类方法,可以通过类来调用。如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
-
python元类与对象实例化
* Foo(*args, **kwargs) 等价于 Foo.__call__(*args, **kwargs)。
* 因为 Foo 是 type 的对象,所以 Foo.__call__(*args, **kwargs)调用的是 type.__call__(Foo, *args, **kwargs)。
* type.__call__(Foo, *args, **kwargs) 调用的是type.__new__(Foo, *args, **kwargs),然后返回了 obj。
* obj 被 obj.__init__(*args, **kwargs) 初始化, 最后 obj 就被返回了
-
怎么实现一个单例
- 一个利用 new 方法的很强大的示例就是实现 Singleton 类:
class Singleton(object): def __new__(cls, *args, **kw): if not hasattr(cls, '_instance'): orig = super(Singleton, cls) cls._instance = orig.__new__(cls, *args, **kw) return cls._instance
- 共享属性: 创建实例时把所有实例的dict指向同一个字典,这样它们具有相同的属性和方法.
class Borg(object): _state = {} def __new__(cls, *args, **kw): ob = super(Borg, cls).__new__(cls, *args, **kw) ob.__dict__ = cls._state return ob
- 装饰器版本
def singleton(cls, *args, **kw): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls(*args, **kw) return instances[cls] return getinstance
- import方法: 作为python的模块是天然的单例模式
```PYTHON
# mysingleton.py
class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
# to use
from mysingleton import my_singleton
my_singleton.foo()
-
yield 和 generator, 协程
http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html
yield实现一个生产者消费者模型:
import time def consumer(): r = '' while True: n = yield r if not n: return print('[CONSUMER] Consuming %s...' % n) time.sleep(1) r = '200 OK' def produce(c): c.next() n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) print('[PRODUCER] Consumer return: %s' % r) c.close() if __name__=='__main__': c = consumer() produce(c)
跟多线程不同的是,协程是非抢占式的。协程的实现跟多线程没什么关系,主要还是通过类似保存栈的上下文环境(或者类似的技术)来实现的。
python中可以通过多进程+协程来充分利用多核优势,而且避免了多线程之间切换的开销。
注意到consumer函数是一个generator(生成器),把一个consumer传入produce后:
-
首先调用c.next()启动生成器;
-
然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
-
consumer通过yield拿到消息,处理,又通过yield把结果传回;
-
produce拿到consumer处理的结果,继续生产下一条消息;
-
produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
最后套用Donald Knuth的一句话总结协程的特点:
“子程序就是协程的一种特例。”
-
-
gevent
from gevent import monkey; monkey.patch_all() import gevent import urllib2 def f(url): print('GET: %s' % url) resp = urllib2.urlopen(url) data = resp.read() print('%d bytes received from %s.' % (len(data), url)) gevent.joinall([ gevent.spawn(f, 'https://www.python.org/'), gevent.spawn(f, 'https://www.yahoo.com/'), gevent.spawn(f, 'https://github.com/'), ])
-
面向切面编程AOP和装饰器
-
鸭子类型
-
GIL线程全局锁
服务器系统
- tornado单线程怎么实现非阻塞异步的web服务器系统
网友评论