[翻译整理]stackoverflow python 百问

更新到github了,地址:https://github.com/wklken/stackoverflow-py-top-qa

后续这里不更新了哈


进度40%,最近有点犯懒

刚刚注册,好东西

查看了下前面(vote前15页,挑了下,vote都是100+的样子,大概120个)的问题,链接, 大体梳理了下,本来想放一页搞定,奈何排版太乱,按类型分了下

第一页的前几个比较长,目测都有中文翻译版本,大家可以网上搜下

其他问题相对比较杂,有些简单,有些复杂,拉过来参考参考也不错

总结整理,复习印证(注意,合并了每个问题的多个答案,但是时间仓促,疏漏难免,感兴趣问题直接点链接看原文吧)


基本数据结构(列表,元组,字典等)

判断一个列表为空得最佳实践

问题 链接

答案:

if not a:
    print "List is empty"
#不要用len(a)来判断

为什么是string.join(list)而不是list.join(string)

问题 链接

my_list = ["Hello", "world"]
print "-".join(my_list)
#为什么不是 my_list.join("-") 。。。。这个....

答案:

因为所有可迭代对象都可以被连接,但是连接者总是字符串

如何合并两个列表

问题 链接

listone = [1,2,3]
listtwo = [4,5,6]
#outcome we expect: mergedlist == [1, 2, 3, 4, 5, 6]

1.不考虑顺序(原来问题不是很明确)

listone + listtwo
#linstone.extend(listtwo)也行,就是会修改listone

2.考虑顺序做些处理

>>> listone = [1,2,3]
>>> listtwo = [4,5,6]
>>> import itertools
>>> for item in itertools.chain(listone, listtwo):
...     print item
...
1
2
3
4
5
6

如何扁平一个二维数组

问题 链接

l = [[1,2,3],[4,5,6], [7], [8,9]]
变为[1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9]

列表解析

[item for sublist in l for item in sublist]

itertools

>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain(*list2d))

# python >= 2.6
>>> import itertools
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> merged = list(itertools.chain.from_iterable(list2d))

sum

sum(l, [])

如何获取一个列表的长度

问题 链接

python中是不是只有这种方法可以获取长度?语法很奇怪

arr.__len__()

应该使用这种方式

mylist = [1,2,3,4,5]
len(mylist)

这样做法,不需要对每个容器都定义一个.length()方法,你可以使用len()检查所有实现了__len__()方法的对象

Python中如何复制一个列表

问题 链接

可以用切片的方法

new_list = old_list[:]

可以使用list()函数

new_list = list(old_list)

可以使用copy.copy(),比list()稍慢,因为它首先去查询old_list的数据类型

import copy
new_list = copy.copy(old_list)

如果列表中包含对象,可以使用copy.deepcopy(), 所有方法中最慢,但有时候无法避免

import copy
new_list = copy.deepcopy(old_list)

例子:

import copy

class Foo(object):
    def __init__(self, val):
         self.val = val

    def __repr__(self):
        return str(self.val)

foo = Foo(1)

a = ['foo', foo]
b = a[:]
c = list(a)
d = copy.copy(a)
e = copy.deepcopy(a)

# edit orignal list and instance
a.append('baz')
foo.val = 5

print "original: %r\n slice: %r\n list(): %r\n copy: %r\n deepcopy: %r" \
       % (a, b, c, d, e)

结果:

original: ['foo', 5, 'baz']
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]

效率简单比较

10.59 - copy.deepcopy(old_list)
10.16 - pure python Copy() method copying classes with deepcopy
1.488 - pure python Copy() method not copying classes (only dicts/lists/tuples)
0.325 - for item in old_list: new_list.append(item)
0.217 - [i for i in old_list] (a list comprehension)
0.186 - copy.copy(old_list)
0.075 - list(old_list)
0.053 - new_list = []; new_list.extend(old_list)
0.039 - old_list[:] (list slicing)

列表的append和extend的区别

问题 链接

>>> x = [1, 2]
>>> x.append(3)
>>> x
[1, 2, 3]
>>> x.append([4,5])
>>> x
[1, 2, 3, [4, 5]]
>>>
>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> x
[1, 2, 3, 4, 5]

如何随机地从列表中抽取变量

问题 链接

foo = ['a', 'b', 'c', 'd', 'e']
from random import choice
print choice(foo)

如何利用下标从列表中删除一个元素

问题 链接

1.del

In [9]: a = range(10)
In [10]: a
Out[10]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [11]: del a[-1]
In [12]: a
Out[12]: [0, 1, 2, 3, 4, 5, 6, 7, 8]

2.pop

a = ['a', 'b', 'c', 'd']
a.pop(1)
# now a is ['a', 'c', 'd']

a = ['a', 'b', 'c', 'd']
a.pop()
# now a is ['a', 'b', 'c']

获取列表的最后一个元素

问题 链接

result = l[-1]
result = l.pop()

序列的切片操作

问题 链接

It’s pretty simple really: 很简单:

a[start:end] # start 到 end-1
a[start:]    # start 到 末尾
a[:end]      # 0 到 end-1
a[:]         # 整个列表的拷贝

还有一个step变量,控制步长,可在上面语法中使用

a[start🔚step] # start through not past end, by step

注意,左闭右开

其他特点,开始或结束下标可能是负数,表示从序列末尾开始计算而非从头开始计算,所以

a[-1]    # 最后一个元素
a[-2:]   # 最后两个元素
a[:-2]   # 除了最后两个元素

Python对程序员很友好,如果序列中存在的元素数量少于你要的,例如,你请求 a[:-2] 但是a只有一个元素,你会得到一个空列表,而不是一个错误.有时候你或许希望返回的是一个错误,所以你必须知道这点

如何将一个列表切分成若干个长度相同的子序列

问题 链接

想要得到这样的效果

l = range(1, 1000)
print chunks(l, 10) -> [ [ 1..10 ], [ 11..20 ], .., [ 991..999 ] ]

使用yield:

def chunks(l, n):
    """ Yield successive n-sized chunks from l.
    """
    for i in xrange(0, len(l), n):
        yield l[i:i+n]
list(chunks(range(10, 75), 10))

直接处理

def chunks(l, n):
    return [l[i:i+n] for i in range(0, len(l), n)]

使用列表解析创建一个字典

问题 链接

python 2.6

d = dict((key, value) for (key, value) in sequence)

python 2.7+ or 3, 使用 字典解析语法

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

使用"in"还是"has_key()"

问题 链接

d = {'a': 1, 'b': 2}
'a' in d
True
or:

d = {'a': 1, 'b': 2}
d.has_key('a')
True

哪种更好

in更pythonic, 另外 has_key()在Python3.x中已经被移除

字典默认值

问题 链接

和问题有点偏

#获取时,如不存在,得到默认值
d.get(key, 0)
#设置时,若key不存在,设置默认值,已存在,返回已存在value
d.setdefault(key, []).append(new_element)
#初始即默认值
from collections import defaultdict
d = defaultdict(lambda: 0)
#or d = defaultdict(int)

如何给字典添加一个值

问题 链接

#### Making a dictionary ####
data = {}
# OR #
data = dict()

#### Initially adding values ####
data = {'a':1,'b':2,'c':3}
# OR #
data = dict(a=1, b=2, c=3)

#### Inserting/Updating value ####
data['a']=1  # updates if 'a' exists, else adds 'a'
# OR #
data.update({'a':1})
# OR #
data.update(dict(a=1))

#### Merging 2 dictionaries ####
data.update(data2)  # Where data2 is also a dict.

如何将字段转换成一个object,然后使用对象-属性的方式读取

问题 链接

有dict

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}}

想用这种方式访问

>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar

使用namedtuple

>>> from collections import namedtuple
>>> MyStruct = namedtuple('MyStruct', 'a b d')
>>> s = MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s
MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s.a
1
>>> s.b
{'c': 2}
>>> s.c
>>> s.d
['hi']

使用类

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2

字符串,文件

字符如何转为小写

问题 链接

s = "Kilometer"
print(s.lower())

如何创建不存在的目录结构

问题 链接

if not os.path.exists(directory):
    os.makedirs(directory)

需要注意的是,当目录在exists和makedirs两个函数调用之间被创建时,makedirs将抛出OSError

如何拷贝一个文件

问题 链接

shutil模块

copyfile(src, dst)

将src文件内容拷贝到dst,目标文件夹必须可写,否则将抛出IOError异常

如果目标文件已存在,将被覆盖

另外特殊文件,想字符文件,块设备文件,无法用这个方法进行拷贝

src/dst是字符串

字符串转为float/int

>>> a = "545.2222"
>>> float(a)
545.2222
>>> int(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '545.2222'
>>> int(float(a))
545
>>> int('544')
544

另一种,用 ast模块

>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31

如何反向输出一个字符串

问题 链接

做法

>>> 'hello world'[::-1]
'dlrow olleh'

如何随机生成大写字母和数字组成的字符串

6U1S75
4Z4UKK
U911K4

解决

import string, random
''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(N))

逐行读文件去除换行符(perl chomp line)

问题 链接 类似问题 链接

读一个文件,如何获取每一行内容(不包括换行符)

比较pythonic的做法:

>>> text = "line 1\nline 2\r\nline 3\nline 4"
>>> text.splitlines()
['line 1', 'line 2', 'line 3', 'line 4']

用rstrip,(rstrip/lstrip/strip)

#去除了空白+换行
>>> 'test string \n'.rstrip()
'test string'
#只去换行
>>> 'test string \n'.rstrip('\n')
'test string '
#更通用的做法,系统相关
>>> import os, sys
>>> sys.platform
'linux2'
>>> "foo\r\n".rstrip(os.linesep)
'foo\r'

python中字符串的contains

问题 链接

python中字符串判断contains

使用in关键字

if not "blah" in somestring: continue
if "blah" not in somestring: continue

使用字符串的find/index (注意index查找失败抛异常)

s = "This be a string"
if s.find("is") == -1:
    print "No 'is' here!"
else:
    print "Found 'is' in the string."

如何判断一个字符串是数字

问题 链接

使用这种方法会不会十分丑陋和低效

def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

使用这种方法并不丑陋和低效

使用isdigit(缺点,对非整数无能为力)

a = "03523"
a.isdigit()

如何填充0到数字字符串中保证统一长度

问题 链接

对于字符串

>>> n = '4'
>>> print n.zfill(3)
>>> '004'

对于数字,相关文档

>>> n = 4
>>> print '%03d' % n
>>> 004
>>> print "{0:03d}".format(4)  # python >= 2.6
>>> 004
>>> print("{0:03d}".format(4))  # python 3
>>> 004

控制结构(条件、循环)

如何在循环中获取下标

问题 链接

使用enumerate

for idx, val in enumerate(ints):
    print idx, val

如何判断一个变量的类型

问题 链接

使用type

>>> i = 123
>>> type(i)
<type 'int'>
>>> type(i) is int
True
>>> i = 123456789L
>>> type(i)
<type 'long'>
>>> type(i) is long
True
>>> i = 123.456
>>> type(i)
<type 'float'>
>>> type(i) is float
True

另外一个相同的问题 链接

>>> type( [] ) == list
True
>>> type( {} ) == dict
True
>>> type( "" ) == str
True
>>> type( 0 ) == int
True

>>> class Test1 ( object ):
    pass
>>> class Test2 ( Test1 ):
    pass
>>> a = Test1()
>>> b = Test2()
>>> type( a ) == Test1
True
>>> type( b ) == Test2
True
>>> type( b ) == Test1
False
>>> isinstance( b, Test1 )
True
>>> isinstance( b, Test2 )
True
>>> isinstance( a, Test1 )
True
>>> isinstance( a, Test2 )
False
>>> isinstance( [], list )
True
>>> isinstance( {}, dict )
True

如何判断一个对象是否拥有某个属性

问题 链接

if hasattr(a, 'property'):
    a.property

两种风格

EAFP(easier to ask for forgiveness than permission)

LBYL(look before you leap)

相关内容 EAFP vs LBYL (was Re: A little disappointed so far) EAFP vs. LBYL @Code Like a Pythonista: Idiomatic Python

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()
or

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()

Python中的类变量(环境变量)

问题 链接

在类中定义的变量,不在方法定义中,成为类变量或静态变量

>>> class MyClass:
...     i = 3
...
>>> MyClass.i
3

i是类级别的变量,但这里要和实例级别的变量i区分开

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

这和C++/java完全不同,但和C#区别不大,C#不允许类实例获取静态变量

具体见 what the Python tutorial has to say on the subject of classes and class objects

另外,静态方法

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

如何定义静态方法(static method)

问题 链接

使用 staticmethod装饰器

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print x
MyClass.the_static_method(2) # outputs 2

@staticmethod和@classmethod的区别

问题 链接

staticmethod,静态方法在调用时,对类及实例一无所知

仅仅是获取传递过来的参数,没有隐含的第一个参数,在Python里基本上用处不大,你完全可以用一个模块函数替换它

classmethod, 在调用时,将会获取到其所在的类,或者类实例,作为其第一个参数

当你想将函数作为一个类工厂时,这非常有用: 第一个参数是类,你可以实例化出对应实例对象,甚至子类对象。

可以观察下 dict.fromkey(),是一个类方法,当子类调用时,返回子类的实例

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>

如何获取一个实例的类名

问题 链接

x.__class__.__name__

模块

如何列出一个目录的所有文件

问题 链接

1.使用os.listdir(),得到目录下的所有文件和文件夹

#只需要文件
from os import listdir
from os.path import isfile, join
onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]

2.os.walk()

from os import walk

f = []
for (dirpath, dirnames, filenames) in walk(mypath):
    f.extend(filenames)
    break

3.glob

import glob
print glob.glob("/home/adam/*.txt")

重复问题 链接

import os

for dirname, dirnames, filenames in os.walk('.'):
    # print path to all subdirectories first.
    for subdirname in dirnames:
        print os.path.join(dirname, subdirname)

    # print path to all filenames.
    for filename in filenames:
        print os.path.join(dirname, filename)

json和simplejson的区别

问题 链接

json就是simple,加入到标准库. json在2.6加入,simplejson在2.4+,2.6+,更有优势

另外,simplejson更新频率更高,如果你想使用最新版本,建议用simplejson

好的做法是

try: import simplejson as json
except ImportError: import json

另外,可以关注二者性能上的比较

python中如何获取当前时间

问题 链接

时间日期

>>> import datetime
>>> datetime.datetime.now()
datetime(2009, 1, 6, 15, 8, 24, 78915)

如果仅获取时间

>>> datetime.datetime.time(datetime.datetime.now())
datetime.time(15, 8, 24, 78915))
#等价
>>> datetime.datetime.now().time()

可以从文档中获取更多 文档

如果想避免额外的datetime.

>>> from datetime import datetime

其他

如何从标准输入读取内容stdin

问题 链接

使用fileinput

import fileinput
for line in fileinput.input():
    pass

foo is None 和 foo == None的区别

问题 链接

if foo is None: pass
if foo == None: pass

如果比较相同的对象实例,is总是返回True 而 == 最终取决于 “eq()”

>>> class foo(object):
    def __eq__(self, other):
        return True

>>> f = foo()
>>> f == None
True
>>> f is None
False

>>> list1 = [1, 2, 3]
>>> list2 = [1, 2, 3]]
>>> list1==list2
True
>>> list1 is list2
False

另外

(ob1 is ob2) 等价于 (id(ob1) == id(ob2))

__init__.py是做什么用的

问题 链接

这是包的一部分,具体文档

__init__.py让Python把目录当成包,

最简单的例子,__init__.py仅是一个空文件,但它可以一样执行包初始化代码或者设置__all__变量,后续说明

如何获取安装的python模块列表

问题 链接

>>> help('modules')

环境相关

setup.py安装后如何卸载

问题 链接

使用下面命令安装的包如何卸载

python setup.py install

手工删除的话

python setup.py install --record files.txt
cat files.txt | xargs rm -rf

异常

如何一行内处理多个异常

问题 链接

我知道可以这么做

try:
    # do something that may fail
except:
    # do this if ANYTHING goes wrong

也可以

try:
    # do something that may fail
except IDontLikeYourFaceException:
    # put on makeup or smile
except YouAreTooShortException:
    # stand on a ladder

如果想在一行里处理多个异常的话

try:
    # do something that may fail
except IDontLIkeYouException, YouAreBeingMeanException: #没生效
except Exception, e: #捕获了所有
    # say please

答案

# as在python2.6,python2.7中仍然可以使用
except (IDontLIkeYouException, YouAreBeingMeanException) as e:
    pass

如何flush Python的print输出

问题 链接 重复问题 链接

默认print输出到sys.stdout

import sys
sys.stdout.flush()

参考 http://docs.python.org/reference/simple_stmts.html#the-print-statement http://docs.python.org/library/sys.html http://docs.python.org/library/stdtypes.html#file-objects

如何获取一个函数的函数名字符串

问题 链接

my_function.__name__
>>> import time
>>> time.time.__name__
'time'

应该在学习Python3之前学习Python2,还是直接学习Python3

问题 链接

你可以从python2开始,2和3主要的语法格式和风格相同

3要替代2不是短时间内能完成的,将会是一个很长的过程,所以学习Python2并没有什么坏处

我建议你关注下2和3的不同之处 This slides gives you a quick introduction of the changes in Python 2 and 3

python中用==比较字符串,is有时候会返回错误判断

问题 链接

is是身份测试,==是相等测试

>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False'

is 等价于 id(a) == id(b)

如何截取一个字符串获得子串

问题 链接

>>> x = "Hello World!"
>>> x[2:]
'llo World!'
>>> x[:2]
'He'
>>> x[:-2]
'Hello Worl'
>>> x[-2:]
'd!'
>>> x[2:-2]
'llo Worl'

python将这类操作称为切片,可以作用于序列类型,不仅仅是字符串

用函数名字符串调用一个函数

问题 链接

假设模块foo有函数bar:

import foo
methodToCall = getattr(foo, 'bar')
result = methodToCall()

或者一行搞定

result = getattr(foo, 'bar')()

如何获取文件扩展名

问题 链接

使用os.path.splitext方法:

>>> import os
>>> fileName, fileExtension = os.path.splitext('/path/to/somefile.ext')
>>> fileName
'/path/to/somefile'
>>> fileExtension
'.ext'

如何获取list中包含某个元素所在的下标

问题 链接

>>> ["foo","bar","baz"].index('bar')
1

参照 文档

如何截掉空格(包括tab)

问题 链接

空白在字符串左右两边

s = "  \t a string example\t  "
s = s.strip()

空白在字符串右边

s = s.rstrip()

左边

s = s.lstrip()

另外你可以指定要截掉的字符作为参数

s = s.strip(' \t\n\r')

如何将一个十六进制字符串转为整数

问题 链接

>>> int("a", 16)
10
>>> int("0xa",16)
10

如何结束退出一个python脚本

问题 链接

import sys
sys.exit()

详细 文档

如何往文件中追加文本

问题 链接

with open("test.txt", "a") as myfile:
    myfile.write("appended text")

可以使用’a’或’a+b’ mode打开文件,见 文档

如何使用不同分隔符切分字符串

问题 链接

使用re.split 文档

>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.'])

或者匹配获取正确的 re.findall

import re
DATA = "Hey, you - what are you doing here!?"
print re.findall(r"[\w']+", DATA)
# Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

如何获取一个字符的ASCII码

问题 链接

>>> ord('a')
97
>>> chr(97)
'a'
>>> chr(ord('a') + 3)
'd'
>>>

另外对于unicode

>>> unichr(97)
u'a'
>>> unichr(1234)
u'\u04d2'

排序一个列表中的所有dict,根据dict内值

问题 链接

如何排序如下列表,根据name或age

[{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}]

简单的做法;

newlist = sorted(list_to_be_sorted, key=lambda k: k['name'])

高效的做法

from operator import itemgetter
newlist = sorted(list_to_be_sorted, key=itemgetter('name'))

读文件到列表中

问题 链接

f = open('filename')
lines = f.readlines()
f.close()
等价
with open(fname) as f:
    content = f.readlines()

文档

如何用http下载一个文件

问题 链接

直接使用urllib

import urllib
urllib.urlretrieve ("http://www.example.com/songs/mp3.mp3", "mp3.mp3")

使用urllib2,并提供一个进度条

import urllib2

url = "http://download.thinkbroadband.com/10MB.zip"

file_name = url.split('/')[-1]
u = urllib2.urlopen(url)
f = open(file_name, 'wb')
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
print "Downloading: %s Bytes: %s" % (file_name, file_size)

file_size_dl = 0
block_sz = 8192
while True:
    buffer = u.read(block_sz)
    if not buffer:
        break

    file_size_dl += len(buffer)
    f.write(buffer)
    status = r"%10d  [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
    status = status + chr(8)*(len(status)+1)
    print status,

f.close()

使用第三方requests

>>> import requests
>>>
>>> url = "http://download.thinkbroadband.com/10MB.zip"
>>> r = requests.get(url)
>>> print len(r.content)
10485760

在virtualenv中如何使用不同的python版本

问题 链接

在创建virtualenv实例时,使用-p选项

virtualenv -p /usr/bin/python2.6 <path/to/new/virtualenv/>

python中如何将一行长代码切成多行

问题 链接

例如:

e = 'a' + 'b' + 'c' + 'd'
变成
e = 'a' + 'b' +
    'c' + 'd'

括号中,可以直接换行

a = dostuff(blahblah1, blahblah2, blahblah3, blahblah4, blahblah5,
            blahblah6, blahblah7)

非括号你可以这么做

a = '1' + '2' + '3' + \
    '4' + '5'
或者
a = ('1' + '2' + '3' +
    '4' + '5')

可以查看下代码风格: style guide 推荐是后一种,但某些个别情况下,加入括号会导致错误

如何找到一个目录下所有.txt文件

问题 链接

使用glob

import glob
import os
os.chdir("/mydir")
for files in glob.glob("*.txt"):
    print files

使用os.listdir

import os
os.chdir("/mydir")
for files in os.listdir("."):
    if files.endswith(".txt"):
        print files

或者遍历目录

import os
for r,d,f in os.walk("/mydir"):
    for files in f:
        if files.endswith(".txt"):
            print os.path.join(r,files)

如何使用绝对路径import一个模块

问题 链接

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

如何在遍历一个list时删除某些玄素

问题 链接

使用列表解析

somelist = [x for x in somelist if determine(x)]

上面那个操作将产生一个全新的somelist对象,而失去了对原有somelist对象的引用

#在原有对象上进行修改
somelist[:] = [x for x in somelist if determine(x)]

使用itertools

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

如何强制使用浮点数除法

问题 链接

如何强制使除法结果c是浮点数

c = a / b

可以使用__future__

>>> from __future__ import division
>>> a = 4
>>> b = 6
>>> c = a / b
>>> c
0.66666666666666663

或者转换,如果除数或被除数是浮点数,那么结果也是浮点数

c = a / float(b)

如何映射两个列表成为一个字典

问题 链接

两个列表

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')

如何得到

dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}

使用zip

>>> keys = ['a', 'b', 'c']
>>> values = [1, 2, 3]
>>> dictionary = dict(zip(keys, values))
>>> print dictionary
{'a': 1, 'b': 2, 'c': 3}

找到当前目录及文件所在目录

问题 链接

查找当前目录使用os.getcwd()

查找某个文件的目录,使用, os.path

import os.path
os.path.realpath(__file__)

为何1 in [1,0] == True执行结果是False

问题 链接

有如下

>>> 1 in [1,0]             # This is expected
True
>>> 1 in [1,0] == True     # This is strange
False
>>> (1 in [1,0]) == True   # This is what I wanted it to be
True
>>> 1 in ([1,0] == True)   # But it's not just a precedence issue!
                           # It did not raise an exception on the second example.

Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
      1 in ([1,0] == True)
      TypeError: argument of type 'bool' is not iterable

这里python使用了比较运算符链

1 in [1,0] == True

将被转为

(1 in [1, 0]) and ([1, 0] == True)

很显然是false的

同样的

a < b < c

会被转为

(a < b) and (b < c) # b不会被解析两次

具体文档

Python中的switch替代语法

问题 链接

python中没有switch,有什么推荐的处理方法么

使用字典:

def f(x):
    return {
        'a': 1,
        'b': 2,
    }.get(x, 9)

Python Cookbook中的几种方式

Readable switch construction without lambdas or dictionaries

Exception-based Switch-Case

Using a Dictionary in place of a ‘switch’ statement

如何将字符串转换为datetime

问题 链接

可以查看下time模块的strptime方法,反向操作是strftime

from datetime import datetime
date_object = datetime.strptime('Jun 1 2005  1:33PM', '%b %d %Y %I:%M%p')

扩展文档

Python中有没有简单优雅的方式定义单例类

问题 链接

我不认为有必要,一个拥有函数的模块(不是类)可以作为很好的单例使用,它的所有变量被绑定到这个模块,无论如何都不能被重复实例化

如果你确实想用一个类来实现,在python中不能创建私有类或私有构造函数,所以你不能隔离多个实例而仅仅通过自己的API来访问属性

我还是认为将函数放入模块,并将其作为一个单例来使用是最好的办法

将一个字符串转为一个字典

问题 链接

如何将字符串转成字典,不适用eval

s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"

从python2.6开始,你可以使用内建模块 ast.literal_eval

>>> import ast
>>> ast.literal_eval("{'muffin' : 'lolz', 'foo' : 'kitty'}")
{'muffin': 'lolz', 'foo': 'kitty'}

这个做法比直接eval更安全 帮助文档

>>> help(ast.literal_eval)
Help on function literal_eval in module ast:

literal_eval(node_or_string)
    Safely evaluate an expression node or a string containing a Python
    expression.  The string or node provided may only consist of the following
    Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
    and None.

举例

>>> eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 208, in rmtree
    onerror(os.listdir, path, sys.exc_info())
File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 206, in rmtree
    names = os.listdir(path)
OSError: [Errno 2] No such file or directory: 'mongo'
>>> ast.literal_eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 68, in literal_eval
    return _convert(node_or_string)
File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 67, in _convert
    raise ValueError('malformed string')
ValueError: malformed string

Python如何检查一个对象是list或者tuple,但是不是一个字符串

问题 链接

原来的做法是

assert isinstance(lst, (list, tuple))

有没有更好的做法

我认为下面的方式是你需要的

assert not isinstance(lst, basestring)

原来的方式,你可能会漏过很多像列表,但并非list/tuple的

使用 ‘if x is not None’ 还是’if not x is None’

问题 链接

我总想着使用 ‘if x is not None’ 会更加简明

但是google的Python风格指南使用的却是 ‘if x is not None’

性能上没有什么区别,他们编译成相同的字节码

Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39)
>>> import dis
>>> def f(x):
...    return x is not None
...
>>> dis.dis(f)
2           0 LOAD_FAST                0 (x)
            3 LOAD_CONST               0 (None)
            6 COMPARE_OP               9 (is not)
            9 RETURN_VALUE
>>> def g(x):
...   return not x is None
...
>>> dis.dis(g)
2           0 LOAD_FAST                0 (x)
            3 LOAD_CONST               0 (None)
            6 COMPARE_OP               9 (is not)
            9 RETURN_VALUE

在风格上,我尽量避免 ’not x is y’ 这种形式,虽然编译器会认为和 ’not (x is y)‘一样,但是读代码的人或许会误解为 ‘(not x) is y’

如果写作 ‘x is not y’ 就不会有歧义

最佳实践

if x is not None:
    # Do something about x

如何获取一个文件的创建和修改时间

问题 链接

跨平台的获取文件创建及修改时间的方法

你有很多选择

使用os.path.getmtime或者os.path.getctime

import os.path, time
print "last modified: %s" % time.ctime(os.path.getmtime(file))
print "created: %s" % time.ctime(os.path.getctime(file))

或者os.stat

import os, time
(mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(file)
print "last modified: %s" % time.ctime(mtime)

注意,ctime()并非指*nix系统中文件创建时间,而是这个节点数据的最后修改时间

如何离开virtualenv

问题 链接

使用virtualenv时

me@mymachine:~$ workon env1
(env1)me@mymachine:~$ workon env2
(env2)me@mymachine:~$ workon env1
(env1)me@mymachine:~$

如何退出某个环境

$ deactivate

如何认为地抛出一个异常

问题 链接

pythonic

raise Exception("I know python!")

更多可参考 文档

在Python中如何展示二进制字面值

问题 链接

十六进制可以

>>> 0x12AF
4783
>>> 0x100
256

八进制可以

>>> 01267
695
>>> 0100
64

二进制如何表示?

Python 2.5 及更早版本: 可以表示为 int(‘01010101111’,2) 但没有字面量

Python 2.6 beta: 可以使用0b1100111 or 0B1100111 表示

Python 2.6 beta: 也可以使用 0o27 or 0O27 (第二字字符是字母 O)

Python 3.0 beta: 同2.6,但不支持027这种语法

Python中检查类型的权威方法

问题 链接

检查一个对象是否是给定类型或者对象是否继承于给定类型?

比如给定一个对象o,如何判断是不是一个str

检查是否是str

type(o) is str

检查是否是str或者str的子类

isinstance(o, str)

下面的方法在某些情况下有用

issubclass(type(o), str)
type(o) in ([str] + str.__subclasses__())

注意,你或许想要的是

isinstance(o, basestring)

因为unicode字符串可以满足判定(unicode 不是str的子类,但是str和unicode都是basestring的子类)

可选的,isinstance可以接收多个类型参数,只要满足其中一个即True

isinstance(o, (str, unicode))

如何获取Python的site-packages目录位置

问题 链接

参考 How to Install Django" documentation

可以在shell中执行

python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"

更好的可读性

from distutils.sysconfig import get_python_lib
print(get_python_lib())

Python中**和*的作用

问题 链接

*args和**kwargs允许函数拥有任意数量的参数,具体可以查看 more on defining functions

*args将函数所有参数转为序列

In [1]: def foo(*args):
...:     for a in args:
...:         print a
...:
...:

In [2]: foo(1)
1


In [4]: foo(1,2,3)
1
2
3

**kwargs 将函数所有关键字参数转为一个字典

In [5]: def bar(**kwargs):
...:     for a in kwargs:
...:         print a, kwargs[a]
...:
...:

In [6]: bar(name="one", age=27)
age 27
name one

两种用法可以组合使用

def foo(kind, *args, **kwargs):
    pass

*l的另一个用法是用于函数调用时的参数列表解包(unpack)

In [9]: def foo(bar, lee):
...:     print bar, lee
...:
...:

In [10]: l = [1,2]

In [11]: foo(*l)
1 2

在Python3.0中,可以将*l放在等号左边用于赋值 Extended Iterable Unpacking

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

字符串格式化 % vs format

问题 链接

Python2.6中引入string.format()方法,语法和原先%操作符的字符串格式化差异较大

在什么情况下使用哪种更好?

以下的输出是一致的,有什么区别

#!/usr/bin/python
sub1 = "python string!"
sub2 = "an arg"

a = "i am a %s"%sub1
b = "i am a {0}".format(sub1)

c = "with %(kwarg)s!"%{'kwarg':sub2}
d = "with {kwarg}!".format(kwarg=sub2)

print a
print b
print c
print d

.format 看起来更加强大,可以用在很多情况.

例如你可以在格式化时重用传入的参数,而你用%时无法做到这点

另一个比较讨厌的是,%只处理 一个变量或一个元组, 你或许会认为下面的语法是正确的

"hi there %s" % name

但当name恰好是(1,2,3)时,会抛出TypeError异常.为了保证总是正确的,你必须这么写

"hi there %s" % (name,)   # supply the single argument as a single-item tuple

这么写很丑陋, .format没有这些问题

什么时候不考虑使用.format

你对.format知之甚少
使用Python2.5

Python中什么项目结构更好

问题 链接

假设你要开发一个较大的客户端程序(非web端),如何组织项目目录和递归?

不要太在意这个.按你高兴的方式组织就行.Python项目很简单,所以没有那么多愚蠢的规则

/scripts or /bin  命令行脚本
/tests 测试
/lib C-语言包
/doc 文档
/apidoc api文档

并且顶层目录包含README和Config

难以抉择的是,是否使用/src树. /src,/lib,/bin在Python中没有明显的区别,和Java/c不同

因为顶层/src文件夹显得没有什么实际意义,你的顶层目录可以是程序顶层架构的目录

/foo
/bar
/baz

我建议将这些文件放入到"模块名"的目录中,这样,如果你在写一个应用叫做quux, /quux目录将包含所有这些东西

你可以在PYTHONPATH中加入 /path/to/quux/foo,这样你可以QUUX.foo中重用模块

另一个回答

Project/
|-- bin/
|   |-- project
|
|-- project/
|   |-- test/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py
|
|-- setup.py
|-- README

argparse可选位置参数

问题 链接

脚本运行 usage: installer.py dir [-h] [-v]

dir是一个位置参数,定义如下

parser.add_argument('dir', default=os.getcwd())

我想让dir变为可选,如果未设置,使用os.getcwd()

不幸的是,当我不指定dir时,得到错误 “Error: Too few arguments”

尝试使用 nargs=’?’

parser.add_argument('dir', nargs='?', default=os.getcwd())

例子

>>> import os, argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-v', action='store_true')
_StoreTrueAction(option_strings=['-v'], dest='v', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('dir', nargs='?', default=os.getcwd())
_StoreAction(option_strings=[], dest='dir', nargs='?', const=None, default='/home/vinay', type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args('somedir -v'.split())
Namespace(dir='somedir', v=True)
>>> parser.parse_args('-v'.split())
Namespace(dir='/home/vinay', v=True)
>>> parser.parse_args(''.split())
Namespace(dir='/home/vinay', v=False)
>>> parser.parse_args(['somedir'])
Namespace(dir='somedir', v=False)
>>> parser.parse_args('somedir -h -v'.split())
usage: [-h] [-v] [dir]

positional arguments:
dir

optional arguments:
-h, --help  show this help message and exit
-v

Python中 new 和 __init__的用法

问题 链接

我很疑惑,为何__init__总是在__new__之后调用

如下

class A(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in A._dict:
            print "EXISTS"
            return A._dict['key']
        else:
            print "NEW"
            return super(A, cls).__new__(cls)

    def __init__(self):
        print "INIT"
        A._dict['key'] = self
        print ""

a1 = A()
a2 = A()
a3 = A()

输出

NEW
INIT

EXISTS
INIT

EXISTS
INIT

有木有人可以解释一下

来自 链接

使用__new__,当你需要控制一个实例的生成

使用__init__,当你需要控制一个实例的初始化

__new__是实例创建的第一步.最先被调用,并且负责返回类的一个新实例.

相反的,__init__不返回任何东西,只是负责在实例创建后进行初始化

通常情况下,你不必重写__new__除非你写一个子类继承不可变类型,例如str,int,unicode或tuple

你必须了解到,你尝试去做的用Factory可以很好地解决,并且是最好的解决方式.使用__new__不是一个简洁的处理方式,一个factory例子

Python ‘self’ 解释

问题 链接

self关键字的作用是什么? 我理解他用户在创建class时具体化实例,但我无法理解为何需要给每个方法加入self作为参数.

举例,在ruby中,我这么做:

class myClass
    def myFunc(name)
        @name = name
    end
end

我可以很好地理解,非常简单.但是在Python中,我需要去加入self:

class myClass:
    def myFunc(self, name):
        self.name = name

有谁能解释下么?

使用self关键字的原因是,Python没有@语法用于引用实例属性.Python决定用一种方式声明方法:实例对象自动传递给属于它的方法,但不是接收自动化:方法的第一个参数是调用这个方法的实例对象本身.这使得方法整个同函数一致,并且由你自己决定真实的名(虽然self是约定,但当你使用其他名的时候,通常人们并不乐意接受).self对于代码不是特殊的,只是另一个对象.

Python本来可以做一些用来区分真实的名字和属性的区别 —— 像Ruby有的特殊语法,或者像C++/Java的命令声明,或者其他可能的的语法 —— 但是Python没有这么做.Python致力于使事情变得明确简单,让事情是其本身,虽然并不是全部地方都这么做,但是实例属性石这么做的!这就是为什么给一个实例属性赋值时需要知道是给哪个实例赋值,并且,这就是为什么需要self

举例

class Vector(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def length(self):
        return math.sqrt(self.x ** 2 + self.y ** 2)

等价于

def length_global(vector):
    return math.sqrt(vector.x ** 2 + vector.y ** 2)

另外

v_instance.length()
转为
Vector.length(v_instance)

为什么Python的’private’方法并不是真正的私有方法

问题 链接

Python允许我们创建’private’ 函数:变量以两个下划线开头,像这样: __myPrivateMethod(). 但是,如何解释:

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()
>>> obj.myPublicMethod()
public method
>>> obj.__myPrivateMethod()
Traceback (most recent call last):
File "", line 1, in
AttributeError: MyClass instance has no attribute '__myPrivateMethod'
>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
>>> obj._MyClass__myPrivateMethod()
this is private!!

dir(obj) 和 obj._MyClass__myPrivateMethod()

回答

‘private’只是用作,确保子类不会意外覆写父类的私有方法和属性.不是为了保护外部意外访问而设计的!

例如:

>>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

当然,这对于两个同名的类没有作用

另外,可以查看diveintopython的解释 入口

Python中类方法的作用是什么

问题 链接

我现在意识到,我不需要像我在使用java的static方法那样使用类方法,但是我不确定什么时候使用

谁能通过一个好的例子解释下Python中的类方法,至少有人能告诉我什么时候确实需要使用类方法

类方法用在:当你需要使用不属于任何明确实例的方法,但同时必须涉及类.有趣的是,你可以在子类中覆写,这在Java的static方法和Python的模块级别函数中是不可能做到的

如果你有一个MyClass, 并且一个模块级别函数操作MyClass(工厂,依赖注入桩等等), 声明一个类方法.然后这个类方法可以在子类中调用

如何删除一个list中重复的值同时保证原有顺序

问题 链接

我是这么做的额

def uniq(input):
output = []
for x in input:
    if x not in output:
    output.append(x)
return output

有什么更好的方法?

你可以在这里找到一些可用的方法 入口

最快的一个

def f7(seq):
    seen = set()
    seen_add = seen.add
    return [ x for x in seq if x not in seen and not seen_add(x)]

如果你需要在同一个数据集中多次是哦那个这个方法,或许你可以使用ordered set处理 http://code.activestate.com/recipes/528878/

插入,删除和归属判断复杂度都是O(1)

有什么方法可以获取系统当前用户名么?

问题 链接

至少在Linux和Windows下都可用.就像 os.getuid

>>> os.getuid()
42
>>> os.getusername()
'slartibartfast'

可以看看 getpass 模块

>>> import getpass
>>> getpass.getuser()
'kostya'

可用: Unix, Windows

Python assert最佳实践

问题 链接

有没有代码实例使用assert作为独立代码,而不是仅用来debug

assert x >= 0, 'x is less than zero'

类似
if x < 0:
    raise Exception, 'x is less than zero'

有什么方法,可以设定一个规则就像 if x \< 0 抛出错误但是不是通过try/except/finally检查的

搞晕了:

原文 Also, is there any way to set a business rule like if x \< 0 raise error that is always checked without the try/except/finally so, if at anytime throughout the code x is less than 0 an error is raised, like if you set assert x < 0 at the start of a function, anywhere within the function where x becomes less then 0 an exception is raised?

回答

Assert仅用在,测试那些从不发生的情况!目的是让程序尽早失败

Exception用在,那些可以明确知道会发生的错误,并且建议总是创建自己的异常类

例如,你写一个函数从配置文件中读取配置放入字典,文件格式不正确抛出一个ConfigurationSyntaxError,同时你可以assert返回值非None

在你的例子中,如果x是通过用户接口或外部传递设置的,最好使用exception

如果x仅是同一个程序的内部代码,使用assert

在非创建全局变量的地方使用全局变量

问题 链接

如果我在一个函数中创建了全局变量,如何在另一个函数中使用?

回答:

你可以在给全局变量赋值的函数中声明 global

globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print globvar     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1

我猜想这么做的原因是,全局变量很危险,Python想要确保你真的知道你要对一个全局的变量进行操作

如果你想知道如何在模块间使用全局变量,查看其他回答

如何在单一表达式中合并两个Python字典

问题 链接

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print z
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

我想要最终合并结果在z中,不是x,我要怎么做?

回答

这种情况下,可以使用

z = dict(x.items() + y.items())

这个表达式将会实现你想要的,最终结果z,并且相同key的值,将会是y中key对应的值

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

如果在Python3中,会变得有些复杂

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}

如何使用 pip 更新所有包

问题 链接

如何使用pip更新python的所有包

没有内置的标志可以实现

但是你可以这么做

pip freeze --local | grep -v '^\-e' | cut -d = -f 1  | xargs pip install -U

Python中声明exception的方法

问题 链接

在python2.6中定义异常得到警告

>>> class MyError(Exception):
...     def __init__(self, message):
...         self.message = message
...
>>> MyError("foo")
_sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6

问题很长,大意如标题

回答

或许我理解错了,但是为什么不这样做

class MyException(Exception):
    pass

如果要重写什么,例如传递额外参数,可以这么做

class ValidationError(Exception):
    def __init__(self, message, Errors):

        # Call the base class constructor with the parameters it needs
        Exception.__init__(self, message)

        # Now for your custom code...
        self.Errors = Errors

你可以通过第二个参数传递error 字典, 之后通过e.Errors获取

在Python中使用Counter错误

问题 链接

当使用Counter时,出现异常

AttributeError: 'module' object has no attribute 'Counter'

from collections import Counter
ImportError: cannot import name Counter

原因:

版本问题,Counter在 python2.7中才被加入到这个模块,你可能使用了Python2.6或更老的版本

可以看下 文档

如果要在 Python2.6或2.5版本使用,可以看 这里

如何删除Python easy_install安装的包

问题 链接

pip, setuptools/easy_install的另一种选择,提供uninstall命令

首先,移除依赖

$ easy_install -m [PACKAGE]

然后,手动删除egg文件

$ rm -rf .../python2.X/site-packages/[PACKAGE].egg

在Python中如何解析xml

问题 链接

<foo>
<bar>
    <type foobar="1"/>
    <type foobar="2"/>
</bar>
</foo>

如何解析获取xml文件中内容

我建议使用 ElementTree (有其他可用的实现,例如 lxml,他们只是更快, ElementTree提供更简单的编程api)

在使用XML建立Element实例之后,例如使用 XML 函数

for atype in e.findall('type')
    print(atype.get('foobar'))

如何将一个Python time.struct_time对象转换为一个datetime对象

问题 链接

使用 time.mktime() 将time元组(本地时间)转成秒, 然后使用 datetime.fromtimestamp() 转成datetime对象

from time import mktime
from datetime import datetime

dt = datetime.fromtimestamp(mktime(struct))