python 面试指南

Table of Contents

  • Python语言特性
    • 1 Python的函数参数传递
    • 2 Python中的元类(metaclass)
    • 3 @staticmethod和@classmethod
    • 4 类变量和实例变量
    • 5 Python自省
    • 6 字典推导式
    • 7 Python中单下划线和双下划线
    • 8 字符串格式化:%和.format
    • 9 迭代器和生成器
    • 10 *args and **kwargs
    • 11 面向切面编程AOP和装饰器
    • 12 鸭子类型
    • 13 Python中重载
    • 14 新式类和旧式类
    • 15 __new____init__的区别
    • 16 单例模式
      • 1 使用__new__方法
      • 2 共享属性
      • 3 装饰器版本
    • 17 Python中的作用域
    • 18 GIL线程全局锁
    • 19 协程
    • 20 闭包
    • 21 lambda函数
    • 22 Python函数式编程
    • 23 Python里的拷贝
    • 24 Python垃圾回收机制
      • 1 引用计数
      • 2 标记-清除机制
      • 3 分代技术
    • 25 Python的List
    • 26 Python的is
    • 27 read,readline和readlines
    • 28 Python2和3的区别
  • 操作系统
    • 1 select,poll和epoll
    • 2 调度算法
    • 3 死锁
    • 4 程序编译与链接
      • 1 预处理
      • 2 编译
      • 3 汇编
      • 4 链接
    • 5 静态链接和动态链接
    • 6 虚拟内存技术
    • 7 分页和分段
      • 分页与分段的主要区别
    • 8 页面置换算法
    • 9 边沿触发和水平触发
  • 数据库
    • 1 事务
    • 2 数据库索引
    • 3 Redis原理
    • 4 乐观锁和悲观锁
    • 5 MVCC
    • 6 MyISAM和InnoDB
  • 网络
    • 1 三次握手
    • 2 四次挥手
    • 3 ARP协议
    • 4 urllib和urllib2的区别
    • 5 Post和Get
    • 6 Cookie和Session
    • 7 apache和nginx的区别
    • 8 网站用户密码保存
    • 9 HTTP和HTTPS
    • 10 XSRF和XSS
    • 11 幂等 Idempotence
    • 12 RESTful架构(SOAP,RPC)
    • 13 SOAP
    • 14 RPC
    • 15 CGI和WSGI
    • 16 中间人攻击
    • 17 c10k问题
    • 18 socket
    • 19 浏览器缓存
    • 20 HTTP1.0和HTTP1.1
    • 21 Ajax
    • 22 HTTP头部信息
  • *NIX
    • unix进程间通信方式(IPC)
  • 数据结构
    • 1 红黑树
  • 编程题
    • 1 台阶问题/斐波纳挈
    • 2 变态台阶问题
    • 3 矩形覆盖
    • 4 杨氏矩阵查找
    • 5 去除列表中的重复元素
    • 6 链表成对调换
    • 7 创建字典的方法
      • 1 直接创建
      • 2 工厂方法
      • 3 fromkeys()方法
    • 8 合并两个有序列表
    • 9 交叉链表求交点
    • 10 二分查找
    • 11 快排
    • 12 找零问题
    • 13 广度遍历和深度遍历二叉树
    • 14 二叉树节点
    • 15 层次遍历
    • 16 深度遍历
    • 17 前中后序遍历
    • 18 求最大树深
    • 19 求两棵树是否相同
    • 20 前序中序求后序
    • 21 单链表逆置

Python语言特性

1 Python的函数参数传递

看两个例子:

a = 1
def fun(a):
    a = 2
print a  # 1
a = []
def fun(a):
    a.append(1)
print a  # [1]

所有的变量都可以理解是内存中一个对象的“引用”,或者,也可以看似c中void*的感觉。

这里记住的是类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。(这就是这个问题的重点)

当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.所以第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感觉.而第二个例子就不一样了,函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改.

如果还不明白的话,这里有更好的解释: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference

2 Python中的元类(metaclass)

这个非常的不常用,但是像ORM这种复杂的结构还是会需要的,详情请看:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python

3 @staticmethod和@classmethod

Python其实有3个方法,即静态方法(staticmethod),类方法(classmethod)和实例方法,如下:

def foo(x):
    print "executing foo(%s)"%(x)

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x

a=A()

这里先理解下函数参数里面的self和cls.这个self和cls是对类或者实例的绑定,对于一般的函数来说我们可以这么调用foo(x),这个函数就是最常用的,它的工作跟任何东西(类,实例)无关.对于实例方法,我们知道在类里每次定义方法的时候都需要绑定这个实例,就是foo(self, x),为什么要这么做呢?因为实例方法的调用离不开实例,我们需要把实例自己传给函数,调用的时候是这样的a.foo(x)(其实是foo(a, x)).类方法一样,只不过它传递的是类而不是实例,A.class_foo(x).注意这里的self和cls可以替换别的参数,但是python的约定是这俩,还是不要改的好.

对于静态方法其实和普通的方法一样,不需要对谁进行绑定,唯一的区别是调用的时候需要使用a.static_foo(x)或者A.static_foo(x)来调用.

\ 实例方法 类方法 静态方法
a = A() a.foo(x) a.class_foo(x) a.static_foo(x)
A 不可用 A.class_foo(x) A.static_foo(x)

更多关于这个问题:http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python

4 类变量和实例变量

class Person:
    name="aaa"

p1=Person()
p2=Person()
p1.name="bbb"
print p1.name  # bbb
print p2.name  # aaa
print Person.name  # aaa

类变量就是供类使用的变量,实例变量就是供实例使用的.

这里p1.name="bbb"是实例调用了类变量,这其实和上面第一个问题一样,就是函数传参的问题,p1.name一开始是指向的类变量name="aaa",但是在实例的作用域里把类变量的引用改变了,就变成了一个实例变量,self.name不再引用Person的类变量name了.

可以看看下面的例子:

class Person:
    name=[]

p1=Person()
p2=Person()
p1.name.append(1)
print p1.name  # [1]
print p2.name  # [1]
print Person.name  # [1]

参考:http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block

5 Python自省

这个也是python彪悍的特性.

自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.比如type(),dir(),getattr(),hasattr(),isinstance().

6 字典推导式

可能你见过列表推导时,却没有见过字典推导式,在2.7中才加入的:

d = {
   
   key: value for (key, value) in iterable}

7 Python中单下划线和双下划线

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{
   
   '_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

__foo__:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突.

_foo:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.

__foo:这个有真正的意义:解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名.

详情见:http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python

或者: http://www.zhihu.com/question/19754941

8 字符串格式化:%和.format

.format在许多方面看起来更便利.对于%最烦人的是它无法同时传递一个变量和元组.你可能会想下面的代码不会有什么问题:

"hi there %s" % name

但是,如果name恰好是(1,2,3),它将会抛出一个TypeError异常.为了保证它总是正确的,你必须这样做:

"hi there %s" % (name,)   # 提供一个单元素的数组而不是一个参数

但是有点丑…format就没有这些问题.你给的第二个问题也是这样,.format好看多了.

你为什么不用它?

  • 不知道它(在读这个之前)
  • 为了和Python2.5兼容(譬如logging库建议使用%(issue #4))

http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format

9 迭代器和生成器

这个是stackoverflow里python排名第一的问题,值得一看: http://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python

这是中文版: http://taizilongxu.gitbooks.io/stackoverflow-about-python/content/1/README.html

10 *args and **kwargs

*args**kwargs只是为了方便并没有强制使用它们.

当你不确定你的函数里将要传递多少参数时你可以用*args.例如,它可以传递任意数量的参数:

>>> def print_everything(*args):
        for count, thing in enumerate(args):
...         print '{0}. {1}'.format(count, thing)
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage

相似的,**kwargs允许你使用没有事先定义的参数名:

>>> def table_things(**kwargs):
...     for name, value in kwargs.items():
...         print '{0} = {1}'.format(name, value)
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit

你也可以混着用.命名参数首先获得参数值然后所有的其他参数都传递给*args**kwargs.命名参数在列表的最前端.例如:

def table_things(titlestring, **kwargs)

*args**kwargs可以同时在函数的定义中,但是*args必须在**kwargs前面.

当调用函数时你也可以用***语法.例如:

>>> def print_three_things(a, b, c):
..
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨痕_777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值