├── contents ├── qa-tuple.md ├── qa-datetime.md ├── qa-exception.md ├── qa-pip-easy_install.md ├── qa-dict.md ├── qa-modules.md ├── qa-built-in.md ├── qa-control-flow.md ├── qa-file.md ├── qa-string.md ├── qa-list.md ├── qa-others.md ├── qa-func.md ├── qa-std-modules.md ├── qa-math.md └── qa-oop.md └── README.md /contents/qa-tuple.md: -------------------------------------------------------------------------------- 1 | ### Python中的命名元组是什么? 2 | 3 | 问题[链接](http://stackoverflow.com/questions/2970608/what-are-named-tuples-in-python) 4 | 5 | 命名元组基本上是一种易创建,轻量的对象类型。命名元组实例像值引用一样被对象引用或者使用基础的元组语法。他们可以像`struct`或者其他常用的记录类型一样被使用,除了他们是不可变的。他们在Python 2.6和Python 3.0中被加入。尽管有一个[在Python2.4中实现的秘诀](http://code.activestate.com/recipes/500261/) 6 | 7 | 举个例子,通常我们要顶一个点,用元组表示`(x, y)`。用代码写出来像下面这样: 8 | 9 | pt1 = (1.0, 5.0) 10 | pt2 = (2.5, 1.5) 11 | 12 | from math import sqrt 13 | line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2) 14 | 15 | 使用命名元组可以更可读: 16 | 17 | from collections import namedtuple 18 | Point = namedtuple('Point', 'x y') 19 | pt1 = Point(1.0, 5.0) 20 | pt2 = Point(2.5, 1.5) 21 | 22 | from math import sqrt 23 | line_length = sqrt((pt1.x-pt2.x)**2 + (pt1.y-pt2.y)**2) 24 | 25 | 然而,命名元组仍然向下兼容普通的元组,所以下面的代码仍然有效: 26 | 27 | Point = namedtuple('Point', 'x y') 28 | pt1 = Point(1.0, 5.0) 29 | pt2 = Point(2.5, 1.5) 30 | 31 | from math import sqrt 32 | # use index referencing 33 | line_length = sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2) 34 | # use tuple unpacking 35 | x1, y1 = pt1 36 | 37 | 因此,如果你认为对象标记可以让你的代码更Pythonic、更可读,那么请将所有的元组替换为命名元组。我个人已经开始使用命名元组去替代非常简单的值类型,尤其是那些要作为参数传入函数的东西。它让函数不用知道元组的包装内容,更加具有可读性。 38 | 39 | 长远点说,你还可以用命名元组替代不含方法的普通不可变类。你还可以把你的命名元组类型作为基类: 40 | 41 | class Point(namedtuple('Point', 'x y')): 42 | [...] 43 | 44 | 当然,作为元组,命名元组中的属性仍然是不可变的: 45 | 46 | >>> Point = namedtuple('Point', 'x y') 47 | >>> pt1 = Point(1.0, 5.0) 48 | >>> pt1.x = 2.0 49 | AttributeError: can't set attribute 50 | 51 | 如果你想改变这些值,你需要另一个类型。有一个方便的方法[mutable recordtypes](http://code.activestate.com/recipes/576555/),它允许你把修改属性为新的值。 52 | 53 | >>> from rcdtype import * 54 | >>> Point = recordtype('Point', 'x y') 55 | >>> pt1 = Point(1.0, 5.0) 56 | >>> pt1 = Point(1.0, 5.0) 57 | >>> pt1.x = 2.0 58 | >>> print(pt1[0]) 59 | 2.0 60 | 61 | 我仍然不知道有任何”命名列表“的结构,可以让你添加新的区块。这种情况下你可能只是需要用一个字典。命名元组可以转化成字典,用`pt1._asdict()`可以返回`{'x': 1.0, 'y': 5.0}`而且升级为可以使用所有字典常用的函数。 62 | 63 | 已经标记过的,你应该[查看文档](https://docs.python.org/3/library/collections.html#collections.namedtuple)来获取更多搭建这些例子的信息。 -------------------------------------------------------------------------------- /contents/qa-datetime.md: -------------------------------------------------------------------------------- 1 | 2 | ### 如何将一个Python time.struct_time对象转换为一个datetime对象 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/1697815/how-do-you-convert-a-python-time-struct-time-object-into-a-datetime-object) 5 | 6 | 使用 [time.mktime()]() 将time元组(本地时间)转成秒, 然后使用 datetime.fromtimestamp() 转成datetime对象 7 | 8 | from time import mktime 9 | from datetime import datetime 10 | 11 | dt = datetime.fromtimestamp(mktime(struct)) 12 | 13 | ### python中如何获取当前时间 14 | 15 | 问题 [链接](http://stackoverflow.com/questions/415511/how-to-get-current-time-in-python) 16 | 17 | 时间日期 18 | 19 | >>> import datetime 20 | >>> datetime.datetime.now() 21 | datetime(2009, 1, 6, 15, 8, 24, 78915) 22 | 23 | 如果仅获取时间 24 | 25 | >>> datetime.datetime.time(datetime.datetime.now()) 26 | datetime.time(15, 8, 24, 78915)) 27 | #等价 28 | >>> datetime.datetime.now().time() 29 | 30 | 可以从文档中获取更多 [文档](http://docs.python.org/2/library/datetime.html) 31 | 32 | 如果想避免额外的datetime. 33 | 34 | >>> from datetime import datetime 35 | 36 | ### Python - time.clock() vs. time.time() - 更精确? 37 | 38 | 问题 [链接](http://stackoverflow.com/questions/85451/python-time-clock-vs-time-time-accuracy) 39 | 40 | 哪一个更适合于计时? 哪个更精确, 41 | 42 | 例如 43 | 44 | start = time.clock() 45 | ... do something 46 | elapsed = (time.clock() - start) 47 | 48 | and 49 | 50 | start = time.time() 51 | ... do something 52 | elapsed = (time.time() - start) 53 | 54 | 回答 55 | 56 | 区别 57 | 58 | clock() -> floating point number 59 | 60 | Return the CPU time or real time since the start of the process or since 61 | the first call to clock(). 62 | This has as much precision as the system records. 63 | 64 | time() -> floating point number 65 | 66 | Return the current time in seconds since the Epoch. 67 | Fractions of a second may be present if the system clock provides them. 68 | 69 | 根据 [time module doc](http://docs.python.org/lib/module-time.html) 70 | 71 | clock() 72 | 73 | On Unix, return the current processor time as a floating point number expressed in seconds. The precision, and in fact the very definition of the meaning of ``processor time'', depends on that of the C function of the same name, 74 | 75 | but in any case, this is the function to use for benchmarking Python or timing algorithms. 76 | 77 | 简而言之, time.clock()更精确些, 但是如果涉及cpu外的硬件时间统计(e.g. gpu), 只能使用time.time() 78 | 79 | 另外基于性能的评估, 可以去看下timeit模块 80 | 81 | ### python和javascript中josn的datetime 82 | 83 | 问题 [链接](JSON datetime between Python and JavaScript) 84 | 85 | 怎样从python->javascript传递json的datetime? 86 | 87 | 可以`json.dumps`中加入`default`参数 88 | 89 | >>> dthandler = lambda obj: ( 90 | ... obj.isoformat() 91 | ... if isinstance(obj, datetime.datetime) 92 | ... or isinstance(obj, datetime.date) 93 | ... else None) 94 | >>> json.dumps(datetime.datetime.now(), default=dthandler) 95 | '"2010-04-20T20:08:21.634121"' 96 | 97 | 一个更好理解的handler 98 | 99 | ef handler(obj): 100 | if hasattr(obj, 'isoformat'): 101 | return obj.isoformat() 102 | elif isinstance(obj, ...): 103 | return ... 104 | else: 105 | raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(obj), repr(obj)) 106 | 107 | 但是上面这种做法, 对于json中包含其他的类型, 会返回None 108 | 109 | 110 | import json 111 | import datetime 112 | 113 | class DateTimeJSONEncoder(json.JSONEncoder): 114 | def default(self, obj): 115 | if isinstance(obj, datetime.datetime): 116 | return obj.isoformat() 117 | else: 118 | return super(DateTimeJSONEncoder, self).default(obj) 119 | 120 | >>> DateTimeJSONEncoder().encode([datetime.datetime.now()]) 121 | '["2010-06-15T14:42:28"]' 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /contents/qa-exception.md: -------------------------------------------------------------------------------- 1 | 2 | ### Python中声明exception的方法 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/1319615/proper-way-to-declare-custom-exceptions-in-modern-python) 5 | 6 | 在python2.6中定义异常得到警告 7 | 8 | >>> class MyError(Exception): 9 | ... def __init__(self, message): 10 | ... self.message = message 11 | ... 12 | >>> MyError("foo") 13 | _sandbox.py:3: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6 14 | 15 | 问题很长,大意如标题 16 | 17 | 回答 18 | 19 | 或许我理解错了,但是为什么不这样做 20 | 21 | class MyException(Exception): 22 | pass 23 | 如果要重写什么,例如传递额外参数,可以这么做 24 | 25 | class ValidationError(Exception): 26 | def __init__(self, message, Errors): 27 | 28 | # Call the base class constructor with the parameters it needs 29 | Exception.__init__(self, message) 30 | 31 | # Now for your custom code... 32 | self.Errors = Errors 33 | 34 | 你可以通过第二个参数传递error 字典, 之后通过e.Errors获取 35 | 36 | ### 如何人为地抛出一个异常 37 | 38 | 问题 [链接](http://stackoverflow.com/questions/2052390/how-do-i-manually-throw-raise-an-exception-in-python) 39 | 40 | pythonic 41 | 42 | raise Exception("I know python!") 43 | 44 | 更多可参考 [文档](http://docs.python.org/2/reference/simple_stmts.html#the-raise-statement) 45 | 46 | ### 如何一行内处理多个异常 47 | 48 | 问题 [链接](http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block) 49 | 50 | 我知道可以这么做 51 | 52 | try: 53 | # do something that may fail 54 | except: 55 | # do this if ANYTHING goes wrong 56 | 也可以 57 | 58 | try: 59 | # do something that may fail 60 | except IDontLikeYourFaceException: 61 | # put on makeup or smile 62 | except YouAreTooShortException: 63 | # stand on a ladder 64 | 65 | 如果想在一行里处理多个异常的话 66 | 67 | try: 68 | # do something that may fail 69 | except IDontLIkeYouException, YouAreBeingMeanException: #没生效 70 | except Exception, e: #捕获了所有 71 | # say please 72 | 答案 73 | 74 | # as在python2.6,python2.7中仍然可以使用 75 | except (IDontLIkeYouException, YouAreBeingMeanException) as e: 76 | pass 77 | 78 | ### Python assert最佳实践 79 | 80 | 问题 [链接](http://stackoverflow.com/questions/944592/best-practice-for-python-assert) 81 | 82 | 有没有代码实例使用assert作为独立代码,而不是仅用来debug 83 | 84 | assert x >= 0, 'x is less than zero' 85 | 86 | 类似 87 | if x < 0: 88 | raise Exception, 'x is less than zero' 89 | 90 | 有什么方法,可以设定一个规则就像 if x \< 0 抛出错误但是不是通过try/except/finally检查的 91 | 92 | 搞晕了: 93 | 94 | 原文 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? 95 | 96 | 回答1 97 | 98 | Assert仅用在,测试那些从不发生的情况!目的是让程序尽早失败 99 | 100 | Exception用在,那些可以明确知道会发生的错误,并且建议总是创建自己的异常类 101 | 102 | 103 | 例如,你写一个函数从配置文件中读取配置放入字典,文件格式不正确抛出一个ConfigurationSyntaxError,同时你可以assert返回值非None 104 | 105 | 在你的例子中,如果x是通过用户接口或外部传递设置的,最好使用exception 106 | 107 | 如果x仅是同一个程序的内部代码,使用assert 108 | 109 | 回答2 110 | 111 | 这个函数是为了能够当x小于0的时候,原子性的抛出一个异常。你可以使用[class descriptors](https://docs.python.org/2/reference/datamodel.html#implementing-descriptors)有一个例子: 112 | 113 | class ZeroException(Exception): 114 | pass 115 | 116 | class variable(object): 117 | def __init__(self, value=0): 118 | self.__x = value 119 | 120 | def __set__(self, obj, value): 121 | if value < 0: 122 | raise ZeroException('x is less than zero') 123 | 124 | self.__x = value 125 | 126 | def __get__(self, obj, objType): 127 | return self.__x 128 | 129 | class MyClass(object): 130 | x = variable() 131 | 132 | >>> m = MyClass() 133 | >>> m.x = 10 134 | >>> m.x -= 20 135 | Traceback (most recent call last): 136 | File "", line 1, in 137 | File "my.py", line 7, in __set__ 138 | raise ZeroException('x is less than zero') 139 | ZeroException: x is less than zero 140 | 141 | ### 如何打印到stderr 142 | 143 | 问题 [链接](http://stackoverflow.com/questions/5574702/how-to-print-to-stderr-in-python) 144 | 145 | 经常这么干 146 | 147 | import sys 148 | sys.stderr.write('spam\n') 149 | 150 | print >> sys.stderr, 'spam' 151 | 152 | from __future__ import print_function 153 | print('spam', file=sys.stderr) 154 | 155 | 但是不够pythonic, 有没有更好的方法? 156 | 157 | 回答 158 | 159 | 我发现这种方式是最短/灵活/可扩展/可读的做法 160 | 161 | from __future__ import print_function 162 | 163 | def warning(*objs): 164 | print("WARNING: ", *objs, file=sys.stderr) 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /contents/qa-pip-easy_install.md: -------------------------------------------------------------------------------- 1 | 2 | ### 如何使用 pip 更新所有包 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/2720014/upgrading-all-packages-with-pip) 5 | 6 | 如何使用pip更新python的所有包 7 | 8 | 没有内置的标志可以实现 9 | 10 | 但是你可以这么做 11 | 12 | pip freeze --local | grep -v '^\-e' | cut -d = -f 1 | xargs pip install -U 13 | 14 | ### 如何删除Python easy_install安装的包 15 | 16 | 问题 [链接](http://stackoverflow.com/questions/1231688/how-do-i-remove-packages-installed-with-pythons-easy-install) 17 | 18 | [pip](https://pypi.python.org/pypi/pip/), setuptools/easy_install的另一种选择,提供uninstall命令 19 | 20 | 首先,移除依赖 21 | 22 | $ easy_install -m [PACKAGE] 23 | 24 | 然后,手动删除egg文件 25 | 26 | $ rm -rf .../python2.X/site-packages/[PACKAGE].egg 27 | 28 | ### 如何获取Python的site-packages目录位置 29 | 30 | 问题 [链接](http://stackoverflow.com/questions/122327/how-do-i-find-the-location-of-my-python-site-packages-directory) 31 | 32 | 参考 [How to Install Django" documentation](http://docs.djangoproject.com/en/dev/topics/install/#remove-any-old-versions-of-django) 33 | 34 | 可以在shell中执行 35 | 36 | python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())" 37 | 38 | 更好的可读性 39 | 40 | from distutils.sysconfig import get_python_lib 41 | print(get_python_lib()) 42 | 43 | ### setup.py安装后如何卸载 44 | 45 | 问题 [链接](http://stackoverflow.com/questions/1550226/python-setup-py-uninstall) 46 | 47 | 48 | 使用下面命令安装的包如何卸载 49 | 50 | python setup.py install 51 | 52 | 手工删除的话 53 | 54 | python setup.py install --record files.txt 55 | cat files.txt | xargs rm -rf 56 | 57 | ### 如何获取安装的python模块列表 58 | 59 | 问题 [链接](http://stackoverflow.com/questions/739993/get-a-list-of-installed-python-modules) 60 | 61 | >>> help('modules') 62 | 63 | ### 为什么要使用pip而不是easy_install 64 | 65 | 问题 [链接](http://stackoverflow.com/questions/3220404/why-use-pip-over-easy-install) 66 | 67 | 有一条推文 68 | 69 | Don't use easy_install, unless you like stabbing yourself in the face. Use pip. 70 | 71 | Pip简介 72 | 73 | All packages are downloaded before installation. Partially-completed installation doesn’t occur as a result. 74 | Care is taken to present useful output on the console. 75 | The reasons for actions are kept track of. For instance, if a package is being installed, pip keeps track of why that package was required. 76 | Error messages should be useful. 77 | The code is relatively concise and cohesive, making it easier to use programmatically. 78 | Packages don’t have to be installed as egg archives, they can be installed flat (while keeping the egg metadata). 79 | Native support for other version control systems (Git, Mercurial and Bazaar) 80 | Uninstallation of packages. 81 | Simple to define fixed sets of requirements and reliably reproduce a set of packages. 82 | 83 | 其他原因: 84 | 85 | Another—as of yet unmentioned—reason for favoring pip is because it is the new hotness and will continue to be used in the future. 86 | 87 | pip提供unstall命令 88 | 如果中途安装失败,pip will leave you in a clean state. 89 | 90 | ### 如何在正确使用pip,virtualenv,distribute构建Python环境 91 | 92 | 问题[链接](http://stackoverflow.com/questions/4324558/whats-the-proper-way-to-install-pip-virtualenv-and-distribute-for-python) 93 | 94 | 你可以不向Python本身添加任何东西。 95 | 96 | 你不需要sudo或者任何权限。 97 | 98 | 你不需要编辑任何文件。 99 | 100 | 在自引导的虚拟环境里安装virtualenv。通过这个虚拟环境,它可以创建更多。自从virtualenv搭载了pip和distribute,你就可以从其中一个获得所有东西。 101 | 102 | 1. 下载virtualenv: 103 | http://pypi.python.org/pypi/virtualenv 104 | https://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.9.tar.gz(实际上最好下载最新的版本!) 105 | 2. 解压源码 106 | 3. 用解压好的源文件创建一个干净的虚拟环境。选择正确的命令,虚拟环境会自带pip和distribute。 107 | 4. 在virtualenv中安装virtualenv 108 | 5. 使用第一个自建的环境去创建更多! 109 | 110 | 有一个bash的简单例子: 111 | 112 | # Select current version of virtualenv: 113 | VERSION=1.6.4 114 | # Name your first "bootstrap" environment: 115 | INITIAL_ENV=py-env0 116 | # Options for your first environment: 117 | ENV_OPTS='--no-site-packages --distribute' 118 | # Set to whatever python interpreter you want for your first environment: 119 | PYTHON=$(which python) 120 | URL_BASE=http://pypi.python.org/packages/source/v/virtualenv 121 | 122 | # --- Real work starts here --- 123 | curl -O $URL_BASE/virtualenv-$VERSION.tar.gz 124 | tar xzf virtualenv-$VERSION.tar.gz 125 | # Create the first "bootstrap" environment. 126 | $PYTHON virtualenv-$VERSION/virtualenv.py $ENV_OPTS $INITIAL_ENV 127 | # Don't need this anymore. 128 | rm -rf virtualenv-$VERSION 129 | # Install virtualenv into the environment. 130 | $INITIAL_ENV/bin/pip install virtualenv-$VERSION.tar.gz 131 | 132 | 现在你可以用你的自引导环境去创建更多: 133 | 134 | # Create a second environment from the first: 135 | $INITIAL_ENV/bin/virtualenv --no-site-packages --distribute py-env1 136 | # Create more: 137 | $INITIAL_ENV/bin/virtualenv py-env2 138 | 139 | 疯狂吧! 140 | 141 | 更新 142 | 143 | `—no-site-packages` and`—distribute`现在是默认的了(运行`virtualenv -h`)所以你可以通过`python virtualenv.py bootstrap`或者`python3 virtualenv.py bootstrap`安装你的引导。 144 | -------------------------------------------------------------------------------- /contents/qa-dict.md: -------------------------------------------------------------------------------- 1 | 2 | ### 使用列表解析创建一个字典 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/1747817/python-create-a-dictionary-with-list-comprehension) 5 | 6 | python 2.6 7 | 8 | d = dict((key, value) for (key, value) in sequence) 9 | 10 | python 2.7+ or 3, 使用 [字典解析语法](http://www.python.org/dev/peps/pep-0274/) 11 | 12 | d = {key: value for (key, value) in sequence} 13 | 14 | ### 使用"in"还是"has_key()" 15 | 16 | 问题 [链接](http://stackoverflow.com/questions/1323410/has-key-or-in) 17 | 18 | d = {'a': 1, 'b': 2} 19 | 'a' in d 20 | True 21 | or: 22 | 23 | d = {'a': 1, 'b': 2} 24 | d.has_key('a') 25 | True 26 | 27 | 哪种更好 28 | 29 | in更pythonic, 另外 has_key()在Python3.x中已经被移除 30 | 31 | ### 字典默认值 32 | 33 | 问题 [链接](http://stackoverflow.com/questions/1602934/check-if-a-given-key-already-exists-in-a-dictionary) 34 | 35 | 和问题有点偏 36 | 37 | #获取时,如不存在,得到默认值 38 | d.get(key, 0) 39 | #设置时,若key不存在,设置默认值,已存在,返回已存在value 40 | d.setdefault(key, []).append(new_element) 41 | #初始即默认值 42 | from collections import defaultdict 43 | d = defaultdict(lambda: 0) 44 | #or d = defaultdict(int) 45 | 46 | 47 | ### 如何给字典添加一个值 48 | 49 | 问题 [链接](http://stackoverflow.com/questions/1024847/add-to-a-dictionary-in-python) 50 | 51 | 52 | #### Making a dictionary #### 53 | data = {} 54 | # OR # 55 | data = dict() 56 | 57 | #### Initially adding values #### 58 | data = {'a':1,'b':2,'c':3} 59 | # OR # 60 | data = dict(a=1, b=2, c=3) 61 | 62 | #### Inserting/Updating value #### 63 | data['a']=1 # updates if 'a' exists, else adds 'a' 64 | # OR # 65 | data.update({'a':1}) 66 | # OR # 67 | data.update(dict(a=1)) 68 | 69 | #### Merging 2 dictionaries #### 70 | data.update(data2) # Where data2 is also a dict. 71 | 72 | ### 如何将字段转换成一个object,然后使用对象-属性的方式读取 73 | 74 | 问题 [链接](http://stackoverflow.com/questions/1305532/convert-python-dict-to-object) 75 | 76 | 有dict 77 | 78 | >>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]} 79 | 80 | 想用这种方式访问 81 | 82 | >>> x = dict2obj(d) 83 | >>> x.a 84 | 1 85 | >>> x.b.c 86 | 2 87 | >>> x.d[1].foo 88 | bar 89 | 90 | 使用namedtuple 91 | 92 | >>> from collections import namedtuple 93 | >>> MyStruct = namedtuple('MyStruct', 'a b d') 94 | >>> s = MyStruct(a=1, b={'c': 2}, d=['hi']) 95 | >>> s 96 | MyStruct(a=1, b={'c': 2}, d=['hi']) 97 | >>> s.a 98 | 1 99 | >>> s.b 100 | {'c': 2} 101 | >>> s.c 102 | >>> s.d 103 | ['hi'] 104 | 105 | 使用类 106 | 107 | class Struct: 108 | def __init__(self, **entries): 109 | self.__dict__.update(entries) 110 | 111 | >>> args = {'a': 1, 'b': 2} 112 | >>> s = Struct(**args) 113 | >>> s 114 | <__main__.Struct instance at 0x01D6A738> 115 | >>> s.a 116 | 1 117 | >>> s.b 118 | 2 119 | 120 | ### 如何在单一表达式中合并两个Python字典 121 | 122 | 问题 [链接](http://stackoverflow.com/questions/38987/how-can-i-merge-union-two-python-dictionaries-in-a-single-expression) 123 | 124 | >>> x = {'a':1, 'b': 2} 125 | >>> y = {'b':10, 'c': 11} 126 | >>> z = x.update(y) 127 | >>> print z 128 | None 129 | >>> x 130 | {'a': 1, 'b': 10, 'c': 11} 131 | 132 | 我想要最终合并结果在z中,不是x,我要怎么做? 133 | 134 | 回答 135 | 136 | 这种情况下,可以使用 137 | 138 | z = dict(x.items() + y.items()) 139 | 140 | 这个表达式将会实现你想要的,最终结果z,并且相同key的值,将会是y中key对应的值 141 | 142 | >>> x = {'a':1, 'b': 2} 143 | >>> y = {'b':10, 'c': 11} 144 | >>> z = dict(x.items() + y.items()) 145 | >>> z 146 | {'a': 1, 'c': 11, 'b': 10} 147 | 148 | 如果在Python3中,会变得有些复杂 149 | 150 | >>> z = dict(list(x.items()) + list(y.items())) 151 | >>> z 152 | {'a': 1, 'c': 11, 'b': 10} 153 | 154 | ### 如何映射两个列表成为一个字典 155 | 156 | 问题 [链接](http://stackoverflow.com/questions/209840/map-two-lists-into-a-dictionary-in-python) 157 | 158 | 两个列表 159 | 160 | keys = ('name', 'age', 'food') 161 | values = ('Monty', 42, 'spam') 162 | 如何得到 163 | 164 | dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'} 165 | 166 | 使用zip 167 | 168 | >>> keys = ['a', 'b', 'c'] 169 | >>> values = [1, 2, 3] 170 | >>> dictionary = dict(zip(keys, values)) 171 | >>> print dictionary 172 | {'a': 1, 'b': 2, 'c': 3} 173 | 174 | ### 排序一个列表中的所有dict,根据dict内值 175 | 176 | 问题 [链接](http://stackoverflow.com/questions/72899/in-python-how-do-i-sort-a-list-of-dictionaries-by-values-of-the-dictionary) 177 | 178 | 如何排序如下列表,根据name或age 179 | 180 | [{'name':'Homer', 'age':39}, {'name':'Bart', 'age':10}] 181 | 182 | 简单的做法; 183 | 184 | newlist = sorted(list_to_be_sorted, key=lambda k: k['name']) 185 | 186 | 高效的做法 187 | 188 | from operator import itemgetter 189 | newlist = sorted(list_to_be_sorted, key=itemgetter('name')) 190 | 191 | ### 根据值排序一个字典 192 | 193 | 问题 [链接](http://stackoverflow.com/questions/613183/python-sort-a-dictionary-by-value) 194 | 195 | import operator 196 | x = {1: 2, 3: 4, 4:3, 2:1, 0:0} 197 | sorted_x = sorted(x.iteritems(), key=operator.itemgetter(1)) 198 | #[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)] 199 | #dict(sorted_x) == x 200 | 201 | ### 如何将自定义对象作为字典键值 202 | 203 | 问题 [链接](http://stackoverflow.com/questions/4901815/object-as-a-dictionary-key) 204 | 205 | class MyThing: 206 | def __init__(self,name,location,length): 207 | self.name = name 208 | self.location = location 209 | self.length = length 210 | 211 | def __hash__(self): 212 | return hash((self.name, self.location)) 213 | 214 | def __eq__(self, other): 215 | return (self.name, self.location) == (other.name, other.location) 216 | 217 | -------------------------------------------------------------------------------- /contents/qa-modules.md: -------------------------------------------------------------------------------- 1 | 2 | ### \_\_init\_\_.py是做什么用的 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/448271/what-is-init-py-for) 5 | 6 | 7 | 这是包的一部分,[具体文档](http://docs.python.org/2/tutorial/modules.html#packages) 8 | 9 | \_\_init\_\_.py让Python把目录当成包, 10 | 11 | 最简单的例子,\_\_init\_\_.py仅是一个空文件,但它可以一样执行包初始化代码或者设置\_\_all\_\_变量,后续说明 12 | 13 | ### 如何使用绝对路径import一个模块 14 | 15 | 问题 [链接](http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path) 16 | 17 | 18 | import imp 19 | 20 | foo = imp.load_source('module.name', '/path/to/file.py') 21 | foo.MyClass() 22 | 23 | ### 获取Python模块文件的路径 24 | 25 | 问题 [链接](http://stackoverflow.com/questions/247770/retrieving-python-module-path) 26 | 27 | 如何才能获取一个模块其所在的路径 28 | 29 | 回答 30 | 31 | import a_module 32 | print a_module.__file__ 33 | 34 | 获取其所在目录,可以 35 | 36 | import os 37 | path = os.path.dirname(amodule.__file__) 38 | 39 | ### 谁可以解释一下__all__么? 40 | 41 | 42 | 问题 [链接](http://stackoverflow.com/questions/44834/can-someone-explain-all-in-python) 43 | 44 | 该模块的公有对象列表 45 | 46 | __all__指定了使用import module时,哪些对象会被import进来.其他不在列表里的不会被导入 47 | 48 | __all__ = ["foo", "bar"] 49 | 50 | it's a list of public objects of that module -- it overrides the default of hiding everything that begins with an underscore 51 | 52 | ### 如何重新加载一个python模块 53 | 54 | 问题 [链接](http://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module) 55 | 56 | 使用reload内置函数 57 | 58 | reload(module_name) 59 | 60 | 61 | import foo 62 | 63 | while True: 64 | # Do some things. 65 | if is_changed(foo): 66 | foo = reload(foo) 67 | 68 | ### 在Python中,如何表示Enum(枚举) 69 | 70 | 问题[链接](http://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python) 71 | 72 | Enums已经添加进了Python 3.4,详见PEP435。同时在pypi下被反向移植进了3.3,3.2,3.1,2.7,2.6,2.5和2.4。 73 | 74 | 通过`$ pip install enum34`来使用向下兼容的Enum,下载`enum`(没有数字)则会安装完全不同并且有冲突的版本。 75 | 76 | from enum imoprt Enum 77 | Animal = Enum(‘Animal’, ‘ant bee cat dog’) 78 | 79 | 等效的: 80 | 81 | class Animals(Enum): 82 | ant = 1 83 | bee = 2 84 | cat = 3 85 | dog = 4 86 | 87 | 在早期的版本中,实现枚举的一种方法是: 88 | 89 | def enum(**enums): 90 | return type(‘Enum’, (), enums) 91 | 92 | 使用起来像这样: 93 | 94 | >>> Numbers = enum(ONE=1, TWO=2, THREE='three') 95 | >>> Numbers.ONE 96 | 1 97 | >>> Numbers.TWO 98 | 2 99 | >>> Numbers.THREE 100 | 'three' 101 | 102 | 也可以轻松的实现自动列举像下面这样: 103 | 104 | def enum(*squential, **named): 105 | enums = dict(zip(sequential, range(len(sequential))), **named) 106 | return type(‘Enum’, (), enums) 107 | 108 | 使用起来像这样: 109 | 110 | >>> Numbers = enum('ZERO', 'ONE', 'TWO') 111 | >>> Numbers.ZERO 112 | 0 113 | >>> Numbers.ONE 114 | 1 115 | 116 | 支持把值转换为名字,可以这样添加: 117 | 118 | def enum(*sequential, **named): 119 | enums = dict(zip(sequential, range(len(sequential))), **named) 120 | reverse = dict((value, key) for key, value in enums.iteritems()) 121 | enums['reverse_mapping'] = reverse 122 | return type('Enum', (), enums) 123 | 124 | 这将会根据名字重写任何东西,但是对于渲染你打印出的枚举值很有效。如果反向映射不存在,它会抛出KeyError。看一个例子: 125 | 126 | >>> Numbers.reverse_mapping[‘three’] 127 | ’THREE’ 128 | 129 | ### if __name__ == “__main__”做了什么? 130 | 131 | 问题[链接](http://stackoverflow.com/questions/419163/what-does-if-name-main-do) 132 | 133 | 稍微拓展一下Harley的答案... 134 | 135 | 当Python的解释器读一个源文件时,它执行了里面能找到的所有代码。在执行之前,它会定义少数几个变量。举个例子,如果Python解释器把该模块(即源文件)当做主程序运行,它就会把特殊的`__name__`变量的值设置为`“__main__”`。如果这个文件被其他模块引用,`__name__`就会被设置为其他模块的名字。 136 | 137 | 就你的脚本来说,我们假设把它当做主函数来执行,你可能会在命令行上这样用: 138 | 139 | python threading_example.py 140 | 141 | 设置好特殊变量之后,它会执行`import`声明并加载其他的模块。然后它会预估`def`的缩进,创建一个函数对象和一个指向函数对象的值叫做`myfunction`。之后它将读取`if`语句,确定`__name__`等于`”__main__”`后,执行缩进并展示。 142 | 143 | 这样做的主要原因是,有时候你写了一个可以直接执行的模块(一个`.py`文件),同时,它也可以被其他模块引用。通过执行主函数检查,你可以让你的代码只在作为主程序时执行,而在被其他模块引用或调用其中的函数时不执行。 144 | 145 | [这页](http://ibiblio.org/g2swap/byteofpython/read/module-name.html)可以看到更多的细节。 146 | 147 | ### 通过相对路径引用一个模块 148 | 149 | 问题[链接](http://stackoverflow.com/questions/279237/import-a-module-from-a-relative-path) 150 | 151 | 假设你的两个文件夹都是真实的python包(都有`__init__.py`文件在里面),这里有一个可以安全的把相对路径模块包含进本地的脚本。 152 | 153 | 我假设你想这样做,因为你需要在脚本中包含一系列的模块。我在许多产品的生产环境和不同的情景下用过这个:调用其他文件夹下的脚本或者在不打开一个新的解释器的情况下在Python中执行。 154 | 155 | import os, sys, inspect 156 | # realpath() will make your script run, even if you symlink it :) 157 | cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0])) 158 | if cmd_folder not in sys.path: 159 | sys.path.insert(0, cmd_folder) 160 | 161 | # use this if you want to include modules from a subfolder 162 | cmd_subfolder=os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder"))) 163 | if cmd_subfolder not in sys.path: 164 | sys.path.insert(0, cmd_subfolder) 165 | 166 | # Info: 167 | # cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE__file__ !!! 168 | # __file__ fails if script is called in different ways on Windows 169 | # __file__ fails if someone does os.chdir() before 170 | # sys.argv[0] also fails because it doesn't not always contains the path 171 | 172 | 通过这个途径,确实迫使Python使用你的模块,而不用系统自带的那些。 173 | 174 | 但是注意。在`egg`文件中的模块会发生什么我确实不知道。可能会失败。如果你知道更好的解决办法请留言,我会花几个小时去改进它。 175 | 176 | ### Python中如何进行间接引用 177 | 178 | 问题[链接](http://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python) 179 | 180 | 看上去每个人都希望告诉你你该怎么做好过只回答这个问题。 181 | 182 | 问题在于你在运行一个作为`’__main__’`的模块,向解释器传递mod1.py作为一个参数。 183 | 184 | 来自[PEP 328](http://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python): 185 | 186 | Relative imports use a module's __name__ attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to '__main__') then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system. 187 | 188 | 在Python 2.6中,他们添加了为主模块表现模块关系的功能,[PEP 366](https://www.python.org/dev/peps/pep-0366/)描述了这个功能。 -------------------------------------------------------------------------------- /contents/qa-built-in.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### 如何flush Python的print输出 4 | 5 | 问题 [链接](http://stackoverflow.com/questions/230751/how-to-flush-output-of-python-print) 6 | 重复问题 [链接](http://stackoverflow.com/questions/107705/python-output-buffering) 7 | 8 | 默认print输出到sys.stdout 9 | 10 | import sys 11 | sys.stdout.flush() 12 | 13 | 参考 14 | [http://docs.python.org/reference/simple_stmts.html#the-print-statement](http://docs.python.org/2/reference/simple_stmts.html#the-print-statement) 15 | [http://docs.python.org/library/sys.html](http://docs.python.org/2/library/sys.html) 16 | [http://docs.python.org/library/stdtypes.html#file-objects](http://docs.python.org/2/library/stdtypes.html#file-objects) 17 | 18 | ### Python如何检查一个对象是list或者tuple,但是不是一个字符串 19 | 20 | 问题 [链接](http://stackoverflow.com/questions/1835018/python-check-if-an-object-is-a-list-or-tuple-but-not-string) 21 | 22 | 原来的做法是 23 | 24 | assert isinstance(lst, (list, tuple)) 25 | 26 | 有没有更好的做法 27 | 28 | 我认为下面的方式是你需要的 29 | 30 | assert not isinstance(lst, basestring) 31 | 32 | 原来的方式,你可能会漏过很多像列表,但并非list/tuple的 33 | 34 | ### Python中检查类型的权威方法 35 | 36 | 问题 [链接](http://stackoverflow.com/questions/152580/whats-the-canonical-way-to-check-for-type-in-python) 37 | 38 | 检查一个对象是否是给定类型或者对象是否继承于给定类型? 39 | 40 | 比如给定一个对象o,如何判断是不是一个str 41 | 42 | 检查是否是str 43 | 44 | type(o) is str 45 | 46 | 检查是否是str或者str的子类 47 | 48 | isinstance(o, str) 49 | 50 | 下面的方法在某些情况下有用 51 | 52 | issubclass(type(o), str) 53 | type(o) in ([str] + str.__subclasses__()) 54 | 55 | 注意,你或许想要的是 56 | 57 | isinstance(o, basestring) 58 | 59 | 因为unicode字符串可以满足判定(unicode 不是str的子类,但是str和unicode都是basestring的子类) 60 | 61 | 可选的,isinstance可以接收多个类型参数,只要满足其中一个即True 62 | 63 | isinstance(o, (str, unicode)) 64 | 65 | ### 如何判断一个变量的类型 66 | 67 | 问题 [链接](http://stackoverflow.com/questions/402504/how-to-determine-the-variable-type-in-python) 68 | 69 | 使用type 70 | 71 | >>> i = 123 72 | >>> type(i) 73 | 74 | >>> type(i) is int 75 | True 76 | >>> i = 123456789L 77 | >>> type(i) 78 | 79 | >>> type(i) is long 80 | True 81 | >>> i = 123.456 82 | >>> type(i) 83 | 84 | >>> type(i) is float 85 | True 86 | 87 | 另外一个相同的问题 [链接](http://stackoverflow.com/questions/2225038/python-determine-the-type-of-an-object) 88 | 89 | >>> type( [] ) == list 90 | True 91 | >>> type( {} ) == dict 92 | True 93 | >>> type( "" ) == str 94 | True 95 | >>> type( 0 ) == int 96 | True 97 | 98 | >>> class Test1 ( object ): 99 | pass 100 | >>> class Test2 ( Test1 ): 101 | pass 102 | >>> a = Test1() 103 | >>> b = Test2() 104 | >>> type( a ) == Test1 105 | True 106 | >>> type( b ) == Test2 107 | True 108 | >>> type( b ) == Test1 109 | False 110 | >>> isinstance( b, Test1 ) 111 | True 112 | >>> isinstance( b, Test2 ) 113 | True 114 | >>> isinstance( a, Test1 ) 115 | True 116 | >>> isinstance( a, Test2 ) 117 | False 118 | >>> isinstance( [], list ) 119 | True 120 | >>> isinstance( {}, dict ) 121 | True 122 | 123 | ### Python中如何注释一段代码块/为什么Python没有多行注释 124 | 125 | 问题 [链接](http://stackoverflow.com/questions/675442/comment-out-a-python-code-block) 126 | 127 | 问题 [链接](http://stackoverflow.com/questions/397148/why-doesnt-python-have-multiline-comments) 128 | 129 | Python中多行注释的方式是 130 | 131 | #print "hello" 132 | #print "world" 133 | 134 | 注意,不要使用多行字符串对代码块进行注释,除非是文档字符串docstring. 135 | 136 | ### Python中单引号和双引号 137 | 138 | 问题 [链接](http://stackoverflow.com/questions/56011/single-quotes-vs-double-quotes-in-python) 139 | 140 | 根据文档,两者貌似没什么区别,有什么风格上的使用建议么? 141 | 142 | 143 | 我偏好于 144 | 145 | 双引号: 用于插入/改写的字符串, 自然语言消息 146 | 147 | 单引号: 标识符字符串,例如字典key. 除非该字符串本身有单括号或者我忘了 148 | 149 | 三引号: 文档字符串docstring 或者 正则表达式中原始字符串raw string 150 | 151 | 例如: 152 | 153 | LIGHT_MESSAGES = { 154 | 'English': "There are %(number_of_lights)s lights.", 155 | 'Pirate': "Arr! Thar be %(number_of_lights)s lights." 156 | } 157 | 158 | def lights_message(language, number_of_lights): 159 | """Return a language-appropriate string reporting the light count.""" 160 | return LIGHT_MESSAGES[language] % locals() 161 | 162 | def is_pirate(message): 163 | """Return True if the given message sounds piratical.""" 164 | return re.search(r"(?i)(arr|avast|yohoho)!", message) is not None 165 | 166 | 这里很偏个人风格,所以,根据自己喜好,保持一致就行 167 | 168 | 169 | ### 你是否能解释Python中的闭包 170 | 171 | 问题 [链接](http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python) 172 | 173 | 174 | 参考文章 [Closure on closures](http://mrevelle.blogspot.com/2006/10/closure-on-closures.html) 175 | 176 | 对象是数据和方法关联 177 | 闭包是函数和数据关联 178 | 179 | 例如 180 | 181 | def make_counter(): 182 | i = 0 183 | def counter(): # counter() is a closure 184 | nonlocal i 185 | i += 1 186 | return i 187 | return counter 188 | 189 | c1 = make_counter() 190 | c2 = make_counter() 191 | 192 | print (c1(), c1(), c2(), c2()) 193 | # -> 1 2 1 2 194 | 195 | 其他解释(感觉英文更精准) 196 | 197 | A function that references variables from a containing scope, potentially after flow-of-control has left that scope 198 | 199 | A function that can refer to environments that are no longer active. 200 | A closure allows you to bind variables into a function without passing them as parameters. 201 | 202 | ### Python Lambda - why? 203 | 204 | 问题 [链接](http://stackoverflow.com/questions/890128/python-lambda-why) 205 | 206 | Are you talking about lambda functions? Like 207 | 208 | 你是指lambda函数? 例如 209 | 210 | f = lambda x: x**2 + 2*x - 5 211 | 212 | 非常有用, python支持函数式编程, 你可以将函数作为参数进行传递去做一些事情 213 | 214 | 例子: 215 | 216 | mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9]) 217 | # sets mult3 to [3, 6, 9] 218 | 219 | 这样相对于完整地函数更为简短 220 | 221 | def filterfunc(x): 222 | return x % 3 == 0 223 | mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9]) 224 | 225 | 当然, 这个例子你也可以使用列表解析进行处理 226 | 227 | mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0] 228 | 229 | 甚至是 230 | 231 | range(3,10,3) 232 | 233 | lambda function may be the shortest way to write something out 234 | 235 | ### Python中__str__和__repr__的区别 236 | 237 | 问题[链接](http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python) 238 | 239 | Alex总结的很好,但是,有点出乎意料的精简了。 240 | 241 | 首先,让我重复一下Alex回答的重点: 242 | 243 | - 缺省实现是没用的(很难想象,但是的确是这样的) 244 | 245 | - `__repr__`的目的是清晰 246 | 247 | - `__str__`的目的是可读性 248 | 249 | - 容器的`__str__`使用已包含对象`__repr__` 250 | 251 | **缺省实现是没用的** 252 | 253 | 这实在是奇怪,因为Python的缺省实现是为了完全的可用。然而,在这种情况下,使用缺省的`__repr__`会表现的像这样: 254 | 255 | return "%s(%r)" % (self.__class__, self.__dict__) 256 | 257 | 这很危险(举个例子。如果对象被引用,太容易陷入无限循环)。所以,Python选择逃避。注意有一个缺省是正确的:如果`__repr__`已经定义,而`__str__`没有,对象会表现出`__str__=__repr__`。 258 | 259 | 这意味着,简单讲:几乎所有你实现的对象都应该有一个`__repr__`函数用来理解这个对象。实现`__str__`是一个选择:如果你需要一个"良好的打印”函数(举个例子,用来表现一个生成器) 260 | 261 | **`__repr__`的目标是清晰的** 262 | 263 | 让我实话实说-我并不相信调试器。我不知道如何使用任何一种调试器,而且没有认真使用过任何一款。我觉的调试器的最大错误是它们的本质--我调试错误发生在很久很久以前,超级久远。这意味着我有着宗教热情一般的相信日志。日志是一切一劳永逸的服务器系统的生命之血。Python可以轻松的记录日志:可能某些项目有特殊的包装,但是你需要的仅仅是一句: 264 | 265 | (INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c) 266 | 267 | 但是你需要做最后一步,所有你实现的对象有一个有效的repr,所以上面这种代码才会工作。这就是为什么"eval"这种东西出现:如果你又足够的信息可以让`eval(repr(c)) == c`,这意味着你知道所有的东西,像知道`c`一样。如果它足够简单,至少通过模糊的方法,实现它。如果不是这样的,请无论如何了解`c`的足够信息。我通常使用一个类eval的格式:`"My class(this=%r, that=%r)" % (self.this, self.that)"`。这不意味着你可以真正的结构化MyClass或者他们全都是正确的结构器参数。但是他们是很有用的形式代表“这个实例中你需要了解的信息就是这些”。 268 | 269 | 注意:我用的是`%r`而不是`%s`。你总是想用`repr()`[或者`%r`格式等效的角色]在一个可实现的`__repr__`中,或者你被repr的目的打败的。你需要知道`MyClass(3)`和`Myclass("3")`的区别。 270 | 271 | **`__str__`的目标是可读性** 272 | 273 | 实际上,它不是为了更清晰--注意`str(3) == str("3")`。同样的,如果你实现了一个IP的抽象,有一个字符串看上去像192.168.1.1是Ok的。当实现一个日期或时间的抽象时,字符串可以是“2014/4/12 15:35:33"等等。所以它的目标是通过一种方式让用户,而不是一个程序员,可以正常的阅读它。去掉那些无用的字码,假装成其他的类--在它支持可读性之后,这是一种进化。 274 | 275 | **容器的`__str__`使用已包含对象`__repr__` 276 | 277 | 这看上去很奇怪,是不是?确实有一点,但是可读性是这样: 278 | 279 | [moshe is, 3, hello 280 | world, this is a list, oh I don't know, containing just 4 elements] 281 | 282 | 吗?不一定。尤其是,容器内部的字符串会找到一个很容易实现的方式去构建它们所代表的东西。面对这种含糊不清的东西,记住,Python禁止猜测。如果你打印一个列表,想要上述的表现形式时,只需要 283 | 284 | print "["+", ".join(l)+"]" 285 | 286 | (你应该会想出如何处理字典) 287 | 288 | **总结** 289 | 290 | 为你所有实现的类,实现`__repr__`。这应该是第二特性。实现`__str__`,对于那些你认为使用可视化字符串会更好的表现出错误的可读性,并阻止含糊不清的东西。 -------------------------------------------------------------------------------- /contents/qa-control-flow.md: -------------------------------------------------------------------------------- 1 | ### 如何结束退出一个python脚本 2 | 3 | 问题 [链接](http://stackoverflow.com/questions/73663/terminating-a-python-script) 4 | 5 | import sys 6 | sys.exit() 7 | 8 | ### foo is None 和 foo == None的区别 9 | 10 | 问题 [链接](http://stackoverflow.com/questions/26595/is-there-any-difference-between-foo-is-none-and-foo-none) 11 | 12 | if foo is None: pass 13 | if foo == None: pass 14 | 15 | 如果比较相同的对象实例,is总是返回True 16 | 而 == 最终取决于 "__eq__()" 17 | 18 | >>> class foo(object): 19 | def __eq__(self, other): 20 | return True 21 | 22 | >>> f = foo() 23 | >>> f == None 24 | True 25 | >>> f is None 26 | False 27 | 28 | >>> list1 = [1, 2, 3] 29 | >>> list2 = [1, 2, 3] 30 | >>> list1==list2 31 | True 32 | >>> list1 is list2 33 | False 34 | 35 | 另外 36 | 37 | (ob1 is ob2) 等价于 (id(ob1) == id(ob2)) 38 | 39 | 40 | 41 | ### 如何在循环中获取下标 42 | 43 | 问题 [链接](http://stackoverflow.com/questions/522563/accessing-the-index-in-python-for-loops) 44 | 45 | 使用enumerate 46 | 47 | for idx, val in enumerate(ints): 48 | print idx, val 49 | 50 | ### python中如何将一行长代码切成多行 51 | 52 | 问题 [链接](http://stackoverflow.com/questions/53162/how-can-i-do-a-line-break-line-continuation-in-python) 53 | 54 | 例如: 55 | 56 | e = 'a' + 'b' + 'c' + 'd' 57 | 变成 58 | e = 'a' + 'b' + 59 | 'c' + 'd' 60 | 61 | 括号中,可以直接换行 62 | 63 | a = dostuff(blahblah1, blahblah2, blahblah3, blahblah4, blahblah5, 64 | blahblah6, blahblah7) 65 | 66 | 67 | 非括号你可以这么做 68 | 69 | a = '1' + '2' + '3' + \ 70 | '4' + '5' 71 | 或者 72 | a = ('1' + '2' + '3' + 73 | '4' + '5') 74 | 75 | 可以查看下代码风格: [style guide](http://www.python.org/dev/peps/pep-0008/) 76 | 推荐是后一种,但某些个别情况下,加入括号会导致错误 77 | 78 | ### 为何1 in [1,0] == True执行结果是False 79 | 80 | 问题 [链接](http://stackoverflow.com/questions/9284350/why-does-1-in-1-0-true-evaluate-to-false) 81 | 82 | 有如下 83 | 84 | >>> 1 in [1,0] # This is expected 85 | True 86 | >>> 1 in [1,0] == True # This is strange 87 | False 88 | >>> (1 in [1,0]) == True # This is what I wanted it to be 89 | True 90 | >>> 1 in ([1,0] == True) # But it's not just a precedence issue! 91 | # It did not raise an exception on the second example. 92 | 93 | Traceback (most recent call last): 94 | File "", line 1, in 95 | 1 in ([1,0] == True) 96 | TypeError: argument of type 'bool' is not iterable 97 | 98 | 这里python使用了比较运算符链 99 | 100 | 1 in [1,0] == True 101 | 102 | 将被转为 103 | 104 | (1 in [1, 0]) and ([1, 0] == True) 105 | 106 | 很显然是false的 107 | 108 | 同样的 109 | 110 | a < b < c 111 | 112 | 会被转为 113 | 114 | (a < b) and (b < c) # b不会被解析两次 115 | 116 | [具体文档](http://docs.python.org/2/reference/expressions.html#not-in) 117 | 118 | ### Python中的switch替代语法 119 | 120 | 问题 [链接](http://stackoverflow.com/questions/60208/replacements-for-switch-statement-in-python) 121 | 122 | python中没有switch,有什么推荐的处理方法么 123 | 124 | 使用字典: 125 | 126 | def f(x): 127 | return { 128 | 'a': 1, 129 | 'b': 2, 130 | }.get(x, 9) 131 | 132 | Python Cookbook中的几种方式 133 | 134 | [Readable switch construction without lambdas or dictionaries](http://code.activestate.com/recipes/410692/) 135 | 136 | [Exception-based Switch-Case](http://code.activestate.com/recipes/410695/) 137 | 138 | [Using a Dictionary in place of a 'switch' statement](http://code.activestate.com/recipes/181064/) 139 | 140 | 141 | ### 使用 'if x is not None' 还是'if not x is None' 142 | 143 | 问题 [链接](http://stackoverflow.com/questions/2710940/python-if-x-is-not-none-or-if-not-x-is-none) 144 | 145 | 我总想着使用 'if not x is None' 会更加简明 146 | 147 | 但是google的Python风格指南使用的却是 'if x is not None' 148 | 149 | 性能上没有什么区别,他们编译成相同的字节码 150 | 151 | Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39) 152 | >>> import dis 153 | >>> def f(x): 154 | ... return x is not None 155 | ... 156 | >>> dis.dis(f) 157 | 2 0 LOAD_FAST 0 (x) 158 | 3 LOAD_CONST 0 (None) 159 | 6 COMPARE_OP 9 (is not) 160 | 9 RETURN_VALUE 161 | >>> def g(x): 162 | ... return not x is None 163 | ... 164 | >>> dis.dis(g) 165 | 2 0 LOAD_FAST 0 (x) 166 | 3 LOAD_CONST 0 (None) 167 | 6 COMPARE_OP 9 (is not) 168 | 9 RETURN_VALUE 169 | 170 | 在风格上,我尽量避免 'not x is y' 这种形式,虽然编译器会认为和 'not (x is y)'一样,但是读代码的人或许会误解为 '(not x) is y' 171 | 172 | 如果写作 'x is not y' 就不会有歧义 173 | 174 | 最佳实践 175 | 176 | if x is not None: 177 | # Do something about x 178 | 179 | ### 在非创建全局变量的地方使用全局变量 180 | 181 | 问题 [链接](http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them) 182 | 183 | 如果我在一个函数中创建了全局变量,如何在另一个函数中使用? 184 | 185 | 回答: 186 | 187 | 你可以在给全局变量赋值的函数中声明 global 188 | 189 | globvar = 0 190 | 191 | def set_globvar_to_one(): 192 | global globvar # Needed to modify global copy of globvar 193 | globvar = 1 194 | 195 | def print_globvar(): 196 | print globvar # No need for global declaration to read value of globvar 197 | 198 | set_globvar_to_one() 199 | print_globvar() # Prints 1 200 | 201 | 我猜想这么做的原因是,全局变量很危险,Python想要确保你真的知道你要对一个全局的变量进行操作 202 | 203 | 如果你想知道如何在模块间使用全局变量,查看其他回答 204 | 205 | ### 如何检测一个变量是否存在 206 | 207 | 问题 [链接](http://stackoverflow.com/questions/843277/how-do-i-check-if-a-variable-exists-in-python) 208 | 209 | 我想检测一个变量是否存在,我现在是这么做的 210 | 211 | try: 212 | myVar 213 | except NameError: 214 | # Doint smth 215 | 216 | 存在其他不是使用exception的方式么? 217 | 218 | 回答 219 | 220 | 221 | 检测本地变量 222 | 223 | if 'myVar' in locals(): 224 | # myVar exists. 225 | 226 | 检测全局变量 227 | 228 | if 'myVar' in globals(): 229 | # myVar exists. 230 | 231 | 检测一个对象是否包含某个属性 232 | 233 | if hasattr(obj, 'attr_name'): 234 | # obj.attr_name exists. 235 | 236 | ### Python中是否存在三元运算符 237 | 238 | 问题 [链接](http://stackoverflow.com/questions/394809/does-python-have-a-ternary-conditional-operator) 239 | 240 | 三元运算在Python2.5中被加入 241 | 242 | a if test else b 243 | 244 | 使用 245 | 246 | >>> 'true' if True else 'false' 247 | 'true' 248 | >>> 'true' if False else 'false' 249 | 'false' 250 | 251 | 官方文档: 252 | 253 | [Conditional expressions](https://docs.python.org/3/reference/expressions.html#conditional-expressions) 254 | 255 | [Is there an equivalent of C’s ”?:” ternary operator?](https://docs.python.org/3.3/faq/programming.html#is-there-an-equivalent-of-c-s-ternary-operator) 256 | 257 | 258 | ### Python中的do-while 259 | 260 | 问题 [链接](http://stackoverflow.com/questions/743164/do-while-loop-in-python) 261 | 262 | 实现方法 263 | 264 | while True: 265 | stuff() 266 | if fail_condition: 267 | break 268 | 269 | 或者 270 | 271 | stuff() 272 | while not fail_condition: 273 | stuff() 274 | 275 | ### 相对于range() 应该更倾向于实用xrange()? 276 | 277 | 问题 [链接](http://stackoverflow.com/questions/135041/should-you-always-favor-xrange-over-range) 278 | 279 | why or why not? 280 | 281 | 就性能而言, 特别是当你迭代一个大的range, xrange()更优. 但是, 有一些情况下range()更优 282 | 283 | - 在Python3中, range() 等价于 python2.x的 xrange(), 而xrange()不存在了.(如果你的代码将在2和3下运行, 不能使用xrange) 284 | 285 | - range()在某些情况下更快, 例如, 多次重复遍历同一个序列. 286 | 287 | - xrange()并不适用于所有情况, 例如, 不支持slices以及任意的list方法 288 | 289 | 290 | ### 在Python中,“i += x”和“i = i + x”什么时候不等 291 | 292 | 问题[链接](http://stackoverflow.com/questions/15376509/when-is-i-x-different-from-i-i-x-in-python) 293 | 294 | 这完全取决于i这个对象。 295 | 296 | `+=`调用了[`__iadd__`方法](https://docs.python.org/2/reference/datamodel.html#object.__iadd__)(如果存在—不存在就退一步调用`__add__`),然而`+`调用[`__add__`方法](https://docs.python.org/2/reference/datamodel.html#object.__add__)^1 297 | 298 | 从一个API的角度,`__iadd__`期望被使用在恰当的位置修改易变的对象(返回的对象也是转变后的),而`__add__`应该返回某些东西的一个新的实例。对于不可变对象,两种方法都返回新的实例,但`__iadd__`会把新的实例放在和旧实例名字相同的命名空间里。这就是为什么 299 | 300 | i = 1 301 | i += 1 302 | 303 | 看上去增量`i`,实际上,你得到了一个新的数值,并且转移到了`i`的最上面—丢掉了旧的数值的引用。在这种情况下,`i += 1`和`i = i + 1`是完全一样的。但是,对于大多数可变对象,这是完全不同的: 304 | 305 | 一个具体的例子: 306 | 307 | a = [1, 2, 3] 308 | b = a 309 | b += [1, 2, 3] 310 | print a #[1, 2, 3, 1, 2, 3] 311 | print b #[1, 2, 3, 1, 2, 3] 312 | 313 | 对比一下: 314 | 315 | a = [1, 2, 3] 316 | b = a 317 | b = b + [1, 2, 3] 318 | print a #[1, 2, 3] 319 | print b #[1, 2, 3, 1, 2, 3] 320 | 321 | 注意第一个例子,从`b`和`a`代表相同的对象开始,当我对`b`使用`+=`,实际上它改变了`b`(`a`看起来也改变了- -毕竟他们代表同一个列表)。但是在第二个例子里,当我进行`b = b + [1, 2, 3]`操作时,b被引用并且和一个新的列表`[1, 2, 3]`联系了起来。之后在b的命名空间保存了这个关联的列表- -不考虑b之前的序列。 322 | -------------------------------------------------------------------------------- /contents/qa-file.md: -------------------------------------------------------------------------------- 1 | 2 | ### 如何判断一个文件是否存在 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/82831/how-do-i-check-if-a-file-exists-using-python) 5 | 6 | 如何检查一个文件是否存在,不适用try:声明 7 | 8 | import os.path 9 | print os.path.isfile(fname) 10 | 11 | print os.path.exists(fname) 12 | 13 | 14 | ### 如何创建不存在的目录结构 15 | 16 | 问题 [链接](http://stackoverflow.com/questions/273192/python-best-way-to-create-directory-if-it-doesnt-exist-for-file-write) 17 | 18 | 19 | if not os.path.exists(directory): 20 | os.makedirs(directory) 21 | 22 | 需要注意的是,当目录在exists和makedirs两个函数调用之间被创建时,makedirs将抛出OSError 23 | 24 | ### 如何拷贝一个文件 25 | 26 | 问题 [链接](http://stackoverflow.com/questions/123198/how-do-i-copy-a-file-in-python) 27 | 28 | [shutil](http://docs.python.org/2/library/shutil.html)模块 29 | 30 | copyfile(src, dst) 31 | 32 | 将src文件内容拷贝到dst,目标文件夹必须可写,否则将抛出IOError异常 33 | 34 | 如果目标文件已存在,将被覆盖 35 | 36 | 另外特殊文件,如字符文件和块设备文件,无法用这个方法进行拷贝 37 | 38 | src/dst是字符串 39 | 40 | ### 逐行读文件去除换行符(perl chomp line) 41 | 42 | 问题 [链接](http://stackoverflow.com/questions/275018/how-can-i-remove-chomp-a-newline-in-python) 43 | 类似问题 [链接](http://stackoverflow.com/questions/761804/trimming-a-string-in-python) 44 | 45 | 读一个文件,如何获取每一行内容(不包括换行符) 46 | 47 | 比较pythonic的做法: 48 | 49 | >>> text = "line 1\nline 2\r\nline 3\nline 4" 50 | >>> text.splitlines() 51 | ['line 1', 'line 2', 'line 3', 'line 4'] 52 | 53 | 用rstrip,(rstrip/lstrip/strip) 54 | 55 | #去除了尾部的空白+换行 56 | >>> 'test string \n'.rstrip() 57 | 'test string' 58 | #只去换行 59 | >>> 'test string \n'.rstrip('\n') 60 | 'test string ' 61 | #更通用的做法,系统相关 62 | >>> import os, sys 63 | >>> sys.platform 64 | 'linux2' 65 | >>> "foo\r\n".rstrip(os.linesep) 66 | 'foo\r' 67 | 68 | ### 如何获取一个文件的创建和修改时间 69 | 70 | 问题 [链接](http://stackoverflow.com/questions/237079/how-to-get-file-creation-modification-date-times-in-python) 71 | 72 | 跨平台的获取文件创建及修改时间的方法 73 | 74 | 你有很多选择 75 | 76 | 使用[os.path.getmtime](http://docs.python.org/release/2.5.2/lib/module-os.path.html#l2h-2177)或者[os.path.getctime](http://docs.python.org/release/2.5.2/lib/module-os.path.html#l2h-2178) 77 | 78 | 79 | import os.path, time 80 | print "last modified: %s" % time.ctime(os.path.getmtime(file)) 81 | print "created: %s" % time.ctime(os.path.getctime(file)) 82 | 83 | 或者[os.stat](http://www.python.org/doc/2.5.2/lib/module-stat.html) 84 | 85 | import os, time 86 | (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(file) 87 | print "last modified: %s" % time.ctime(mtime) 88 | 89 | 注意,ctime()并非指*nix系统中文件创建时间,而是这个节点数据的最后修改时间 90 | 91 | ### 如何将字符串转换为datetime 92 | 93 | 问题 [链接](http://stackoverflow.com/questions/466345/converting-string-into-datetime) 94 | 95 | 可以查看下time模块的[strptime](http://docs.python.org/2/library/time.html#time.strptime)方法,反向操作是[strftime](http://docs.python.org/2/library/time.html#time.strftime) 96 | 97 | from datetime import datetime 98 | date_object = datetime.strptime('Jun 1 2005 1:33PM', '%b %d %Y %I:%M%p') 99 | 100 | [扩展文档](http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior) 101 | 102 | ### 找到当前目录及文件所在目录 103 | 104 | 问题 [链接](http://stackoverflow.com/questions/5137497/find-current-directory-and-files-directory) 105 | 106 | 查找当前目录使用os.getcwd() 107 | 108 | 查找某个文件的目录,使用, [os.path](http://docs.python.org/2/library/os.path.html) 109 | 110 | import os.path 111 | os.path.realpath(__file__) 112 | 113 | ### 如何找到一个目录下所有.txt文件 114 | 115 | 问题 [链接](http://stackoverflow.com/questions/3964681/find-all-files-in-directory-with-extension-txt-with-python) 116 | 117 | 使用[glob](http://docs.python.org/2/library/glob.html) 118 | 119 | import glob 120 | import os 121 | os.chdir("/mydir") 122 | for files in glob.glob("*.txt"): 123 | print files 124 | 125 | 使用os.listdir 126 | 127 | import os 128 | os.chdir("/mydir") 129 | for files in os.listdir("."): 130 | if files.endswith(".txt"): 131 | print files 132 | 133 | 或者遍历目录 134 | 135 | import os 136 | for r,d,f in os.walk("/mydir"): 137 | for files in f: 138 | if files.endswith(".txt"): 139 | print os.path.join(r,files) 140 | 141 | ### 读文件到列表中 142 | 143 | 问题 [链接](http://stackoverflow.com/questions/3277503/python-read-file-line-by-line-into-array) 144 | 145 | 146 | f = open('filename') 147 | lines = f.readlines() 148 | f.close() 149 | 等价 150 | with open(fname) as f: 151 | content = f.readlines() 152 | 153 | [文档](http://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files) 154 | 155 | ### 如何往文件中追加文本 156 | 157 | 问题 [链接](http://stackoverflow.com/questions/4706499/how-do-you-append-to-file-in-python) 158 | 159 | with open("test.txt", "a") as myfile: 160 | myfile.write("appended text") 161 | 162 | 可以使用'a'或'a+b' mode打开文件,见 [文档](http://docs.python.org/2/library/functions.html#open) 163 | 164 | ### 如何获取文件扩展名 165 | 166 | 问题 [链接](http://stackoverflow.com/questions/541390/extracting-extension-from-filename-in-python) 167 | 168 | 使用os.path.splitext方法: 169 | 170 | >>> import os 171 | >>> fileName, fileExtension = os.path.splitext('/path/to/somefile.ext') 172 | >>> fileName 173 | '/path/to/somefile' 174 | >>> fileExtension 175 | '.ext' 176 | 177 | ### 如何列出一个目录的所有文件 178 | 179 | 问题 [链接](http://stackoverflow.com/questions/3207219/how-to-list-all-files-of-a-directory-in-python) 180 | 181 | 1.使用os.listdir(),得到目录下的所有文件和文件夹 182 | 183 | #只需要文件 184 | from os import listdir 185 | from os.path import isfile, join 186 | onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ] 187 | 188 | 2.os.walk() 189 | 190 | from os import walk 191 | 192 | f = [] 193 | for (dirpath, dirnames, filenames) in walk(mypath): 194 | f.extend(filenames) 195 | break 196 | 197 | 3.glob 198 | 199 | import glob 200 | print glob.glob("/home/adam/*.txt") 201 | 202 | 重复问题 [链接](http://stackoverflow.com/questions/120656/directory-listing-in-python) 203 | 204 | import os 205 | 206 | for dirname, dirnames, filenames in os.walk('.'): 207 | # print path to all subdirectories first. 208 | for subdirname in dirnames: 209 | print os.path.join(dirname, subdirname) 210 | 211 | # print path to all filenames. 212 | for filename in filenames: 213 | print os.path.join(dirname, filename) 214 | 215 | ### 如何从标准输入读取内容stdin 216 | 217 | 问题 [链接](http://stackoverflow.com/questions/1450393/how-do-you-read-from-stdin-in-python) 218 | 219 | 220 | 使用[fileinput](http://docs.python.org/2/library/fileinput.html) 221 | 222 | import fileinput 223 | for line in fileinput.input(): 224 | pass 225 | 226 | ### 如何高效地获取文件行数 227 | 228 | 问题 [链接](http://stackoverflow.com/questions/845058/how-to-get-line-count-cheaply-in-python) 229 | 230 | 231 | 比较结果python2.6 232 | 233 | mapcount : 0.471799945831 234 | simplecount : 0.634400033951 235 | bufcount : 0.468800067902 236 | opcount : 0.602999973297 237 | 238 | 代码 239 | 240 | from __future__ import with_statement 241 | import time 242 | import mmap 243 | import random 244 | from collections import defaultdict 245 | 246 | def mapcount(filename): 247 | f = open(filename, "r+") 248 | buf = mmap.mmap(f.fileno(), 0) 249 | lines = 0 250 | readline = buf.readline 251 | while readline(): 252 | lines += 1 253 | return lines 254 | 255 | def simplecount(filename): 256 | lines = 0 257 | for line in open(filename): 258 | lines += 1 259 | return lines 260 | 261 | def bufcount(filename): 262 | f = open(filename) 263 | lines = 0 264 | buf_size = 1024 * 1024 265 | read_f = f.read # loop optimization 266 | 267 | buf = read_f(buf_size) 268 | while buf: 269 | lines += buf.count('\n') 270 | buf = read_f(buf_size) 271 | 272 | return lines 273 | 274 | def opcount(fname): 275 | with open(fname) as f: 276 | for i, l in enumerate(f): 277 | pass 278 | return i + 1 279 | 280 | 281 | counts = defaultdict(list) 282 | 283 | for i in range(5): 284 | for func in [mapcount, simplecount, bufcount, opcount]: 285 | start_time = time.time() 286 | assert func("big_file.txt") == 1209138 287 | counts[func].append(time.time() - start_time) 288 | 289 | for key, vals in counts.items(): 290 | print key.__name__, ":", sum(vals) / float(len(vals)) 291 | 292 | 293 | ### Python如何实现mkdir -p功能 294 | 295 | 296 | 问题 [链接](http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python) 297 | 298 | import os, errno 299 | 300 | def mkdir_p(path): 301 | try: 302 | os.makedirs(path) 303 | except OSError as exc: # Python >2.5 304 | if exc.errno == errno.EEXIST and os.path.isdir(path): 305 | pass 306 | else: raise 307 | 308 | -------------------------------------------------------------------------------- /contents/qa-string.md: -------------------------------------------------------------------------------- 1 | ### 为什么是string.join(list)而不是list.join(string) 2 | 3 | 问题 [链接](http://stackoverflow.com/questions/493819/python-join-why-is-it-string-joinlist-instead-of-list-joinstring) 4 | 5 | my_list = ["Hello", "world"] 6 | print "-".join(my_list) 7 | #为什么不是 my_list.join("-") 。。。。这个.... 8 | 9 | 答案: 10 | 11 | 因为所有可迭代对象都可以被连接,而不只是列表,但是连接者总是字符串 12 | 13 | ### 字符如何转为小写 14 | 15 | 问题 [链接](http://stackoverflow.com/questions/6797984/how-to-convert-string-to-lowercase-in-python) 16 | 17 | s = "Kilometer" 18 | print(s.lower()) 19 | 20 | ### 字符串转为float/int 21 | 22 | >>> a = "545.2222" 23 | >>> float(a) 24 | 545.2222 25 | >>> int(a) 26 | Traceback (most recent call last): 27 | File "", line 1, in 28 | ValueError: invalid literal for int() with base 10: '545.2222' 29 | >>> int(float(a)) 30 | 545 31 | >>> int('544') 32 | 544 33 | 34 | 另一种,用 [ast](http://docs.python.org/2/library/ast.html#ast.literal_eval)模块 35 | 36 | 37 | >>> import ast 38 | >>> ast.literal_eval("545.2222") 39 | 545.2222 40 | >>> ast.literal_eval("31") 41 | 31 42 | 43 | 44 | ### 如何反向输出一个字符串 45 | 46 | 问题 [链接](http://stackoverflow.com/questions/931092/reverse-a-string-in-python) 47 | 48 | 做法 49 | 50 | >>> 'hello world'[::-1] 51 | 'dlrow olleh' 52 | 53 | ### 如何随机生成大写字母和数字组成的字符串 54 | 55 | 6U1S75 56 | 4Z4UKK 57 | U911K4 58 | 59 | 解决 60 | 61 | import string, random 62 | ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(N)) 63 | 64 | ### python中字符串的contains 65 | 66 | 问题 [链接](http://stackoverflow.com/questions/3437059/does-python-have-a-string-contains-method) 67 | 68 | python中字符串判断contains 69 | 70 | 使用in关键字 71 | 72 | if not "blah" in somestring: continue 73 | if "blah" not in somestring: continue 74 | 75 | 使用字符串的find/index (注意index查找失败抛异常) 76 | 77 | s = "This be a string" 78 | if s.find("is") == -1: 79 | print "No 'is' here!" 80 | else: 81 | print "Found 'is' in the string." 82 | 83 | ### 如何判断一个字符串是数字 84 | 85 | 问题 [链接](http://stackoverflow.com/questions/354038/how-do-i-check-if-a-string-is-a-number-in-python) 86 | 87 | 使用这种方法会不会十分丑陋和低效 88 | 89 | def is_number(s): 90 | try: 91 | float(s) 92 | return True 93 | except ValueError: 94 | return False 95 | 96 | 使用这种方法并不丑陋和低效 97 | 98 | 使用isdigit(缺点,对非整数无能为力) 99 | 100 | a = "03523" 101 | a.isdigit() 102 | 103 | ### 字符串格式化 % vs format 104 | 105 | 问题 [链接](http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format) 106 | 107 | Python2.6中引入string.format()方法,语法和原先%操作符的字符串格式化差异较大 108 | 109 | 在什么情况下使用哪种更好? 110 | 111 | 以下的输出是一致的,有什么区别 112 | 113 | #!/usr/bin/python 114 | sub1 = "python string!" 115 | sub2 = "an arg" 116 | 117 | a = "i am a %s"%sub1 118 | b = "i am a {0}".format(sub1) 119 | 120 | c = "with %(kwarg)s!"%{'kwarg':sub2} 121 | d = "with {kwarg}!".format(kwarg=sub2) 122 | 123 | print a 124 | print b 125 | print c 126 | print d 127 | 128 | .format 看起来更加强大,可以用在很多情况. 129 | 130 | 例如你可以在格式化时重用传入的参数,而你用%时无法做到这点 131 | 132 | 另一个比较讨厌的是,%只处理 一个变量或一个元组, 你或许会认为下面的语法是正确的 133 | 134 | "hi there %s" % name 135 | 136 | 但当name恰好是(1,2,3)时,会抛出TypeError异常.为了保证总是正确的,你必须这么写 137 | 138 | "hi there %s" % (name,) # supply the single argument as a single-item tuple 139 | 140 | 这么写很丑陋, .format没有这些问题 141 | 142 | 什么时候不考虑使用.format 143 | 144 | 你对.format知之甚少 145 | 使用Python2.5 146 | 147 | ### 将一个字符串转为一个字典 148 | 149 | 问题 [链接](http://stackoverflow.com/questions/988228/converting-a-string-to-dictionary) 150 | 151 | 如何将字符串转成字典,不适用eval 152 | 153 | s = "{'muffin' : 'lolz', 'foo' : 'kitty'}" 154 | 155 | 从python2.6开始,你可以使用内建模块 ast.literal_eval 156 | 157 | >>> import ast 158 | >>> ast.literal_eval("{'muffin' : 'lolz', 'foo' : 'kitty'}") 159 | {'muffin': 'lolz', 'foo': 'kitty'} 160 | 161 | 这个做法比直接eval更安全 162 | 帮助文档 163 | 164 | >>> help(ast.literal_eval) 165 | Help on function literal_eval in module ast: 166 | 167 | literal_eval(node_or_string) 168 | Safely evaluate an expression node or a string containing a Python 169 | expression. The string or node provided may only consist of the following 170 | Python literal structures: strings, numbers, tuples, lists, dicts, booleans, 171 | and None. 172 | 173 | 举例 174 | 175 | >>> eval("shutil.rmtree('mongo')") 176 | Traceback (most recent call last): 177 | File "", line 1, in 178 | File "", line 1, in 179 | File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 208, in rmtree 180 | onerror(os.listdir, path, sys.exc_info()) 181 | File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 206, in rmtree 182 | names = os.listdir(path) 183 | OSError: [Errno 2] No such file or directory: 'mongo' 184 | >>> ast.literal_eval("shutil.rmtree('mongo')") 185 | Traceback (most recent call last): 186 | File "", line 1, in 187 | File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 68, in literal_eval 188 | return _convert(node_or_string) 189 | File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 67, in _convert 190 | raise ValueError('malformed string') 191 | ValueError: malformed string 192 | 193 | ### 如何获取一个字符的ASCII码 194 | 195 | 问题 [链接](http://stackoverflow.com/questions/227459/ascii-value-of-a-character-in-python) 196 | 197 | >>> ord('a') 198 | 97 199 | >>> chr(97) 200 | 'a' 201 | >>> chr(ord('a') + 3) 202 | 'd' 203 | >>> 204 | 205 | 另外对于unicode 206 | 207 | >>> unichr(97) 208 | u'a' 209 | >>> unichr(1234) 210 | u'\u04d2' 211 | 212 | ### 如何使用不同分隔符切分字符串 213 | 214 | 问题 [链接](http://stackoverflow.com/questions/1059559/python-strings-split-with-multiple-separators) 215 | 216 | 使用re.split [文档](http://docs.python.org/2/library/re.html#re.split) 217 | 218 | >>> re.split('\W+', 'Words, words, words.') 219 | ['Words', 'words', 'words', ''] 220 | >>> re.split('(\W+)', 'Words, words, words.') 221 | ['Words', ', ', 'words', ', ', 'words', '.', ''] 222 | >>> re.split('\W+', 'Words, words, words.', 1) 223 | ['Words', 'words, words.']) 224 | 225 | 或者匹配获取正确的 re.findall 226 | 227 | import re 228 | DATA = "Hey, you - what are you doing here!?" 229 | print re.findall(r"[\w']+", DATA) 230 | # Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here'] 231 | 232 | ### 如何截掉空格(包括tab) 233 | 234 | 问题 [链接](http://stackoverflow.com/questions/1185524/how-to-trim-whitespace-including-tabs) 235 | 236 | 空白在字符串左右两边 237 | 238 | s = " \t a string example\t " 239 | s = s.strip() 240 | 241 | 空白在字符串右边 242 | 243 | s = s.rstrip() 244 | 245 | 左边 246 | 247 | s = s.lstrip() 248 | 249 | 另外你可以指定要截掉的字符作为参数 250 | 251 | s = s.strip(' \t\n\r') 252 | 253 | ### 如何截取一个字符串获得子串 254 | 255 | 问题 [链接](http://stackoverflow.com/questions/663171/is-there-a-way-to-substring-a-string-in-python) 256 | 257 | 258 | >>> x = "Hello World!" 259 | >>> x[2:] 260 | 'llo World!' 261 | >>> x[:2] 262 | 'He' 263 | >>> x[:-2] 264 | 'Hello Worl' 265 | >>> x[-2:] 266 | 'd!' 267 | >>> x[2:-2] 268 | 'llo Worl' 269 | 270 | python将这类操作称为切片,可以作用于序列类型,不仅仅是字符串 271 | 272 | ### python中用==比较字符串,is有时候会返回错误判断 273 | 274 | 问题 [链接](http://stackoverflow.com/questions/1504717/python-vs-is-comparing-strings-is-fails-sometimes-why) 275 | 276 | is是身份测试,==是相等测试 277 | 278 | >>> a = 'pub' 279 | >>> b = ''.join(['p', 'u', 'b']) 280 | >>> a == b 281 | True 282 | >>> a is b 283 | False' 284 | 285 | is 等价于 id(a) == id(b) 286 | 287 | ### 如何填充0到数字字符串中保证统一长度 288 | 289 | 问题 [链接](http://stackoverflow.com/questions/339007/python-nicest-way-to-pad-zeroes-to-string) 290 | 291 | 对于字符串 292 | 293 | >>> n = '4' 294 | >>> print n.zfill(3) 295 | >>> '004' 296 | 297 | 对于数字,[相关文档](http://docs.python.org/2/library/string.html#formatexamples) 298 | 299 | >>> n = 4 300 | >>> print '%03d' % n 301 | >>> 004 302 | >>> print "{0:03d}".format(4) # python >= 2.6 303 | >>> 004 304 | >>> print("{0:03d}".format(4)) # python 3 305 | >>> 004 306 | 307 | ### 如何将字符串转换为datetime 308 | 309 | 字符串 -> time [strptime](https://docs.python.org/2/library/time.html#time.strptime) 310 | 311 | >>> import time 312 | >>> time.strptime("30 Nov 00", "%d %b %y") 313 | time.struct_time(tm_year=2000, tm_mon=11, tm_mday=30, tm_hour=0, tm_min=0, 314 | tm_sec=0, tm_wday=3, tm_yday=335, tm_isdst=-1) 315 | 316 | time -> 字符串 [strftime](https://docs.python.org/2/library/time.html#time.strftime) 317 | 318 | >>> from time import gmtime, strftime 319 | >>> strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) 320 | 'Thu, 28 Jun 2001 14:17:15 +0000' 321 | 322 | 323 | ### 如何将byte array转为string 324 | 325 | 问题 [链接](http://stackoverflow.com/questions/606191/convert-byte-array-to-python-string) 326 | 327 | >>> b"abcde" 328 | b'abcde' 329 | >>> b"abcde".decode("utf-8") 330 | 'abcde' 331 | 332 | 333 | -------------------------------------------------------------------------------- /contents/qa-list.md: -------------------------------------------------------------------------------- 1 | ### 序列的切片操作 2 | 3 | 问题 [链接](http://stackoverflow.com/questions/509211/the-python-slice-notation) 4 | 5 | It's pretty simple really: 6 | 很简单: 7 | 8 | a[start:end] # start 到 end-1 9 | a[start:] # start 到 末尾 10 | a[:end] # 0 到 end-1 11 | a[:] # 整个列表的拷贝 12 | 13 | 还有一个step变量,控制步长,可在上面语法中使用 14 | 15 | a[start:end:step] # start through not past end, by step 16 | 17 | 18 | 注意,左闭右开 19 | 20 | 其他特点,开始或结束下标可能是负数,表示从序列末尾开始计算而非从头开始计算,所以 21 | 22 | a[-1] # 最后一个元素 23 | a[-2:] # 最后两个元素 24 | a[:-2] # 除了最后两个元素 25 | 26 | Python对程序员很友好,如果序列中存在的元素数量少于你要的,例如,你请求 a[:-2] 但是a只有一个元素,你会得到一个空列表,而不是一个错误.有时候你或许希望返回的是一个错误,所以你必须知道这点 27 | ### 判断一个列表为空得最佳实践 28 | 29 | 问题 [链接](http://stackoverflow.com/questions/53513/python-what-is-the-best-way-to-check-if-a-list-is-empty) 30 | 31 | 答案: 32 | 33 | if not a: 34 | print "List is empty" 35 | #不要用len(a)来判断 36 | 37 | ### 如何合并两个列表 38 | 39 | 问题 [链接](http://stackoverflow.com/questions/1720421/merge-two-lists-in-python) 40 | 41 | listone = [1,2,3] 42 | listtwo = [4,5,6] 43 | #outcome we expect: mergedlist == [1, 2, 3, 4, 5, 6] 44 | 45 | 1.不考虑顺序(原来问题不是很明确) 46 | 47 | listone + listtwo 48 | #linstone.extend(listtwo)也行,就是会修改listone 49 | 50 | 2.考虑顺序做些处理 51 | 52 | >>> listone = [1,2,3] 53 | >>> listtwo = [4,5,6] 54 | >>> import itertools 55 | >>> for item in itertools.chain(listone, listtwo): 56 | ... print item 57 | ... 58 | 1 59 | 2 60 | 3 61 | 4 62 | 5 63 | 6 64 | 65 | ### 如何获取一个列表的长度 66 | 67 | 问题 [链接](http://stackoverflow.com/questions/518021/getting-the-length-of-an-array-in-python) 68 | 69 | python中是不是只有这种方法可以获取长度?语法很奇怪 70 | 71 | arr.__len__() 72 | 73 | 应该使用这种方式 74 | 75 | mylist = [1,2,3,4,5] 76 | len(mylist) 77 | 78 | 这样做法,不需要对每个容器都定义一个.length()方法,你可以使用len()检查所有实现了__len__()方法的对象 79 | 80 | ### Python中如何复制一个列表 81 | 82 | 问题 [链接](http://stackoverflow.com/questions/2612802/how-to-clone-a-list-in-python) 83 | 84 | 可以用切片的方法 85 | 86 | new_list = old_list[:] 87 | 88 | 可以使用list()函数 89 | 90 | new_list = list(old_list) 91 | 92 | 可以使用copy.copy(),比list()稍慢,因为它首先去查询old_list的数据类型 93 | 94 | import copy 95 | new_list = copy.copy(old_list) 96 | 97 | 如果列表中包含对象,可以使用copy.deepcopy(), 所有方法中最慢,但有时候无法避免 98 | 99 | import copy 100 | new_list = copy.deepcopy(old_list) 101 | 102 | 例子: 103 | 104 | import copy 105 | 106 | class Foo(object): 107 | def __init__(self, val): 108 | self.val = val 109 | 110 | def __repr__(self): 111 | return str(self.val) 112 | 113 | foo = Foo(1) 114 | 115 | a = ['foo', foo] 116 | b = a[:] 117 | c = list(a) 118 | d = copy.copy(a) 119 | e = copy.deepcopy(a) 120 | 121 | # edit orignal list and instance 122 | a.append('baz') 123 | foo.val = 5 124 | 125 | print "original: %r\n slice: %r\n list(): %r\n copy: %r\n deepcopy: %r" \ 126 | % (a, b, c, d, e) 127 | 128 | 结果: 129 | 130 | original: ['foo', 5, 'baz'] 131 | slice: ['foo', 5] 132 | list(): ['foo', 5] 133 | copy: ['foo', 5] 134 | deepcopy: ['foo', 1] 135 | 136 | 效率简单比较 137 | 138 | 10.59 - copy.deepcopy(old_list) 139 | 10.16 - pure python Copy() method copying classes with deepcopy 140 | 1.488 - pure python Copy() method not copying classes (only dicts/lists/tuples) 141 | 0.325 - for item in old_list: new_list.append(item) 142 | 0.217 - [i for i in old_list] (a list comprehension) 143 | 0.186 - copy.copy(old_list) 144 | 0.075 - list(old_list) 145 | 0.053 - new_list = []; new_list.extend(old_list) 146 | 0.039 - old_list[:] (list slicing) 147 | 148 | ### 列表的append和extend的区别 149 | 150 | 问题 [链接](http://stackoverflow.com/questions/252703/python-append-vs-extend) 151 | 152 | >>> x = [1, 2] 153 | >>> x.append(3) 154 | >>> x 155 | [1, 2, 3] 156 | >>> x.append([4,5]) 157 | >>> x 158 | [1, 2, 3, [4, 5]] 159 | >>> 160 | >>> x = [1, 2, 3] 161 | >>> x.extend([4, 5]) 162 | >>> x 163 | [1, 2, 3, 4, 5] 164 | 165 | ### 如何随机地从列表中抽取变量 166 | 167 | 问题 [链接](http://stackoverflow.com/questions/306400/how-do-i-randomly-select-an-item-from-a-list-using-python) 168 | 169 | foo = ['a', 'b', 'c', 'd', 'e'] 170 | from random import choice 171 | print choice(foo) 172 | 173 | ### 如何利用下标从列表中删除一个元素 174 | 175 | 问题 [链接](http://stackoverflow.com/questions/627435/how-to-remove-an-element-from-a-list-by-index-in-python) 176 | 177 | 1.del 178 | 179 | In [9]: a = range(10) 180 | In [10]: a 181 | Out[10]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 182 | In [11]: del a[-1] 183 | In [12]: a 184 | Out[12]: [0, 1, 2, 3, 4, 5, 6, 7, 8] 185 | 186 | 2.pop 187 | 188 | a = ['a', 'b', 'c', 'd'] 189 | a.pop(1) 190 | # now a is ['a', 'c', 'd'] 191 | 192 | a = ['a', 'b', 'c', 'd'] 193 | a.pop() 194 | # now a is ['a', 'b', 'c'] 195 | 196 | ### 获取列表的最后一个元素 197 | 198 | 问题 [链接](http://stackoverflow.com/questions/930397/how-to-get-the-last-element-of-a-list) 199 | 200 | 囧 201 | 202 | result = l[-1] 203 | result = l.pop() 204 | 205 | ### 如何将一个列表切分成若干个长度相同的子序列 206 | 207 | 问题 [链接](http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python) 208 | 209 | 想要得到这样的效果 210 | 211 | l = range(1, 1000) 212 | print chunks(l, 10) -> [ [ 1..10 ], [ 11..20 ], .., [ 991..999 ] ] 213 | 214 | 使用yield: 215 | 216 | def chunks(l, n): 217 | """ Yield successive n-sized chunks from l. 218 | """ 219 | for i in xrange(0, len(l), n): 220 | yield l[i:i+n] 221 | list(chunks(range(10, 75), 10)) 222 | 223 | 直接处理 224 | 225 | def chunks(l, n): 226 | return [l[i:i+n] for i in range(0, len(l), n)] 227 | 228 | ### 如何删除一个list中重复的值同时保证原有顺序 229 | 230 | 问题 [链接](http://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order) 231 | 232 | 我是这么做的额 233 | 234 | def uniq(input): 235 | output = [] 236 | for x in input: 237 | if x not in output: 238 | output.append(x) 239 | return output 240 | 241 | 有什么更好的方法? 242 | 243 | 你可以在这里找到一些可用的方法 [入口](http://www.peterbe.com/plog/uniqifiers-benchmark) 244 | 245 | 最快的一个 246 | 247 | def f7(seq): 248 | seen = set() 249 | seen_add = seen.add 250 | return [ x for x in seq if x not in seen and not seen_add(x)] 251 | 252 | 为什么要建立一个到`seen.add`函数的引用`seen_add`,而不是直接调用`seen.add()`呢?Python是一个动态语言,如果使用`seen.add()`,迭代器每次都要解析`seen.add()`函数,相比直接调用一个局部变量`seen_add`会消耗更多资源。(评论问,为什么迭代器每次都要解析`seen.add()`)`seen.add()`可能会在每次迭代中可能会发生变化,而Python的Runtime没有智能到发现这一变化,因此安全起见,每次迭代过程中,迭代器都会重新检查这一对象。 253 | 254 | 如果你需要在同一个数据集中多次是哦那个这个方法,或许你可以使用ordered set处理 http://code.activestate.com/recipes/528878/ 255 | 256 | 插入,删除和归属判断复杂度都是O(1) 257 | 258 | ### 如何在遍历一个list时删除某些元素 259 | 260 | 问题 [链接](http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python) 261 | 262 | 使用列表解析 263 | 264 | somelist = [x for x in somelist if determine(x)] 265 | 266 | 上面那个操作将产生一个全新的somelist对象,而失去了对原有somelist对象的引用 267 | 268 | #在原有对象上进行修改 269 | somelist[:] = [x for x in somelist if determine(x)] 270 | 271 | 使用itertools 272 | 273 | from itertools import ifilterfalse 274 | somelist[:] = list(ifilterfalse(determine, somelist)) 275 | 276 | ### 如何获取list中包含某个元素所在的下标 277 | 278 | 问题 [链接](http://stackoverflow.com/questions/176918/in-python-how-do-i-find-the-index-of-an-item-given-a-list-containing-it) 279 | 280 | 281 | >>> ["foo","bar","baz"].index('bar') 282 | 1 283 | 284 | 参照 [文档](http://docs.python.org/2/tutorial/datastructures.html#more-on-lists) 285 | 286 | **注:** 这毫无疑问是最好的答案,但是千万注意.index()返回的是列表中**第一个**符合这个的元素。举个例子 `["foo", "bar", "baz", "bar"].index('bar')`返回的同样是 `1`. 287 | 288 | ### 如何扁平一个二维数组 289 | 290 | 问题 [链接](http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python) 291 | 292 | l = [[1,2,3],[4,5,6], [7], [8,9]] 293 | 变为[1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9] 294 | 295 | 列表解析 296 | 297 | [item for sublist in l for item in sublist] 298 | 299 | itertools 300 | 301 | >>> import itertools 302 | >>> list2d = [[1,2,3],[4,5,6], [7], [8,9]] 303 | >>> merged = list(itertools.chain(*list2d)) 304 | 305 | # python >= 2.6 306 | >>> import itertools 307 | >>> list2d = [[1,2,3],[4,5,6], [7], [8,9]] 308 | >>> merged = list(itertools.chain.from_iterable(list2d)) 309 | 310 | sum 311 | 312 | sum(l, []) 313 | 314 | 315 | ### 列表解析和map 316 | 317 | 问题 [链接](http://stackoverflow.com/questions/1247486/python-list-comprehension-vs-map) 318 | 319 | 更喜欢使用map()而不是列表解析的原因是什么? 320 | 321 | 322 | 在某些情况下,map性能更高一些(当你不是为了某些目的而使用lambda,而是在map和列表解析中使用相同函数). 323 | 324 | 列表解析在另一些情况下性能更好,并且大多数pythonistas认为这样更简洁直接 325 | 326 | 使用相同函数,略微优势 327 | 328 | $ python -mtimeit -s'xs=range(10)' 'map(hex, xs)' 329 | 100000 loops, best of 3: 4.86 usec per loop 330 | $ python -mtimeit -s'xs=range(10)' '[hex(x) for x in xs]' 331 | 100000 loops, best of 3: 5.58 usec per loop 332 | 333 | 相反情况,使用lambda 334 | 335 | $ python -mtimeit -s'xs=range(10)' 'map(lambda x: x+2, xs)' 336 | 100000 loops, best of 3: 4.24 usec per loop 337 | $ python -mtimeit -s'xs=range(10)' '[x+2 for x in xs]' 338 | 100000 loops, best of 3: 2.32 usec per loop 339 | 340 | ### 列表和元组有什么区别 341 | 342 | 问题[链接](http://stackoverflow.com/questions/626759/whats-the-difference-between-list-and-tuples) 343 | 344 | 除了元组是不可变的之外,还有一个语义的区别去控制它们的使用。元组是各种结构类型混杂的(比如,它们的入口有不同的含义),列表则是一致的序列。元组有结构,列表有顺序。 345 | 346 | 根据这种区别,刻意让代码更为明确和易理解。 347 | 348 | 用页数和行数来定义一本书中的位置的例子: 349 | 350 | my_location = (42, 11) # page number, line number 351 | 352 | 然后你可以在一个字典里把这个当做键保存位置的记录。然而列表可以用来存储多点定位。通常会想添加或移除一个列表中的某个定位,所以列表是可变的。另一方面,为了保持行数的完好无损,而改变页书的值似乎说不通,这很可能会给你一个新的定位。而且,可能有很完美的解决办法用来处理正确的行数(而不是替换所有的元组) 353 | 354 | 这一点,有很多有趣的文章,比如[”Python Tuples are Not Just Constant Lists”](http://jtauber.com/blog/2006/04/15/python_tuples_are_not_just_constant_lists/) or [“Understanding tuples vs. lists in Python”](http://news.e-scribe.com/397)。Python官方文档也提到了[“元组是不可变对象,并且用于包含哪些混杂的序列…”](https://docs.python.org/2/tutorial/datastructures.html#tuples-and-sequences)。 355 | 356 | 在一个动态类型语言比如haskell,元组通常有不同的类型,并且元组的长度必须是固定的。在列表中值必须是同一种类型,值长度不需要固定。所以区别很明显。 357 | 358 | 最后,Python中还有一个[nametuple](https://docs.python.org/dev/library/collections.html#collections.namedtuple),合理表示一个元组已经有的结构。这些突出的想法明确了元组是类和实例的一种轻型的替换。 359 | 360 | ### Python 2.7里[...]是什么? 361 | 362 | 我在IDLE中输入了这段代码: 363 | 364 | p = [1, 2] 365 | p[1:1] = [p] 366 | print p 367 | 368 | 其输出为: 369 | 370 | [1, [...], 2] 371 | 372 | 这里的`[...]`是什么意思,有趣的是,这似乎是一个无限层次的列表的列表的列表,比如: 373 | 374 | p[1][1][1].... 375 | 376 | 问题[链接](http://stackoverflow.com/questions/17160162/what-is-in-python-2-7) 377 | 378 | 它意味着你在它的内部创建了一个无限嵌套的不能打印的列表。`p`包含一个包含`p`的`p`...等等。`[...]`就是一种让你知道问题的标记,为了通告信息,它不能被而代表。看一下@6502的答案,那些展示了发生什么的优秀的图片。 379 | 380 | 现在,关于之后你编辑的三个问题: 381 | 382 | * 这个[答案](http://stackoverflow.com/questions/7674685/whats-exactly-happening-in-infinite-nested-lists/7680125#7680125)看上去已经覆盖它了 383 | 384 | * Ignacio的[链接](http://www.csse.monash.edu.au/~lloyd/tildeFP/1993ACJ/)描述了一些可能的用法 385 | 386 | * 这更像是一种数据结构设计的话题而不是编程语言,所以很不幸,你不能在Python的官方文档找到任何参考 387 | 388 | 以下是@0562的部分回答: 389 | 390 | 你创建了一个如下的结构: 391 | 392 | ![Struct](http://i.stack.imgur.com/mUnTM.png "Struct") 393 | 394 | 这个列表的第一个和最后一个元素指向两个数字(1和2),其中间的元素是指向自己。 395 | -------------------------------------------------------------------------------- /contents/qa-others.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### 应该在学习Python3之前学习Python2,还是直接学习Python3 4 | 5 | 问题 [链接](http://stackoverflow.com/questions/170921/should-i-learn-python-2-before-3-or-start-directly-from-python-3) 6 | 7 | 你可以从python2开始,2和3主要的语法格式和风格相同 8 | 9 | 3要替代2不是短时间内能完成的,将会是一个很长的过程,所以学习Python2并没有什么坏处 10 | 11 | 我建议你关注下2和3的不同之处 [This slides gives you a quick introduction of the changes in Python 2 and 3](http://stackoverflow.com/questions/170921/should-i-learn-python-2-before-3-or-start-directly-from-python-3) 12 | 13 | 14 | 15 | 16 | 17 | ### 在virtualenv中如何使用不同的python版本 18 | 19 | 问题 [链接](http://stackoverflow.com/questions/1534210/use-different-python-version-with-virtualenv) 20 | 21 | 在创建virtualenv实例时,使用-p选项 22 | 23 | virtualenv -p /usr/bin/python2.6 24 | 25 | ### 如何离开virtualenv 26 | 27 | 问题 [链接](http://stackoverflow.com/questions/990754/how-to-leave-a-python-virtualenv) 28 | 29 | 使用virtualenv时 30 | 31 | me@mymachine:~$ workon env1 32 | (env1)me@mymachine:~$ workon env2 33 | (env2)me@mymachine:~$ workon env1 34 | (env1)me@mymachine:~$ 35 | 36 | 如何退出某个环境 37 | 38 | $ deactivate 39 | 40 | ### Python中什么项目结构更好 41 | 42 | 问题 [链接](http://stackoverflow.com/questions/193161/what-is-the-best-project-structure-for-a-python-application) 43 | 44 | 假设你要开发一个较大的客户端程序(非web端),如何组织项目目录和递归? 45 | 46 | 47 | 不要太在意这个.按你高兴的方式组织就行.Python项目很简单,所以没有那么多愚蠢的规则 48 | 49 | /scripts or /bin 命令行脚本 50 | /tests 测试 51 | /lib C-语言包 52 | /doc 文档 53 | /apidoc api文档 54 | 55 | 并且顶层目录包含README和Config 56 | 57 | 难以抉择的是,是否使用/src树. /src,/lib,/bin在Python中没有明显的区别,和Java/c不同 58 | 59 | 因为顶层/src文件夹显得没有什么实际意义,你的顶层目录可以是程序顶层架构的目录 60 | 61 | /foo 62 | /bar 63 | /baz 64 | 65 | 我建议将这些文件放入到"模块名"的目录中,这样,如果你在写一个应用叫做quux, /quux目录将包含所有这些东西 66 | 67 | 你可以在PYTHONPATH中加入 /path/to/quux/foo,这样你可以QUUX.foo中重用模块 68 | 69 | 70 | 另一个回答 71 | 72 | Project/ 73 | |-- bin/ 74 | | |-- project 75 | | 76 | |-- project/ 77 | | |-- test/ 78 | | | |-- __init__.py 79 | | | |-- test_main.py 80 | | | 81 | | |-- __init__.py 82 | | |-- main.py 83 | | 84 | |-- setup.py 85 | |-- README 86 | 87 | 88 | ### 在Python中使用Counter错误 89 | 90 | 问题 [链接](http://stackoverflow.com/questions/13311094/counter-in-collections-module-python) 91 | 92 | 当使用Counter时,出现异常 93 | 94 | AttributeError: 'module' object has no attribute 'Counter' 95 | 96 | from collections import Counter 97 | ImportError: cannot import name Counter 98 | 99 | 原因: 100 | 101 | 版本问题,Counter在 python2.7中才被加入到这个模块,你可能使用了Python2.6或更老的版本 102 | 103 | 可以看下 [文档](http://docs.python.org/2/library/collections.html#collections.Counter) 104 | 105 | 如果要在 Python2.6或2.5版本使用,可以看 [这里](http://code.activestate.com/recipes/576611-counter-class/) 106 | 107 | 108 | ### 在Python中如何连接mysql数据库 109 | 110 | 问题 [链接](http://stackoverflow.com/questions/372885/how-do-i-connect-to-a-mysql-database-in-python) 111 | 112 | 首先,安装mysqldb 113 | 114 | 然后 115 | 116 | #!/usr/bin/python 117 | import MySQLdb 118 | 119 | db = MySQLdb.connect(host="localhost", # your host, usually localhost 120 | user="john", # your username 121 | passwd="megajonhy", # your password 122 | db="jonhydb") # name of the data base 123 | 124 | # you must create a Cursor object. It will let 125 | # you execute all the queries you need 126 | cur = db.cursor() 127 | 128 | # Use all the SQL you like 129 | cur.execute("SELECT * FROM YOUR_TABLE_NAME") 130 | 131 | # print all the first cell of all the rows 132 | for row in cur.fetchall() : 133 | print row[0] 134 | 135 | ### Python框架flask和bottle有什么区别 136 | 137 | 问题 [链接](http://stackoverflow.com/questions/4941145/python-flask-vs-bottle) 138 | 139 | 区别:flask基于其他现有的存在很长一段时间的技术像Werkzeug和Jinja2,它没有尝试去重复发明轮子 140 | 141 | 另外一方面,Bottle,试图用一个文件解决一切. 142 | 143 | 我想去合并他们,但是Bottle的开发者貌似对偏离“一个文件”的处理方式不是很感兴趣 144 | 145 | 关于可扩展性: 可以使用其他模板引擎,例如Flask-Genshi使用了mako模板 146 | 147 | Flask, Werkzeug and Jinja2 的开发者亲自回答的...碉堡了,翻译不是很准确 148 | 149 | 150 | ### 如何测试一个python脚本的性能 151 | 152 | 问题 [链接](http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script) 153 | 154 | 155 | 引入 156 | 157 | import cProfile 158 | cProfile.run('foo()') 159 | 160 | 执行脚本 161 | 162 | python -m cProfile myscript.py 163 | 164 | 结果 165 | 166 | 1007 function calls in 0.061 CPU seconds 167 | 168 | Ordered by: standard name 169 | ncalls tottime percall cumtime percall filename:lineno(function) 170 | 1 0.000 0.000 0.061 0.061 :1() 171 | 1000 0.051 0.000 0.051 0.000 euler048.py:2() 172 | 1 0.005 0.005 0.061 0.061 euler048.py:2() 173 | 1 0.000 0.000 0.061 0.061 {execfile} 174 | 1 0.002 0.002 0.053 0.053 {map} 175 | 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler objects} 176 | 1 0.000 0.000 0.000 0.000 {range} 177 | 1 0.003 0.003 0.003 0.003 {sum} 178 | 179 | 一个PyCon演讲 [入口](http://blip.tv/pycon-us-videos-2009-2010-2011/introduction-to-python-profiling-1966784) 180 | 181 | 182 | ### 如何获取5分钟之后的unix时间戳 183 | 184 | 问题 [链接](http://stackoverflow.com/questions/2775864/python-create-unix-timestamp-five-minutes-in-the-future) 185 | 186 | 使用 [calendar.timegm](http://docs.python.org/3.3/library/calendar.html#calendar.timegm) 187 | 188 | future = datetime.datetime.now() + datetime.timedelta(minutes = 5) 189 | return calendar.timegm(future.utctimetuple()) 190 | 191 | strftime的%s在windows中无法使用 192 | 193 | 194 | 195 | ### 在python中如何调用外部命令? 196 | 197 | 问题 [链接](http://stackoverflow.com/questions/89228/calling-an-external-command-in-python) 198 | 199 | Look at the subprocess module in the stdlib: 200 | 201 | 可以看下标准库中的 [subprocess](http://docs.python.org/library/subprocess.html) 202 | 203 | from subprocess import call 204 | call(["ls", "-l"]) 205 | 206 | subprocess相对于system的好处是, 更灵活 207 | 208 | 但是 quick/dirty/one time scripts, os.system is enough 209 | 210 | ### 用Python在终端打印出有颜色的文字? 211 | 212 | 问题[链接](http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python) 213 | 214 | 某种程度上这取决于你使用的平台。通常的方法是用ANSI转义序列。举个简单的例子,这有一些来自[blender build scripts](https://svn.blender.org/svnroot/bf-blender/trunk/blender/build_files/scons/tools/bcolors.py)的代码: 215 | 216 | class bcolors: 217 | HEADER = '\033[95m' 218 | OKBLUE = '\033[94m' 219 | OKGREEN = '\033[92m' 220 | WARNING = '\033[93m' 221 | FAIL = '\033[91m' 222 | ENDC = '\033[0m' 223 | 224 | 为了使用上面那种代码,你应该这样做: 225 | 226 | print bcolors.WARNING + "Warning: No active frommets remain. Continue?" 227 | + bcolors.ENDC 228 | 229 | 这在unixes包括OS X,linux和windows(为你提供[enable ansi.sys](http://support.microsoft.com/kb/101875))上会生效。有ansi代码来设置颜色,移动光标,做更多事情。 230 | 231 | 如果你想了解更为复杂的内容(这听上去好像你正在写一款游戏),你应该深入“cursor”这个没款,它会为你处理很多复杂的部分。[Python Curses HowTO](https://docs.python.org/2/howto/curses.html)是一篇很好的介绍。 232 | 233 | 如果你是用的不是ASCII(或者说你没有用PC),你面对诸如ascii字符低于127,’#’,‘@’可能是你得到空格的最好的赌注。如果你确定你的终端使用IBM [extended ascii character set](http://telecom.tbi.net/asc-ibm.html),你将会有更多的选择,字符176,字符177,字符178,和字符219代表”空格字符”。 234 | 235 | 一些流行的基于文本的程序,比如”Dwarf Fortress”,仿照文本的模式做成了图形模式,使用传统PC的字体图片。你可以在[Dwarf Frotress Wiki](http://dwarffortresswiki.org/DF2014:Tilesets)找一些这种点阵图看看([user-made tilesets](http://dwarffortresswiki.org/Tileset_repository))。 236 | 237 | [Text Mode Demo Contest](http://en.wikipedia.org/wiki/TMDC)有更多把图片处理成文本的源码。 238 | 239 | 嗯...我想这个问题被我扯远了。尽管我现在纠结着去做一款基于文本的史诗冒险游戏。在有颜色的文本这方面,祝你好运。 240 | 241 | ### 我该如何保护我的Python代码 242 | 243 | Python作为字节码编译的解释型语言,是很难封闭的。几遍你使用一种exe包比如[py2exe](http://py2exe.org/),可执行文件的结构依然是清晰可见的,而且Python的字节编码是非常易懂的。 244 | 245 | 通常是这样,你必须要想出一个折衷的办法。保护代码究竟重不重要。里面是不是有很私密的东西(比如银行的对称加密秘钥),或者你是一个偏执狂。选择一门可以让你更快速开发优秀产品的语言,对于你的奇特想法从现实主义考虑一下它的价值。 246 | 247 | 如果你确定使用要强制授权保证安全,可以写一个小的C拓展,那么这个授权检验就会变得很难逆转(但不是完全不可能)。然后把你的大批代码放进Python。 248 | 249 | ### 首选的Python单元测试框架 250 | 251 | 问题[链接](http://stackoverflow.com/questions/191673/preferred-python-unit-testing-framework) 252 | 253 | `nose`实际上不是一个单元测试的框架。它是一个测试的执行器,并且是最好的一款。它可以运行通过`pyUnit`,`py.test`和`doctest`创建的测试。 254 | 255 | 我首选的单元测试框架是pyUnit。它和其他xUnit框架一样,而且可以让没有Python基础的人很好上手。而且它对Eclipse/PyDev提供非常好的支持。 256 | 257 | 在`py.test`中,我发现了很多层级的安装/卸载混淆在一起。我还发现它生成了很多非常无组织和难阅读的单元测试。 258 | 259 | `doctest`对于简单的东西来说还好,但是它很有限,不能真正的用来测试复杂和交互的代码。 260 | 261 | ### Python的单元测试放在哪? 262 | 263 | 问题[链接](http://stackoverflow.com/questions/61151/where-do-the-python-unit-tests-go) 264 | 265 | 对于一个文件`module.py`来说,单元测试通常叫做`test_module.py`,遵循Python的命名规则。 266 | 267 | 在以下几种地方放置`test_module.py`都是可以接受的: 268 | 269 | 1. 和`module.py`放在同一个文件夹。 270 | 271 | 2. 在`../tests/test_module.py`(与代码文件夹的同级) 272 | 273 | 3. 在`tests/test_module.py` (在代码文件夹下的同层) 274 | 275 | 我倾向第一种方法,它可以更直观的被找到并且引入。不管你在使用什么样的开发系统,你都可以轻松的配置并找到以`test_`开头的文件。实际上,方便查找的缺省的单元测试模型是`test*.py`。 276 | 277 | ### distribute, distutils, setuptools和distutils2的区别 278 | 279 | 问题[链接](http://stackoverflow.com/questions/6344076/differences-between-distribute-distutils-setuptools-and-distutils2) 280 | 281 | 到2014年9月,所有其他回答的时间都超过一年了。当你寻求Python打包的建议时,记得看一下发布的日期,而且不要相信过时的信息。 282 | 283 | 这篇搭建在Readthedocs的文章[Python Packaging User Guide](http://stackoverflow.com/questions/6344076/differences-between-distribute-distutils-setuptools-and-distutils2)值得一读。每一页都有一个最近时间展示,所以你可以检查最新的手册,而且它相当的全面。Python 3.4的官方文档已经从信任的角度把这个链接加进来了。 284 | 285 | 工具的总结: 286 | 287 | 这里有一个2014年9月份的Python打包总结: 288 | 289 | * **Distutils** is still the standard tool for packaging in Python. It is included in the standard library (Python 2 and Python 3.0 to 3.4). It is useful for simple Python distributions, but lacks features. It introduces the distutils Python package that can be imported in your setup.py script. 290 | 291 | * **Setuptools** was developed to overcome Distutils' limitations, and is not included in the standard library. It introduced a command-line utility called easy_install. It also introduced the setuptools Python package that can be imported in your setup.py script, and the pkg_resources Python package that can be imported in your code to locate data files installed with a distribution. One of its gotchas is that it monkey-patches the distutils Python package. It should work well with pip. The latest version was released in August 2014. 292 | 293 | * **Distribute** was a fork of Setuptools. It shared the same namespace, so if you had Distribute installed, import setuptools would actually import the package distributed with Distribute. Distribute was merged back into Setuptools 0.7, so you don't need to use Distribute any more. In fact, the version on Pypi is just a compatibility layer that installs Setuptools. 294 | 295 | * **Distutils2** was an attempt to take the best of Distutils, Setuptools and Distribute and become the standard tool included in Python's standard library. The idea was that Distutils2 would be distributed for old Python versions, and that Distutils2 would be renamed to packaging for Python 3.3, which would include it in its standard library. These plans did not go as intended, however, and currently, Distutils2 is an abandoned project. The latest release was in March 2012, and its Pypi home page has finally been updated to reflect its death. 296 | 297 | * **Distlib** is a tool that aims to implement a subset of the previous tools' functionality, but only functionality that is very well-defined in accepted PEPs. It should hopefully be included eventually in the Python standard library. It is still being developed and is not recommended for end-users yet. 298 | 299 | * **Bento** is a packaging solution designed to replace Distutils, Setuptools, Distribute and Distutils2, written from the ground up. Its primary developer is also a core developer of numpy/scipy, so he's familiar with non-simple use-cases for packaging systems. Its first commit was in October 2009, and the latest commit as of writing was in August 2014, although the authors are not updating its Pypi page correspondingly. It's in active development but it is not mature yet, and it is not as widely known as Setuptools yet. 300 | 301 | 推荐: 302 | 303 | 所以综上所述,排除所有这些选项,我回推荐 **Setuptools**,除非你的需求非常基础,那么你可能只需要 Distutils。Setuptools在Virtualenv和Pip上的表现非常好,我强烈推荐。 304 | 305 | 作为一个边注,我建议使用Virtualenv1.10或者更高的版本,因为对Python2或3来说,它是第一个识别Setuptools/Distribute并合并的版本。 306 | -------------------------------------------------------------------------------- /contents/qa-func.md: -------------------------------------------------------------------------------- 1 | 2 | ### 如何获取一个函数的函数名字符串 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/251464/how-to-get-the-function-name-as-string-in-python) 5 | 6 | my_function.__name__ 7 | >>> import time 8 | >>> time.time.__name__ 9 | 'time' 10 | ### 用函数名字符串调用一个函数 11 | 12 | 问题 [链接](http://stackoverflow.com/questions/3061/calling-a-function-from-a-string-with-the-functions-name-in-python) 13 | 14 | 假设模块foo有函数bar: 15 | 16 | import foo 17 | methodToCall = getattr(foo, 'bar') 18 | result = methodToCall() 19 | 20 | 或者一行搞定 21 | 22 | result = getattr(foo, 'bar')() 23 | 24 | 25 | ### Python中\*\*和\*的作用 26 | 27 | 问题 [链接](http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters) 28 | 29 | 30 | \*args和\*\*kwargs允许函数拥有任意数量的参数,具体可以查看 [more on defining functions](http://docs.python.org/dev/tutorial/controlflow.html#more-on-defining-functions) 31 | 32 | *args将函数所有参数转为序列 33 | 34 | In [1]: def foo(*args): 35 | ...: for a in args: 36 | ...: print a 37 | ...: 38 | ...: 39 | 40 | In [2]: foo(1) 41 | 1 42 | 43 | 44 | In [4]: foo(1,2,3) 45 | 1 46 | 2 47 | 3 48 | 49 | **kwargs 将函数所有关键字参数转为一个字典 50 | 51 | In [5]: def bar(**kwargs): 52 | ...: for a in kwargs: 53 | ...: print a, kwargs[a] 54 | ...: 55 | ...: 56 | 57 | In [6]: bar(name="one", age=27) 58 | age 27 59 | name one 60 | 61 | 两种用法可以组合使用 62 | 63 | def foo(kind, *args, **kwargs): 64 | pass 65 | 66 | *l的另一个用法是用于函数调用时的参数列表解包(unpack) 67 | 68 | In [9]: def foo(bar, lee): 69 | ...: print bar, lee 70 | ...: 71 | ...: 72 | 73 | In [10]: l = [1,2] 74 | 75 | In [11]: foo(*l) 76 | 1 2 77 | 78 | 在Python3.0中,可以将*l放在等号左边用于赋值 [Extended Iterable Unpacking](http://www.python.org/dev/peps/pep-3132/) 79 | 80 | first, *rest = [1,2,3,4] 81 | first, *l, last = [1,2,3,4] 82 | 83 | ### 在Python中使用\*\*kwargs的合适方法 84 | 85 | 问题 [链接](http://stackoverflow.com/questions/1098549/proper-way-to-use-kwargs-in-python) 86 | 87 | 当存在默认值的时候,如何合适的使用**kwargs? 88 | 89 | kwargs返回一个字典,但是这是不是设置默认值的最佳方式?还是有其他方式?我只能将其作为一个字典接受,然后用get函数获取参数? 90 | 91 | class ExampleClass: 92 | def __init__(self, **kwargs): 93 | self.val = kwargs['val'] 94 | self.val2 = kwargs.get('val2') 95 | 96 | 问题很简单,但是我没找到合适的解释。我见到人们用不同的方式实现,很难搞明白如何使用 97 | 98 | 回答 99 | 100 | 你可以用get函数给不在字典中的key传递一个默认值 101 | 102 | self.val2 = kwargs.get('val2',"default value") 103 | 104 | 但是,如果你计划给一个特别的参数赋默认值,为什么不在前一个位置使用命名参数? 105 | 106 | def __init__(self, val2="default value", **kwargs): 107 | 108 | <<<<<<< HEAD 109 | ### 构造一个基本的Python迭代器 110 | 111 | - 问题 112 | [链接](http://stackoverflow.com/questions/19151/build-a-basic-python-iterator) 113 | 114 | - 回答 115 | 116 | 117 | python中的迭代器对象遵守迭代器协议,也就意味着python会提供两个方法:__iter__() 和 next().方法__iter__ 返回迭代器对象并且在循环开始时隐含调用.方法next()返回下一个值并且在每次循环中隐含调用.方法next()在没有任何值可返回时,抛出StopIteration异常.之后被循环构造器捕捉到而停止迭代. 118 | 119 | 下面是简单的计数器例子: 120 | ```python 121 | class Counter: 122 | def __init__(self, low, high): 123 | self.current = low 124 | self.high = high 125 | 126 | def __iter__(self): 127 | return self 128 | 129 | def next(self): # Python 3: def __next__(self) 130 | if self.current > self.high: 131 | raise StopIteration 132 | else: 133 | self.current += 1 134 | return self.current - 1 135 | 136 | 137 | for c in Counter(3, 8): 138 | print c 139 | ``` 140 | 输出: 141 | ```python 142 | 3 143 | 4 144 | 5 145 | 6 146 | 7 147 | 8 148 | ``` 149 | 150 | 使用生成器会更简单,包含了先前的回答: 151 | ```python 152 | def counter(low, high): 153 | current = low 154 | while current <= high: 155 | yield current 156 | current += 1 157 | 158 | for c in counter(3, 8): 159 | print c 160 | ``` 161 | 162 | 输出是一样的.本质上说,生成器对象支持迭代协议并且大致完成和计数器类相同的事情. 163 | 164 | David Mertz的文章, [Iterators and Simple Generators](http://www.ibm.com/developerworks/library/l-pycon.html),是一个非常不错的介绍. 165 | 166 | ### \*args和\*\*kwargs是什么 167 | 问题[链接](http://stackoverflow.com/questions/3394835/args-and-kwargs) 168 | 169 | 真正的语法是`*`和`**`,`*args`和`**kwargs`这两个名字只是约定俗成的,但并没有硬性的规定一定要使用它们。 170 | 171 | 当你不确定有多少个参数会被传进你的函数时,你可能会使用`*args`,也就是说它允许你给你的函数传递任意数量的参数,举个例子: 172 | 173 | >>> def print_everything(*args): 174 | for count, thing in enumerate(args): 175 | … print ‘{0}. {1}’.format(count, thing) 176 | … 177 | >>> print_everthing(‘apple’, ‘banana’, ‘cabbage’) 178 | 0. apple 179 | 1. banana 180 | 2. cabbage 181 | 182 | 类似的,`**kwargs`允许你处理那些你没有预先定义好的已命名参数 183 | 184 | >>> def table_everything(*kwargs): 185 | for name, value in kwargs.items(): 186 | … print ‘{0} = {1}’.format(name, value) 187 | … 188 | >>> table_everthing(apple = ‘fruit’, cabbage = ‘vegetable’) 189 | cabbage = vegetable 190 | apple = fruit 191 | 192 | 你一样可以使用这些命名参数。明确的参数会优先获得值,剩下的都会传递给`*args`和`**kwargs`,命名参数排在参数列表前面,举个例子: 193 | 194 | def table_things(titlestring, **kwargs) 195 | 196 | 你可以同时使用它们,但是`*args`必须出现在`**kwargs`之前。 197 | 198 | 调用一个函数时也可以用`*`和`**`语法,举个例子: 199 | 200 | >>> def print_three_things(*args): 201 | … print ‘a = {0}, b = {1}, c = {2}’.format(a, b , c) 202 | … 203 | >>> mylist = [‘aardvark’, ‘baboon’, ‘cat’] 204 | >>> print_three_things(*mylist) 205 | a = aardvark, b = baboon, c = cat 206 | 207 | 正如你看到的,它得到了一个list或者tuple,并解包这个list。通过这种方法,它将这些元素和函数中的参数匹配。当然,你可以同时在函数的定义和调用时使用`*`。 208 | 209 | 210 | ### 在Python中,如何干净、pythonic的实现一个复合构造函数 211 | 212 | 问题[链接](http://stackoverflow.com/questions/682504/what-is-a-clean-pythonic-way-to-have-multiple-constructors-in-python) 213 | 214 | 实际上 `None`比“魔法”值好多了: 215 | 216 | class Cheese(): 217 | def __init__(self, num_holes = None): 218 | if (num_holes is None): 219 | … 220 | 221 | 现在如果你想完全自由地添加更多参数: 222 | 223 | class Cheese(): 224 | def __init__(self, *args, **kwargs): 225 | #args -- tuple of anonymous arguments 226 | #kwargs -- dictionary of named arguments 227 | self.num_holes = kwargs.get('num_holes',random_holes()) 228 | 229 | 为了更好的解释`*args`和`**kwargs`的概念(实际上你可以修改它们的名字): 230 | 231 | def f(*args, **kwargs): 232 | print 'args: ', args, ' kwargs: ', kwargs 233 | 234 | >>> f('a') 235 | args: ('a',) kwargs: {} 236 | >>> f(ar='a') 237 | args: () kwargs: {'ar': 'a'} 238 | >>> f(1,2,param=3) 239 | args: (1, 2) kwargs: {'param': 3} 240 | 241 | [http://docs.python.org/reference/expressions.html#calls](http://docs.python.org/reference/expressions.html#calls) 242 | 243 | ### Python参数中,\*\*和\*是干什么的 244 | 245 | 问题[链接](http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters) 246 | 247 | `*args`和`**args`是一种惯用的方法,允许不定数量的参数传入函数,在Python文档中有描述[more on defining functions](https://docs.python.org/dev/tutorial/controlflow.html#more-on-defining-functions) 248 | 249 | `*args`会把所有的参数当做一个列表传递: 250 | 251 | In [1]: def foo(*args): 252 | ...: for a in args: 253 | ...: print a 254 | ...: 255 | ...: 256 | 257 | In [2]: foo(1) 258 | 1 259 | 260 | 261 | In [4]: foo(1,2,3) 262 | 1 263 | 2 264 | 3 265 | 266 | `**kwargs`会把除了那些符合形参的参数作为一个字典传递: 267 | 268 | In [5]: def bar(**kwargs): 269 | ...: for a in kwargs: 270 | ...: print a, kwargs[a] 271 | ...: 272 | ...: 273 | 274 | In [6]: bar(name="one", age=27) 275 | age 27 276 | name one 277 | 278 | 这两种用法都可以混合进普通参数,允许传入一组固定的的和可变的参数: 279 | 280 | def foo(kind, *args, **kwargs): 281 | pass 282 | 283 | 另一种\*的用法就是在调用一个函数的时候解包参数列表 284 | 285 | In [9]: def foo(bar, lee): 286 | ...: print bar, lee 287 | ...: 288 | ...: 289 | 290 | In [10]: l = [1,2] 291 | 292 | In [11]: foo(*l) 293 | 1 2 294 | 295 | 在Python 3中,可以把\*用在一个待赋值对象的左边([Extended Iterable Upacking](https://www.python.org/dev/peps/pep-3132/)): 296 | 297 | first, *rest = [1, 2, 3, 4] 298 | first, *l, last = [1, 2, 3, 4] 299 | 300 | ### 为什么在Python的函数中,代码运行速度更快 301 | 302 | 问题[链接](http://stackoverflow.com/questions/11241523/why-does-python-code-run-faster-in-a-function) 303 | 304 | 你可能要问为什么在存储在本地变量的比全局变量运行速度更快。这是一个CPython执行细节。 305 | 306 | 记住Cpython在解释器运行时,是编译成字节编码的。当一个函数编译完成,本地变量就全部被存储在一个固定长度的数组中了(而不是字典)而且名字被指定了索引。这是合理的,因为你不能自动添加本地变量到你的函数中去。在指针中循环检索一个本地变量加入到列表中,并且计算琐碎的`PyObject`的增加。 307 | 308 | 不同的是全局查找(`LOAD_GLOBAL`),是一个涉及哈希查找的字典等等。顺带的,这就是为什么当你需要一个全局变量时,要说明`global i`。如果你曾经在一个范围内给一个变量赋值了,那么编译器会为它的入口发布一些`STORE_FAST`。除非你告诉它不要这样做。 309 | 310 | 顺便说一句,全局查找仍然是非常棒的。属性查找`foo.bar`是非常慢的。 311 | 312 | ### 如果把一个变量作为引用传入 313 | 314 | 问题[链接](http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) 315 | 316 | 问题出在[pass by assignment](https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference)。它背后的原理可以分为两部分: 317 | 318 | 1、 传入的参数实际上是一个对象的引用(但是引用的是值) 319 | 320 | 2、 有些数据类型是可变的的,有些不是 321 | 322 | 所以 323 | 324 | - 如果你向方法中传递了一个可变的对象,那么方法得到了这些对象的一个引用,只要你开心,就可以随意改变它。但是如果你在方法中重新定义了引用,外部是不知道的,所以当你改变了它,其他的引用仍然指向根对象。 325 | 326 | - 如果你向方法中传递了一个不可变对象,那么你不会重新定义外部的引用,你甚至不能改变对象。 327 | 328 | 我们做一些示例,让它们更清晰。 329 | 330 | **列表-一种可变类型** 331 | 332 | 我们试着去修改传入方法中的列表: 333 | 334 | def try_to_change_list_contents(the_list): 335 | print 'got', the_list 336 | the_list.append('four') 337 | print 'changed to', the_list 338 | 339 | outer_list = ['one', 'two', 'three'] 340 | 341 | print 'before, outer_list =', outer_list 342 | try_to_change_list_contents(outer_list) 343 | print 'after, outer_list =', outer_list 344 | 345 | 输出: 346 | 347 | before, outer_list = ['one', 'two', 'three'] 348 | got ['one', 'two', 'three'] 349 | changed to ['one', 'two', 'three', 'four'] 350 | after, outer_list = ['one', 'two', 'three', 'four'] 351 | 352 | 一个参数传入的是`outer_list`的一个引用,而不是它的复制,我们可以使用改变列表的方法去改变它,并且把改变反馈给其他的范围。 353 | 354 | 现在让我们看一下当我们试着改变这个作为参数传入的引用: 355 | 356 | def try_to_change_list_reference(the_list): 357 | print 'got', the_list 358 | the_list = ['and', 'we', 'can', 'not', 'lie'] 359 | print 'set to', the_list 360 | 361 | outer_list = ['we', 'like', 'proper', 'English'] 362 | 363 | print 'before, outer_list =', outer_list 364 | try_to_change_list_reference(outer_list) 365 | print 'after, outer_list =', outer_list 366 | 367 | 输出: 368 | 369 | before, outer_list = ['we', 'like', 'proper', 'English'] 370 | got ['we', 'like', 'proper', 'English'] 371 | set to ['and', 'we', 'can', 'not', 'lie'] 372 | after, outer_list = ['we', 'like', 'proper', 'English'] 373 | 374 | `the_list`参数传递的是值,重新定义一个新的列表,对于方法外部的代码,没有任何影响。`the_list`只是`outer_list`的一个引用,我们让`the_list`指向了一个新的列表,但是我们没有办法修改`outer_list`的指向。 375 | 376 | **字符串-不可变类型** 377 | 378 | 它是不可变的,所以我们没有办法改变字符串的内容。 379 | 380 | 我们试着改变一下引用。 381 | 382 | def try_to_change_string_reference(the_string): 383 | print 'got', the_string 384 | the_string = 'In a kingdom by the sea' 385 | print 'set to', the_string 386 | 387 | outer_string = 'It was many and many a year ago' 388 | 389 | print 'before, outer_string =', outer_string 390 | try_to_change_string_reference(outer_string) 391 | print 'after, outer_string =', outer_string 392 | 393 | 输出: 394 | 395 | before, outer_string = It was many and many a year ago 396 | got It was many and many a year ago 397 | set to In a kingdom by the sea 398 | after, outer_string = It was many and many a year ago 399 | 400 | 再一次,`the_string`参数通过值传递,定义一个新的字符串对于外部的代码是不起作用的。`the_string`是`outer_string`的一个引用的复制,我们把`the_string`指向了一个新的字符串。但是我们并没有改变`outer_string`的指向。 401 | 402 | 我希望这样说可以让事情看上去简单一些了。 403 | 404 | 编辑:被标记了,这并没有回答@David主要想问的问题。“有没有什么办法让我传入的值是真实的引用?“。回答一下。 405 | 406 | **我们怎么避免这些?** 407 | 408 | 像@Andrea的我回答所展示的,你可以返回一个新的值。这不会改变传入的值,但是确实可以让你得到你想要输出的信息: 409 | 410 | def return_a_whole_new_string(the_string): 411 | new_string = something_to_do_with_the_old_string(the_string) 412 | return new_string 413 | 414 | # then you could call it like 415 | my_string = return_a_whole_new_string(my_string) 416 | 417 | 如果你确实想避免使用一个返回的值,你可以创建一个类承载你的值,并把他传入一个函数或者用一个已知的类,像列表一样: 418 | 419 | def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change): 420 | new_string = something_to_do_with_the_old_string(stuff_to_change[0]) 421 | stuff_to_change[0] = new_string 422 | 423 | # then you could call it like 424 | wrapper = [my_string] 425 | use_a_wrapper_to_simulate_pass_by_reference(wrapper) 426 | 427 | do_something_with(wrapper[0]) 428 | 429 | 虽然这样看起来有些笨重。 430 | -------------------------------------------------------------------------------- /contents/qa-std-modules.md: -------------------------------------------------------------------------------- 1 | 2 | ### json和simplejson的区别 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/712791/json-and-simplejson-module-differences-in-python) 5 | 6 | json就是simple,加入到标准库. json在2.6加入,simplejson在2.4+,2.6+,更有优势 7 | 8 | 另外,simplejson更新频率更高,如果你想使用最新版本,建议用simplejson 9 | 10 | 好的做法是 11 | 12 | try: import simplejson as json 13 | except ImportError: import json 14 | 15 | 另外,可以关注二者性能上的比较 16 | 17 | ### 如何用http下载一个文件 18 | 19 | 问题 [链接](http://stackoverflow.com/questions/22676/how-do-i-download-a-file-over-http-using-python) 20 | 21 | 直接使用urllib 22 | 23 | import urllib 24 | urllib.urlretrieve ("http://www.example.com/songs/mp3.mp3", "mp3.mp3") 25 | 26 | 使用urllib2,并提供一个进度条 27 | 28 | import urllib2 29 | 30 | url = "http://download.thinkbroadband.com/10MB.zip" 31 | 32 | file_name = url.split('/')[-1] 33 | u = urllib2.urlopen(url) 34 | f = open(file_name, 'wb') 35 | meta = u.info() 36 | file_size = int(meta.getheaders("Content-Length")[0]) 37 | print "Downloading: %s Bytes: %s" % (file_name, file_size) 38 | 39 | file_size_dl = 0 40 | block_sz = 8192 41 | while True: 42 | buffer = u.read(block_sz) 43 | if not buffer: 44 | break 45 | 46 | file_size_dl += len(buffer) 47 | f.write(buffer) 48 | status = r"%10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size) 49 | status = status + chr(8)*(len(status)+1) 50 | print status, 51 | 52 | f.close() 53 | 54 | 使用第三方[requests](http://docs.python-requests.org/en/latest/index.html)包 55 | 56 | >>> import requests 57 | >>> 58 | >>> url = "http://download.thinkbroadband.com/10MB.zip" 59 | >>> r = requests.get(url) 60 | >>> print len(r.content) 61 | 10485760 62 | 63 | ### argparse可选位置参数 64 | 65 | 问题 [链接](http://stackoverflow.com/questions/4480075/argparse-optional-positional-arguments) 66 | 67 | 脚本运行 usage: installer.py dir [-h] [-v] 68 | 69 | dir是一个位置参数,定义如下 70 | 71 | parser.add_argument('dir', default=os.getcwd()) 72 | 73 | 我想让dir变为可选,如果未设置,使用os.getcwd() 74 | 75 | 不幸的是,当我不指定dir时,得到错误 "Error: Too few arguments" 76 | 77 | 尝试使用 nargs='?' 78 | 79 | parser.add_argument('dir', nargs='?', default=os.getcwd()) 80 | 81 | 例子 82 | 83 | >>> import os, argparse 84 | >>> parser = argparse.ArgumentParser() 85 | >>> parser.add_argument('-v', action='store_true') 86 | _StoreTrueAction(option_strings=['-v'], dest='v', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None) 87 | >>> parser.add_argument('dir', nargs='?', default=os.getcwd()) 88 | _StoreAction(option_strings=[], dest='dir', nargs='?', const=None, default='/home/vinay', type=None, choices=None, help=None, metavar=None) 89 | >>> parser.parse_args('somedir -v'.split()) 90 | Namespace(dir='somedir', v=True) 91 | >>> parser.parse_args('-v'.split()) 92 | Namespace(dir='/home/vinay', v=True) 93 | >>> parser.parse_args(''.split()) 94 | Namespace(dir='/home/vinay', v=False) 95 | >>> parser.parse_args(['somedir']) 96 | Namespace(dir='somedir', v=False) 97 | >>> parser.parse_args('somedir -h -v'.split()) 98 | usage: [-h] [-v] [dir] 99 | 100 | positional arguments: 101 | dir 102 | 103 | optional arguments: 104 | -h, --help show this help message and exit 105 | -v 106 | ### 有什么方法可以获取系统当前用户名么? 107 | 108 | 问题 [链接](http://stackoverflow.com/questions/842059/is-there-a-portable-way-to-get-the-current-username-in-python) 109 | 110 | 至少在Linux和Windows下都可用.就像 os.getuid 111 | 112 | >>> os.getuid() 113 | 42 114 | >>> os.getusername() 115 | 'slartibartfast' 116 | 117 | 可以看看 [getpass](http://docs.python.org/2/library/getpass.html) 模块 118 | 119 | >>> import getpass 120 | >>> getpass.getuser() 121 | 'kostya' 122 | 123 | 可用: Unix, Windows 124 | 125 | ### 在Python中如何解析xml 126 | 127 | 问题 [链接](http://stackoverflow.com/questions/1912434/how-do-i-parse-xml-in-python) 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 如何解析获取xml文件中内容 137 | 138 | 我建议使用 [ElementTree](http://docs.python.org/2/library/xml.etree.elementtree.html) (有其他可用的实现,例如 [lxml](http://lxml.de/),他们只是更快, ElementTree提供更简单的编程api) 139 | 140 | 在使用XML建立Element实例之后,例如使用 [XML](http://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.XML) 函数 141 | 142 | for atype in e.findall('type') 143 | print(atype.get('foobar')) 144 | 145 | ### 如何使用Python创建一个GUID 146 | 147 | 问题 [链接](http://stackoverflow.com/questions/534839/how-to-create-a-guid-in-python) 148 | 149 | 如何使用原生的python创建一个GUID? 150 | 151 | Python2.5及以上版本,使用[uuid](http://docs.python.org/2/library/uuid.html)模块 152 | 153 | >>> import uuid 154 | >>> uuid.uuid1() 155 | UUID('5a35a426-f7ce-11dd-abd2-0017f227cfc7') 156 | 157 | 158 | ### 我该使用urllib/urllib2还是requests库 159 | 160 | 问题 [链接](http://stackoverflow.com/questions/2018026/should-i-use-urllib-or-urllib2-or-requests) 161 | 162 | [requests](http://docs.python-requests.org/en/latest/index.html) 163 | 164 | 推荐使用requests库 165 | 166 | 1. 支持restful API 167 | 168 | import requests 169 | ... 170 | 171 | resp = requests.get('http://www.mywebsite.com/user') 172 | resp = requests.post('http://www.mywebsite.com/user') 173 | resp = requests.put('http://www.mywebsite.com/user/put') 174 | resp = requests.delete('http://www.mywebsite.com/user/delete') 175 | 176 | 2. 无论GET/POST,你不需要关注编码 177 | 178 | userdata = {"firstname": "John", "lastname": "Doe", "password": "jdoe123"} 179 | resp = requests.post('http://www.mywebsite.com/user', params=userdata) 180 | 181 | 3. 内建json decoder 182 | 183 | resp.json() 184 | 185 | resp.text #纯文本 186 | 187 | 4. 其他 建官方文档 188 | 189 | urllib2,提供了一些额外的函数,让你可以自定义request headers 190 | 191 | r = Request(url='http://www.mysite.com') 192 | r.add_header('User-Agent', 'awesome fetcher') 193 | r.add_data(urllib.urlencode({'foo': 'bar'}) 194 | response = urlopen(r) 195 | 196 | 注意:urlencode只有urllib中有 197 | 198 | 199 | ### Python中是否存在方法可以打印对象的所有属性和方法 200 | 201 | 问题 [链接](http://stackoverflow.com/questions/192109/is-there-a-function-in-python-to-print-all-the-current-properties-and-values-of) 202 | 203 | 使用pprint 204 | 205 | from pprint import pprint 206 | pprint (vars(your_object)) 207 | 208 | 209 | ### 如何展示一个正在运行的Python应用的堆栈踪迹 210 | 211 | 问题[链接](http://stackoverflow.com/questions/132058/showing-the-stack-trace-from-a-running-python-application) 212 | 213 | 我一般在这种情况下用这个模块-当一个进程会跑很长时间,但是有时被莫名其妙而且不重复出现的原因卡住。看上去有点黑客的感觉,并且只在unix上生效(依赖信号): 214 | 215 | import code, traceback, signal 216 | 217 | def debug(sig, frame): 218 | """Interrupt running process, and provide a python prompt for 219 | interactive debugging.""" 220 | d={'_frame':frame} # Allow access to frame object. 221 | d.update(frame.f_globals) # Unless shadowed by global 222 | d.update(frame.f_locals) 223 | 224 | i = code.InteractiveConsole(d) 225 | message = "Signal received : entering python shell.\nTraceback:\n" 226 | message += ''.join(traceback.format_stack(frame)) 227 | i.interact(message) 228 | 229 | def listen(): 230 | signal.signal(signal.SIGUSR1, debug) # Register handler 231 | 232 | 使用时,当你启动程序时,只需要调用listen()这个函数(你甚至可以放到site.py里,对所有Python程序都起效),让它运行起来。任何时候,都可以对进程发出一个SIGUSR1的信号,使用kill或者在Python中: 233 | 234 | os.kill(pid, signal.SIGUSR1) 235 | 236 | 这会使Python控制台程序在当时停止,并给你展示堆栈的踪迹,允许你操作所有的变量。使用control-d(EOF)继续运行(在发出信号的一刻,通过注释你可以打断任何I/O等等,所以它不是完全无害的)。 237 | 238 | 我还有一个可以做同样事情的脚本,唯一不同的是它可以和正在运行的进程通过pip互通(允许在后台进行程序排错等等)。粘贴到这可能太长了,我已经把它加进了[python cookbook recipe](http://code.activestate.com/recipes/576515/)。 239 | 240 | ### 在Python中,有什么办法杀死一个线程 241 | 242 | 问题[链接](http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python) 243 | 244 | 不论是在Python中还是其他语言,突然停止一个线程通常来讲是一个很不好的习惯。考虑下面的情况: 245 | 246 | - 线程携带了非常重要的数据必须要正确的关闭 247 | 248 | - 线程创建了其余的进程,杀死这一个,其余的也要被杀掉 249 | 250 | 如果你承担得起(比如你再操纵自己的线程),那么比较好的做法是创建一个exit_request标记,每一个线程都会定时的检查是不是轮到它退出了。 251 | 252 | 举个例子: 253 | 254 | import threading 255 | 256 | class StoppableThread(threading.Thread): 257 | """Thread class with a stop() method. The thread itself has to check 258 | regularly for the stopped() condition.""" 259 | 260 | def __init__(self): 261 | super(StoppableThread, self).__init__() 262 | self._stop = threading.Event() 263 | 264 | def stop(self): 265 | self._stop.set() 266 | 267 | def stopped(self): 268 | return self._stop.isSet() 269 | 270 | 上述代码,当你想要停止这个线程时,你可以调用stop()方法,然后等待线程退出,最好用join()。线程应该定时的检查stop这个标记。 271 | 272 | 当然,某些情况下,你有足够的理由必须杀死一个线程。比如你正在封装一个外部的库,而且它已经持续很长时间了,你需要打断它。 273 | 274 | 下面的代码允许(可能有些限制)在Python中触发一个异常。 275 | 276 | 277 | def _async_raise(tid, exctype): 278 | '''Raises an exception in the threads with id tid''' 279 | if not inspect.isclass(exctype): 280 | raise TypeError("Only types can be raised (not instances)") 281 | res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 282 | ctypes.py_object(exctype)) 283 | if res == 0: 284 | raise ValueError("invalid thread id") 285 | elif res != 1: 286 | # "if it returns a number greater than one, you're in trouble, 287 | # and you should call it again with exc=NULL to revert the effect" 288 | ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0) 289 | raise SystemError("PyThreadState_SetAsyncExc failed") 290 | 291 | class ThreadWithExc(threading.Thread): 292 | '''A thread class that supports raising exception in the thread from 293 | another thread. 294 | ''' 295 | def _get_my_tid(self): 296 | """determines this (self's) thread id 297 | 298 | CAREFUL : this function is executed in the context of the caller 299 | thread, to get the identity of the thread represented by this 300 | instance. 301 | """ 302 | if not self.isAlive(): 303 | raise threading.ThreadError("the thread is not active") 304 | 305 | # do we have it cached? 306 | if hasattr(self, "_thread_id"): 307 | return self._thread_id 308 | 309 | # no, look for it in the _active dict 310 | for tid, tobj in threading._active.items(): 311 | if tobj is self: 312 | self._thread_id = tid 313 | return tid 314 | 315 | # TODO: in python 2.6, there's a simpler way to do : self.ident 316 | 317 | raise AssertionError("could not determine the thread's id") 318 | 319 | def raiseExc(self, exctype): 320 | """Raises the given exception type in the context of this thread. 321 | 322 | If the thread is busy in a system call (time.sleep(), 323 | socket.accept(), ...), the exception is simply ignored. 324 | 325 | If you are sure that your exception should terminate the thread, 326 | one way to ensure that it works is: 327 | 328 | t = ThreadWithExc( ... ) 329 | ... 330 | t.raiseExc( SomeException ) 331 | while t.isAlive(): 332 | time.sleep( 0.1 ) 333 | t.raiseExc( SomeException ) 334 | 335 | If the exception is to be caught by the thread, you need a way to 336 | check that your thread has caught it. 337 | 338 | CAREFUL : this function is executed in the context of the 339 | caller thread, to raise an excpetion in the context of the 340 | thread represented by this instance. 341 | """ 342 | _async_raise( self._get_my_tid(), exctype ) 343 | 344 | 正如注释中所写,这并不是一个万能钥匙,如果一个线程在Python解释器之外跑着,那么它不会被抓住并打断。 345 | 346 | 上面这段代码的一个好用法,就是让线程捕获一个特殊的异常并且表现的很干净。这样才能如你所愿的利落的中断一个任务。 347 | 348 | ### Python中isinstance()和type()的区别 349 | 350 | 总结一下其他人的答案(已OK的)作为内容。`isinstance`为继承者们服务(某个父类的实例也是基类的一个实例),而只检查是否相等的`type`则不是这样(他要求某个类型的id,拒绝子类型的实例,也可以叫做子类) 351 | 352 | 在Python中,通常你希望你的代码支持继承,当然(自从继承变得很容易之后,通过使用你自己的而不是使用它本身来停止某些代码是很不好的),所以`isinstance`看上去比检查id的`type`s要好一些,因为它无缝支持继承。 353 | 354 | 这不是说`isinstance`就绝对好,提醒一下,只是比对比类型是否相等好一点。通常从Pythonic的角度出发,最好的解决办法是永远的鸭子类型:试着像用一个渴望得到的类型去使用某个参数,用`try/except`声明捕获所有该参数不属于我们的渴望的类型而引起的异常(或者任何类鸭子类型;-),然后在`except`从句中,试着做一些其他的事情(假设这个参数“可能是”某些类型) 355 | 356 | `basestring`时一个奇葩,这是一个存在的意义仅仅是为了让你使用`isinstance`的内建类型(同理他们的子类`str`和`Unicode`)。字符串是有序的(你可以循环,排序,切片...),但是通常你对待它们就像标准类型--由于某些原因它不太好用(但是我们相当频繁的使用他们),原因是我们对于所有的字符串(或者其他标准类型,比如一个不能回环的东西)都用同一种方法,所有的容器(列表,集合,字典...),另一方面`basestring`加上`isinstance`可以帮你做这种事情--这个习惯用法的全部结构看起来像这样: 357 | 358 | if isinstance(x, basestring) 359 | return treatasscalar(x) 360 | try: 361 | return treatasiter(iter(x)) 362 | except TypeError: 363 | return treatasscalar(x) 364 | 365 | 你可能会说`basestring`是一个抽象类--在子类中没有提供具体的功能,更多的时候充当一个标记,为了让我们使用`isinstance`。从[PEP 3119](http://www.python.org/dev/peps/pep-3119/)开始,这种观念越来越明显,介绍了它的泛型,在Python2.6和3.0中被采用并实现。 366 | 367 | PEP明确了抽象基类可以代替鸭子类型,而且实现起来没什么压力(看[这里](https://www.python.org/dev/peps/pep-3119/#abcs-vs-duck-typing))。最新版本的Python中实现的抽象基类提供了额外的更吸引人的东西:`isinstance`(和`issubclass`)现在不仅仅是一个子类的实例(特别是所有的类都可以注册成为抽象基类并展示为某个子类,它可以实例化抽象基类的实例),抽象基类还为具体的子类提供了更多的便利-自然的通过模板方法来设计模仿应用。(看[这里](http://en.wikipedia.org/wiki/Template_method_pattern)和[这里](http://www.catonmat.net/blog/learning-python-design-patterns-through-video-lectures/)(第三部分)了解Python中特殊不特殊的更多TM DP,以及抽象基类的支持)。 368 | 369 | 对于那些Python 2.6中潜在的关于抽象基类的技巧,看[这里](https://docs.python.org/2/library/abc.html),对于3.1版本,同样,看[这里](https://docs.python.org/3.1/library/abc.html)。两种版本的基本库模块[collections](https://docs.python.org/3.1/library/collections.html#module-collections)(这是3.1版本,几乎一样的2.6版本,看[这里](https://docs.python.org/2/library/collections.html#module-collections))都提供了多种有用的抽象基类。 370 | 371 | 这个答案的目的是,抽象基类保留的那些关键东西(我们可以超过论证横向比较TM DP的功能性,和Python传统的mixin类,比如[UserDict.DictMixin](https://docs.python.org/2/library/userdict.html#UserDict.DictMixin))是他们让`isinstance`(和`issubclass`)比之前(Python2.5及之前)更有魅力且无处不在(在Python2.6以及更新的版本中)。因此,相比之下,在Python中检查类型相等更恶心了,比之前的版本还糟糕。 372 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stackoverflow-py-top-qa 2 | ======================= 3 | 4 | 5 | Notice: 6 | 7 | 目前进度90%, 剩余40+个问题实在没时间翻了, 有兴趣的同学可以试试, 提pr. or后续我找时间处理完整. 8 | 9 | ------------- 10 | 11 | stackoverflow上Python相关回答整理翻译(相对来说都比较简单/散,非系统学习用途,个人整理而已) 12 | 13 | 当前进度: 90% 14 | 问题个数: 135 15 | 最后更新: 2014-10-04 16 | 17 | 18 | 查看了下前面(vote前15页,挑了下,vote都是100+的样子,大概200个)的问题,[链接](http://stackoverflow.com/questions/tagged/python?page=1&sort=votes&pagesize=15) 19 | 20 | 第一页的前几个比较长,目测都有中文翻译版本,大家可以网上搜下 21 | 22 | 如果有兴趣,可以一起翻译 23 | 24 | 注意,合并了每个问题的多个答案,但是时间仓促,疏漏难免,感兴趣问题直接点链接看原文吧 25 | 26 | ### 目录 27 | > 基础 28 | 29 | * [基本语法控制流相关](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-control-flow.md) 30 | * [字符串相关](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-string.md) 31 | * [文件相关](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-file.md) 32 | * [数学相关](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-math.md) 33 | 34 | 35 | > 基本数据结构 36 | 37 | * [列表](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-list.md) 38 | * [元组](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-tuple.md) 39 | * [字典](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-dict.md) 40 | 41 | > 进阶 42 | 43 | * [函数](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-func.md) 44 | * [内置函数](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-built-in.md) 45 | * [异常](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-exception.md) 46 | * [模块](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-modules.md) 47 | * [标准库](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-std-modules.md) 48 | * [日期](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-datetime.md) 49 | * [oop](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-oop.md) 50 | 51 | > 其他 52 | 53 | * [pip/easy_install](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-pip-easy_install.md) 54 | 55 | * [其他](https://github.com/wklken/stackoverflow-py-top-qa/blob/master/contents/qa-others.md) 56 | 57 | ### 待翻译问题链接(还剩0问题) 58 | 59 | qa-tuple.md:问题 (http://stackoverflow.com/questions/2970608/what-are-named-tuples-in-python) 60 | 61 | ### 已翻译问题链接(去重) 62 | 63 | 64 | qa-built-in.md:问题 (http://stackoverflow.com/questions/230751/how-to-flush-output-of-python-print) 65 | 66 | qa-built-in.md:问题 (http://stackoverflow.com/questions/1835018/python-check-if-an-object-is-a-list-or-tuple-but-not-string) 67 | 68 | qa-built-in.md:问题 (http://stackoverflow.com/questions/152580/whats-the-canonical-way-to-check-for-type-in-python) 69 | 70 | qa-built-in.md:问题 (http://stackoverflow.com/questions/402504/how-to-determine-the-variable-type-in-python) 71 | 72 | qa-built-in.md:问题 (http://stackoverflow.com/questions/675442/comment-out-a-python-code-block) 73 | 74 | qa-built-in.md:问题 (http://stackoverflow.com/questions/397148/why-doesnt-python-have-multiline-comments) 75 | 76 | qa-built-in.md:问题 (http://stackoverflow.com/questions/56011/single-quotes-vs-double-quotes-in-python) 77 | 78 | qa-built-in.md:问题 (http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python) 79 | 80 | qa-built-in.md:问题 (http://stackoverflow.com/questions/890128/python-lambda-why) 81 | 82 | qa-built-in.md:问题 (http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python) 83 | 84 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/73663/terminating-a-python-script) 85 | 86 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/26595/is-there-any-difference-between-foo-is-none-and-foo-none) 87 | 88 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/522563/accessing-the-index-in-python-for-loops) 89 | 90 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/53162/how-can-i-do-a-line-break-line-continuation-in-python) 91 | 92 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/9284350/why-does-1-in-1-0-true-evaluate-to-false) 93 | 94 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/60208/replacements-for-switch-statement-in-python) 95 | 96 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/2710940/python-if-x-is-not-none-or-if-not-x-is-none) 97 | 98 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them) 99 | 100 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/843277/how-do-i-check-if-a-variable-exists-in-python) 101 | 102 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/394809/does-python-have-a-ternary-conditional-operator) 103 | 104 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/743164/do-while-loop-in-python) 105 | 106 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/135041/should-you-always-favor-xrange-over-range) 107 | 108 | qa-control-flow.md:问题 (http://stackoverflow.com/questions/15376509/when-is-i-x-different-from-i-i-x-in-python) 109 | 110 | qa-datetime.md:问题 (http://stackoverflow.com/questions/1697815/how-do-you-convert-a-python-time-struct-time-object-into-a-datetime-object) 111 | 112 | qa-datetime.md:问题 (http://stackoverflow.com/questions/415511/how-to-get-current-time-in-python) 113 | 114 | qa-datetime.md:问题 (http://stackoverflow.com/questions/85451/python-time-clock-vs-time-time-accuracy) 115 | 116 | qa-datetime.md:问题 (JSON datetime between Python and JavaScript) 117 | 118 | qa-dict.md:问题 (http://stackoverflow.com/questions/1747817/python-create-a-dictionary-with-list-comprehension) 119 | 120 | qa-dict.md:问题 (http://stackoverflow.com/questions/1323410/has-key-or-in) 121 | 122 | qa-dict.md:问题 (http://stackoverflow.com/questions/1602934/check-if-a-given-key-already-exists-in-a-dictionary) 123 | 124 | qa-dict.md:问题 (http://stackoverflow.com/questions/1024847/add-to-a-dictionary-in-python) 125 | 126 | qa-dict.md:问题 (http://stackoverflow.com/questions/1305532/convert-python-dict-to-object) 127 | 128 | qa-dict.md:问题 (http://stackoverflow.com/questions/38987/how-can-i-merge-union-two-python-dictionaries-in-a-single-expression) 129 | 130 | qa-dict.md:问题 (http://stackoverflow.com/questions/209840/map-two-lists-into-a-dictionary-in-python) 131 | 132 | qa-dict.md:问题 (http://stackoverflow.com/questions/72899/in-python-how-do-i-sort-a-list-of-dictionaries-by-values-of-the-dictionary) 133 | 134 | qa-dict.md:问题 (http://stackoverflow.com/questions/613183/python-sort-a-dictionary-by-value) 135 | 136 | qa-dict.md:问题 (http://stackoverflow.com/questions/4901815/object-as-a-dictionary-key) 137 | 138 | qa-exception.md:问题 (http://stackoverflow.com/questions/1319615/proper-way-to-declare-custom-exceptions-in-modern-python) 139 | 140 | qa-exception.md:问题 (http://stackoverflow.com/questions/2052390/how-do-i-manually-throw-raise-an-exception-in-python) 141 | 142 | qa-exception.md:问题 (http://stackoverflow.com/questions/6470428/catch-multiple-exceptions-in-one-line-except-block) 143 | 144 | qa-exception.md:问题 (http://stackoverflow.com/questions/944592/best-practice-for-python-assert) 145 | 146 | qa-exception.md:问题 (http://stackoverflow.com/questions/5574702/how-to-print-to-stderr-in-python) 147 | 148 | qa-exception.md:问题 (http://stackoverflow.com/questions/944592/best-practice-for-python-assert) 149 | 150 | qa-file.md:问题 (http://stackoverflow.com/questions/82831/how-do-i-check-if-a-file-exists-using-python) 151 | 152 | qa-file.md:问题 (http://stackoverflow.com/questions/273192/python-best-way-to-create-directory-if-it-doesnt-exist-for-file-write) 153 | 154 | qa-file.md:问题 (http://stackoverflow.com/questions/123198/how-do-i-copy-a-file-in-python) 155 | 156 | qa-file.md:问题 (http://stackoverflow.com/questions/275018/how-can-i-remove-chomp-a-newline-in-python) 157 | 158 | qa-file.md:问题 (http://stackoverflow.com/questions/237079/how-to-get-file-creation-modification-date-times-in-python) 159 | 160 | qa-file.md:问题 (http://stackoverflow.com/questions/466345/converting-string-into-datetime) 161 | 162 | qa-file.md:问题 (http://stackoverflow.com/questions/5137497/find-current-directory-and-files-directory) 163 | 164 | qa-file.md:问题 (http://stackoverflow.com/questions/3964681/find-all-files-in-directory-with-extension-txt-with-python) 165 | 166 | qa-file.md:问题 (http://stackoverflow.com/questions/3277503/python-read-file-line-by-line-into-array) 167 | 168 | qa-file.md:问题 (http://stackoverflow.com/questions/4706499/how-do-you-append-to-file-in-python) 169 | 170 | qa-file.md:问题 (http://stackoverflow.com/questions/541390/extracting-extension-from-filename-in-python) 171 | 172 | qa-file.md:问题 (http://stackoverflow.com/questions/3207219/how-to-list-all-files-of-a-directory-in-python) 173 | 174 | qa-file.md:问题 (http://stackoverflow.com/questions/1450393/how-do-you-read-from-stdin-in-python) 175 | 176 | qa-file.md:问题 (http://stackoverflow.com/questions/845058/how-to-get-line-count-cheaply-in-python) 177 | 178 | qa-file.md:问题 (http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python) 179 | 180 | qa-func.md:问题 (http://stackoverflow.com/questions/251464/how-to-get-the-function-name-as-string-in-python) 181 | 182 | qa-func.md:问题 (http://stackoverflow.com/questions/3061/calling-a-function-from-a-string-with-the-functions-name-in-python) 183 | 184 | qa-func.md:问题 (http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters) 185 | 186 | qa-func.md:问题 (http://stackoverflow.com/questions/1098549/proper-way-to-use-kwargs-in-python) 187 | 188 | qa-func.md:问题 (http://stackoverflow.com/questions/3394835/args-and-kwargs) 189 | 190 | qa-func.md:问题 (http://stackoverflow.com/questions/682504/what-is-a-clean-pythonic-way-to-have-multiple-constructors-in-python) 191 | 192 | qa-func.md:问题 (http://stackoverflow.com/questions/36901/what-does-double-star-and-star-do-for-python-parameters) 193 | 194 | qa-func.md:问题 (http://stackoverflow.com/questions/11241523/why-does-python-code-run-faster-in-a-function) 195 | 196 | qa-func.md:问题 (http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) 197 | 198 | qa-list.md:问题 (http://stackoverflow.com/questions/509211/the-python-slice-notation) 199 | 200 | qa-list.md:问题 (http://stackoverflow.com/questions/53513/python-what-is-the-best-way-to-check-if-a-list-is-empty) 201 | 202 | qa-list.md:问题 (http://stackoverflow.com/questions/1720421/merge-two-lists-in-python) 203 | 204 | qa-list.md:问题 (http://stackoverflow.com/questions/518021/getting-the-length-of-an-array-in-python) 205 | 206 | qa-list.md:问题 (http://stackoverflow.com/questions/2612802/how-to-clone-a-list-in-python) 207 | 208 | qa-list.md:问题 (http://stackoverflow.com/questions/252703/python-append-vs-extend) 209 | 210 | qa-list.md:问题 (http://stackoverflow.com/questions/306400/how-do-i-randomly-select-an-item-from-a-list-using-python) 211 | 212 | qa-list.md:问题 (http://stackoverflow.com/questions/627435/how-to-remove-an-element-from-a-list-by-index-in-python) 213 | 214 | qa-list.md:问题 (http://stackoverflow.com/questions/930397/how-to-get-the-last-element-of-a-list) 215 | 216 | qa-list.md:问题 (http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python) 217 | 218 | qa-list.md:问题 (http://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order) 219 | 220 | qa-list.md:问题 (http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python) 221 | 222 | qa-list.md:问题 (http://stackoverflow.com/questions/176918/in-python-how-do-i-find-the-index-of-an-item-given-a-list-containing-it) 223 | 224 | qa-list.md:问题 (http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python) 225 | 226 | qa-list.md:问题 (http://stackoverflow.com/questions/1247486/python-list-comprehension-vs-map) 227 | 228 | qa-list.md:问题 (http://stackoverflow.com/questions/626759/whats-the-difference-between-list-and-tuples) 229 | 230 | qa-list.md:问题 (http://stackoverflow.com/questions/17160162/what-is-in-python-2-7) 231 | 232 | qa-math.md:问题 (http://stackoverflow.com/questions/1476/how-do-you-express-binary-literals-in-python) 233 | 234 | qa-math.md:问题 (http://stackoverflow.com/questions/209513/convert-hex-string-to-int-in-python) 235 | 236 | qa-math.md:问题 (http://stackoverflow.com/questions/1267869/how-can-i-force-division-to-be-floating-point-in-python) 237 | 238 | qa-math.md:问题 (http://stackoverflow.com/questions/961632/converting-integer-to-string-in-python) 239 | 240 | qa-math.md:问题 (http://stackoverflow.com/questions/306313/python-is-operator-behaves-unexpectedly-with-integers) 241 | 242 | qa-math.md:问题 (http://stackoverflow.com/questions/455612/limiting-floats-to-two-decimal-points) 243 | 244 | qa-math.md:问题 (http://stackoverflow.com/questions/432842/how-do-you-get-the-logical-xor-of-two-variables-in-python) 245 | 246 | qa-math.md:问题 (http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python) 247 | 248 | qa-math.md:问题 (http://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python) 249 | 250 | qa-modules.md:问题 (http://stackoverflow.com/questions/448271/what-is-init-py-for) 251 | 252 | qa-modules.md:问题 (http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path) 253 | 254 | qa-modules.md:问题 (http://stackoverflow.com/questions/247770/retrieving-python-module-path) 255 | 256 | qa-modules.md:问题 (http://stackoverflow.com/questions/44834/can-someone-explain-all-in-python) 257 | 258 | qa-modules.md:问题 (http://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module) 259 | 260 | qa-modules.md:问题 (http://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python) 261 | 262 | qa-modules.md:问题 (http://stackoverflow.com/questions/419163/what-does-if-name-main-do) 263 | 264 | qa-modules.md:问题 (http://stackoverflow.com/questions/279237/import-a-module-from-a-relative-path) 265 | 266 | qa-modules.md:问题 (http://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python) 267 | 268 | qa-oop.md:问题 (http://stackoverflow.com/questions/2709821/python-self-explained) 269 | 270 | qa-oop.md:问题 (http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private) 271 | 272 | qa-oop.md:问题 (http://stackoverflow.com/questions/38238/what-are-class-methods-in-python-for) 273 | 274 | qa-oop.md:问题 (http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init) 275 | 276 | qa-oop.md:问题 (http://stackoverflow.com/questions/510972/getting-the-class-name-of-an-instance-in-python) 277 | 278 | qa-oop.md:问题 (http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python) 279 | 280 | qa-oop.md:问题 (http://stackoverflow.com/questions/735975/static-methods-in-python) 281 | 282 | qa-oop.md:问题 (http://stackoverflow.com/questions/68645/static-class-variables-in-python) 283 | 284 | qa-oop.md:问题 (http://stackoverflow.com/questions/610883/how-to-know-if-an-object-has-an-attribute-in-python) 285 | 286 | qa-oop.md:问题 (http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python) 287 | 288 | qa-oop.md:问题 (http://stackoverflow.com/questions/576169/understanding-python-super-and-init-methods) 289 | 290 | qa-oop.md:问题 (http://stackoverflow.com/questions/1952464/in-python-how-do-i-determine-if-an-object-is-iterable) 291 | 292 | qa-oop.md:问题 (http://stackoverflow.com/questions/19151/build-a-basic-python-iterator) 293 | 294 | qa-oop.md:问题 (http://stackoverflow.com/questions/372042/difference-between-abstract-class-and-interface-in-python) 295 | 296 | qa-oop.md:问题 (http://stackoverflow.com/questions/472000/python-slots) 297 | 298 | qa-oop.md:问题 (http://stackoverflow.com/questions/54867/old-style-and-new-style-classes-in-python) 299 | 300 | qa-oop.md:问题 (http://stackoverflow.com/questions/6618002/python-property-versus-getters-and-setters) 301 | 302 | qa-oop.md:问题 (http://stackoverflow.com/questions/904036/chain-calling-parent-constructors-in-python) 303 | 304 | qa-oop.md:问题 (http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python) 305 | 306 | qa-oop.md:问题 (http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object) 307 | 308 | qa-oop.md:问题 (http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python/6581949#6581949) 309 | 310 | qa-oop.md:问题 (http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) 311 | 312 | qa-others.md:问题 (http://stackoverflow.com/questions/170921/should-i-learn-python-2-before-3-or-start-directly-from-python-3) 313 | 314 | qa-others.md:问题 (http://stackoverflow.com/questions/1534210/use-different-python-version-with-virtualenv) 315 | 316 | qa-others.md:问题 (http://stackoverflow.com/questions/990754/how-to-leave-a-python-virtualenv) 317 | 318 | qa-others.md:问题 (http://stackoverflow.com/questions/193161/what-is-the-best-project-structure-for-a-python-application) 319 | 320 | qa-others.md:问题 (http://stackoverflow.com/questions/13311094/counter-in-collections-module-python) 321 | 322 | qa-others.md:问题 (http://stackoverflow.com/questions/372885/how-do-i-connect-to-a-mysql-database-in-python) 323 | 324 | qa-others.md:问题 (http://stackoverflow.com/questions/4941145/python-flask-vs-bottle) 325 | 326 | qa-others.md:问题 (http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script) 327 | 328 | qa-others.md:问题 (http://stackoverflow.com/questions/2775864/python-create-unix-timestamp-five-minutes-in-the-future) 329 | 330 | qa-others.md:问题 (http://stackoverflow.com/questions/89228/calling-an-external-command-in-python) 331 | 332 | qa-others.md:问题 (http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python) 333 | 334 | qa-others.md:问题 (http://stackoverflow.com/questions/261638/how-do-i-protect-python-code) 335 | 336 | qa-others.md:问题 (http://stackoverflow.com/questions/191673/preferred-python-unit-testing-framework) 337 | 338 | qa-others.md:问题 (http://stackoverflow.com/questions/61151/where-do-the-python-unit-tests-go) 339 | 340 | qa-others.md:问题 (http://stackoverflow.com/questions/6344076/differences-between-distribute-distutils-setuptools-and-distutils2) 341 | 342 | qa-pip-easy_install.md:问题 (http://stackoverflow.com/questions/2720014/upgrading-all-packages-with-pip) 343 | 344 | qa-pip-easy_install.md:问题 (http://stackoverflow.com/questions/1231688/how-do-i-remove-packages-installed-with-pythons-easy-install) 345 | 346 | qa-pip-easy_install.md:问题 (http://stackoverflow.com/questions/122327/how-do-i-find-the-location-of-my-python-site-packages-directory) 347 | 348 | qa-pip-easy_install.md:问题 (http://stackoverflow.com/questions/1550226/python-setup-py-uninstall) 349 | 350 | qa-pip-easy_install.md:问题 (http://stackoverflow.com/questions/739993/get-a-list-of-installed-python-modules) 351 | 352 | qa-pip-easy_install.md:问题 (http://stackoverflow.com/questions/3220404/why-use-pip-over-easy-install) 353 | 354 | qa-pip-easy_install.md:问题 (http://stackoverflow.com/questions/4324558/whats-the-proper-way-to-install-pip-virtualenv-and-distribute-for-python) 355 | 356 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/712791/json-and-simplejson-module-differences-in-python) 357 | 358 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/22676/how-do-i-download-a-file-over-http-using-python) 359 | 360 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/4480075/argparse-optional-positional-arguments) 361 | 362 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/842059/is-there-a-portable-way-to-get-the-current-username-in-python) 363 | 364 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/1912434/how-do-i-parse-xml-in-python) 365 | 366 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/534839/how-to-create-a-guid-in-python) 367 | 368 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/2018026/should-i-use-urllib-or-urllib2-or-requests) 369 | 370 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/192109/is-there-a-function-in-python-to-print-all-the-current-properties-and-values-of) 371 | 372 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/132058/showing-the-stack-trace-from-a-running-python-application) 373 | 374 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/1549801/differences-between-isinstance-and-type-in-python) 375 | 376 | qa-std-modules.md:问题 (http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python) 377 | 378 | qa-string.md:问题 (http://stackoverflow.com/questions/493819/python-join-why-is-it-string-joinlist-instead-of-list-joinstring) 379 | 380 | qa-string.md:问题 (http://stackoverflow.com/questions/6797984/how-to-convert-string-to-lowercase-in-python) 381 | 382 | qa-string.md:问题 (http://stackoverflow.com/questions/931092/reverse-a-string-in-python) 383 | 384 | qa-string.md:问题 (http://stackoverflow.com/questions/3437059/does-python-have-a-string-contains-method) 385 | 386 | qa-string.md:问题 (http://stackoverflow.com/questions/354038/how-do-i-check-if-a-string-is-a-number-in-python) 387 | 388 | qa-string.md:问题 (http://stackoverflow.com/questions/5082452/python-string-formatting-vs-format) 389 | 390 | qa-string.md:问题 (http://stackoverflow.com/questions/988228/converting-a-string-to-dictionary) 391 | 392 | qa-string.md:问题 (http://stackoverflow.com/questions/227459/ascii-value-of-a-character-in-python) 393 | 394 | qa-string.md:问题 (http://stackoverflow.com/questions/1059559/python-strings-split-with-multiple-separators) 395 | 396 | qa-string.md:问题 (http://stackoverflow.com/questions/1185524/how-to-trim-whitespace-including-tabs) 397 | 398 | qa-string.md:问题 (http://stackoverflow.com/questions/663171/is-there-a-way-to-substring-a-string-in-python) 399 | 400 | qa-string.md:问题 (http://stackoverflow.com/questions/1504717/python-vs-is-comparing-strings-is-fails-sometimes-why) 401 | 402 | qa-string.md:问题 (http://stackoverflow.com/questions/339007/python-nicest-way-to-pad-zeroes-to-string) 403 | 404 | qa-string.md:问题 (http://stackoverflow.com/questions/606191/convert-byte-array-to-python-string) 405 | 406 | ### contributors 407 | 408 | thx a lot:) 409 | 410 | - [wklken](https://github.com/wklken) 411 | 412 | - [shnode](https://github.com/shnode) 413 | 414 | 415 | more [link](https://github.com/wklken/stackoverflow-py-top-qa/graphs/contributors) 416 | 417 | ### Donation 418 | 419 | You can Buy me a coffee:) [link](http://www.wklken.me/pages/donation.html) 420 | 421 | 422 | 423 | ------ 424 | 425 | 426 | To Be Continue ... 427 | 428 | wklken 429 | 430 | Email: wklken@yeah.net 431 | 432 | Blog: http://wklken.me 433 | 434 | 2013-09-21 于深圳 435 | -------------------------------------------------------------------------------- /contents/qa-math.md: -------------------------------------------------------------------------------- 1 | 2 | ### 在Python中如何展示二进制字面值 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/1476/how-do-you-express-binary-literals-in-python) 5 | 6 | 十六进制可以 7 | 8 | >>> 0x12AF 9 | 4783 10 | >>> 0x100 11 | 256 12 | 13 | 八进制可以 14 | 15 | >>> 01267 16 | 695 17 | >>> 0100 18 | 64 19 | 20 | 二进制如何表示? 21 | 22 | Python 2.5 及更早版本: 可以表示为 int('01010101111',2) 但没有字面量 23 | 24 | Python 2.6 beta: 可以使用0b1100111 or 0B1100111 表示 25 | 26 | Python 2.6 beta: 也可以使用 0o27 or 0O27 (第二字字符是字母 O) 27 | 28 | Python 3.0 beta: 同2.6,但不支持027这种语法 29 | ### 如何将一个十六进制字符串转为整数 30 | 31 | 问题 [链接](http://stackoverflow.com/questions/209513/convert-hex-string-to-int-in-python) 32 | 33 | >>> int("a", 16) 34 | 10 35 | >>> int("0xa",16) 36 | 10 37 | 38 | 39 | 详细 [文档](http://docs.python.org/2/library/sys.html) 40 | 41 | ### 如何强制使用浮点数除法 42 | 43 | 问题 [链接](http://stackoverflow.com/questions/1267869/how-can-i-force-division-to-be-floating-point-in-python) 44 | 45 | 如何强制使除法结果c是浮点数 46 | 47 | c = a / b 48 | 可以使用__future__ 49 | 50 | >>> from __future__ import division 51 | >>> a = 4 52 | >>> b = 6 53 | >>> c = a / b 54 | >>> c 55 | 0.66666666666666663 56 | 57 | 或者转换,如果除数或被除数是浮点数,那么结果也是浮点数 58 | 59 | c = a / float(b) 60 | 61 | ### 如何将一个整数转为字符串 62 | 63 | 问题 [链接](http://stackoverflow.com/questions/961632/converting-integer-to-string-in-python) 64 | 65 | 回答 66 | 67 | >>> str(10) 68 | '10' 69 | >>> int('10') 70 | 10 71 | 72 | 对应文档 [int()](http://docs.python.org/2/library/functions.html#int) [str()](http://docs.python.org/2/library/functions.html#str) 73 | 74 | ### Python的”is”语句在数字类型上表现不正常 75 | 76 | 问题[链接](http://stackoverflow.com/questions/306313/pythons-is-operator-behaves-unexpectedly-with-integers) 77 | 78 | 看看这个: 79 | 80 | >>> a = 256 81 | >>> b = 256 82 | >>> id(a) 83 | 9987148 84 | >>> id(b) 85 | 9987148 86 | >>> a = 257 87 | >>> b = 257 88 | >>> id(a) 89 | 11662816 90 | >>> id(b) 91 | 11662828 92 | 93 | 编辑:这是我在Python文档中发现的,[7.2.1, “Plain Integer Objects”](https://docs.python.org/2/c-api/int.html): 94 | 95 | 正在执行的程序会保持一组从-5到256的数值型对象,当你创建一个在这个范围内的数字,你实际上得到了一个已存在的对象的反馈。所以改变1的数值是有可能的,我猜因此这种表现在Python里还定义。 96 | 97 | ### 将浮点型数字的小数限制为两位 98 | 99 | 问题[链接](http://stackoverflow.com/questions/455612/limiting-floats-to-two-decimal-points) 100 | 101 | 你陷入了一个浮点型数据的很老的错误,即所有的数字都不能表示。命令行只能告诉你内存中的全长小数。在浮点里你四舍五入到一个同样的数字。自从计算机是二进制开始,他们把浮点数保存为整数然后除一个2的幂。两位精确的数字有53比特(16位)的精度,常规的浮点数有24比特(8位)的精度。[floating point in python uses double precision](https://docs.python.org/2/tutorial/floatingpoint.html)保存值。 102 | 103 | 举个例子: 104 | 105 | >>>125650429603636838/(2**53) 106 | 13.949999999999999 107 | 108 | >>> 234042163/(2**24) 109 | 13.949999988079071 110 | 111 | >>> a=13.946 112 | >>> print(a) 113 | 13.946 114 | >>> print("%.2f" % a) 115 | 13.95 116 | >>> round(a,2) 117 | 13.949999999999999 118 | >>> print("%.2f" % round(a,2)) 119 | 13.95 120 | >>> print("{0:.2f}".format(a)) 121 | 13.95 122 | >>> print("{0:.2f}".format(round(a,2))) 123 | 13.95 124 | >>> print("{0:.15f}".format(round(a,2))) 125 | 13.949999999999999 126 | 127 | 作为货币如果你只需要小数点后两位的位置,那么你有一对比较好的选择,用整数存储值为分而不是元,之后除以100来得到元。或者用修正过的小数,比如[decimal](https://docs.python.org/2/library/decimal.html) 128 | 129 | ### 在Python中如何表示逻辑的异或 130 | 131 | 问题[链接](http://stackoverflow.com/questions/432842/how-do-you-get-the-logical-xor-of-two-variables-in-python) 132 | 133 | 如果你已经将输入值设为布尔型,那么 != 就是异或。 134 | 135 | bool(a) != bool(b) 136 | 137 | ### 列出小于N的所有质数的最快方法 138 | 139 | 问题[链接](http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n) 140 | 141 | 警告:`timeit`可能会根据硬件或Python的版本而产生不同的结果。 142 | 143 | 下面的脚本对比了执行一个数字的时间: 144 | 145 | • ambi_sieve_plain, 146 | • rwh_primes, 147 | • rwh_primes1, 148 | • rwh_primes2, 149 | • sieveOfAtkin, 150 | • sieveOfEratosthenes, 151 | • sundaram3, 152 | • sieve_wheel_30, 153 | • ambi_sieve (requires numpy) 154 | • primesfrom3to (requires numpy) 155 | • primesfrom2to (requires numpy) 156 | 157 | 158 | 感谢stephen,他的sieve_wheel_30引起了我的注意。请相信Robert Wolliam Hanks的primesfrom2to, primesfrom3to, rwh_primes, rwh_primes1,还有rwh_primes2。 159 | 160 | 161 | 通过psyco,在n=1000000的情况下,平行地对比这些Python方法,rwh_primes1是最快的。 162 | 163 | 164 | +---------------------+-------+ 165 | | Method | ms | 166 | +---------------------+-------+ 167 | | rwh_primes1 | 43.0 | 168 | | sieveOfAtkin | 46.4 | 169 | | rwh_primes | 57.4 | 170 | | sieve_wheel_30 | 63.0 | 171 | | rwh_primes2 | 67.8 | 172 | | sieveOfEratosthenes | 147.0 | 173 | | ambi_sieve_plain | 152.0 | 174 | | sundaram3 | 194.0 | 175 | +---------------------+-------+ 176 | 177 | 178 | 不使用psyco,在n=1000000的情况下,rwh_primes2最快。 179 | 180 | 181 | +---------------------+-------+ 182 | | Method | ms | 183 | +---------------------+-------+ 184 | | rwh_primes2 | 68.1 | 185 | | rwh_primes1 | 93.7 | 186 | | rwh_primes | 94.6 | 187 | | sieve_wheel_30 | 97.4 | 188 | | sieveOfEratosthenes | 178.0 | 189 | | ambi_sieve_plain | 286.0 | 190 | | sieveOfAtkin | 314.0 | 191 | | sundaram3 | 416.0 | 192 | +---------------------+-------+ 193 | 194 | 对于所有的方法,如果允许*numpy*,n=1000000,primesfrom2to是最快的。 195 | 196 | +---------------------+-------+ 197 | | Method | ms | 198 | +---------------------+-------+ 199 | | primesfrom2to | 15.9 | 200 | | primesfrom3to | 18.4 | 201 | | ambi_sieve | 29.3 | 202 | +---------------------+-------+ 203 | 204 | 计时器用的是命令: 205 | 206 | python -mtimeit -s"import primes" "primes.{method}(10000000)" 207 | 208 | `method`替换成不同的方法名字。 209 | 210 | 211 | primes.py: 212 | 213 | 214 | #!/usr/bin/env python 215 | import psyco; psyco.full() 216 | from math import sqrt, ceil 217 | import numpy as np 218 | 219 | def rwh_primes(n): 220 | # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 221 | """ Returns a list of primes < n """ 222 | sieve = [True] * n 223 | for i in xrange(3,int(n**0.5)+1,2): 224 | if sieve[i]: 225 | sieve[i*i::2*i]=[False]*((n-i*i-1)/(2*i)+1) 226 | return [2] + [i for i in xrange(3,n,2) if sieve[i]] 227 | 228 | def rwh_primes1(n): 229 | # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 230 | """ Returns a list of primes < n """ 231 | sieve = [True] * (n/2) 232 | for i in xrange(3,int(n**0.5)+1,2): 233 | if sieve[i/2]: 234 | sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1) 235 | return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]] 236 | 237 | def rwh_primes2(n): 238 | # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 239 | """ Input n>=6, Returns a list of primes, 2 <= p < n """ 240 | correction = (n%6>1) 241 | n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6] 242 | sieve = [True] * (n/3) 243 | sieve[0] = False 244 | for i in xrange(int(n**0.5)/3+1): 245 | if sieve[i]: 246 | k=3*i+1|1 247 | sieve[ ((k*k)/3) ::2*k]=[False]*((n/6-(k*k)/6-1)/k+1) 248 | sieve[(k*k+4*k-2*k*(i&1))/3::2*k]=[False]*((n/6-(k*k+4*k-2*k*(i&1))/6-1)/k+1) 249 | return [2,3] + [3*i+1|1 for i in xrange(1,n/3-correction) if sieve[i]] 250 | 251 | def sieve_wheel_30(N): 252 | # http://zerovolt.com/?p=88 253 | ''' Returns a list of primes <= N using wheel criterion 2*3*5 = 30 254 | 255 | Copyright 2009 by zerovolt.com 256 | This code is free for non-commercial purposes, in which case you can just leave this comment as a credit for my work. 257 | If you need this code for commercial purposes, please contact me by sending an email to: info [at] zerovolt [dot] com.''' 258 | __smallp = ( 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 259 | 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 260 | 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 261 | 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 262 | 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 263 | 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 264 | 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 265 | 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 266 | 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 267 | 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 268 | 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997) 269 | 270 | wheel = (2, 3, 5) 271 | const = 30 272 | if N < 2: 273 | return [] 274 | if N <= const: 275 | pos = 0 276 | while __smallp[pos] <= N: 277 | pos += 1 278 | return list(__smallp[:pos]) 279 | # make the offsets list 280 | offsets = (7, 11, 13, 17, 19, 23, 29, 1) 281 | # prepare the list 282 | p = [2, 3, 5] 283 | dim = 2 + N // const 284 | tk1 = [True] * dim 285 | tk7 = [True] * dim 286 | tk11 = [True] * dim 287 | tk13 = [True] * dim 288 | tk17 = [True] * dim 289 | tk19 = [True] * dim 290 | tk23 = [True] * dim 291 | tk29 = [True] * dim 292 | tk1[0] = False 293 | # help dictionary d 294 | # d[a , b] = c ==> if I want to find the smallest useful multiple of (30*pos)+a 295 | # on tkc, then I need the index given by the product of [(30*pos)+a][(30*pos)+b] 296 | # in general. If b < a, I need [(30*pos)+a][(30*(pos+1))+b] 297 | d = {} 298 | for x in offsets: 299 | for y in offsets: 300 | res = (x*y) % const 301 | if res in offsets: 302 | d[(x, res)] = y 303 | # another help dictionary: gives tkx calling tmptk[x] 304 | tmptk = {1:tk1, 7:tk7, 11:tk11, 13:tk13, 17:tk17, 19:tk19, 23:tk23, 29:tk29} 305 | pos, prime, lastadded, stop = 0, 0, 0, int(ceil(sqrt(N))) 306 | # inner functions definition 307 | def del_mult(tk, start, step): 308 | for k in xrange(start, len(tk), step): 309 | tk[k] = False 310 | # end of inner functions definition 311 | cpos = const * pos 312 | while prime < stop: 313 | # 30k + 7 314 | if tk7[pos]: 315 | prime = cpos + 7 316 | p.append(prime) 317 | lastadded = 7 318 | for off in offsets: 319 | tmp = d[(7, off)] 320 | start = (pos + prime) if off == 7 else (prime * (const * (pos + 1 if tmp < 7 else 0) + tmp) )//const 321 | del_mult(tmptk[off], start, prime) 322 | # 30k + 11 323 | if tk11[pos]: 324 | prime = cpos + 11 325 | p.append(prime) 326 | lastadded = 11 327 | for off in offsets: 328 | tmp = d[(11, off)] 329 | start = (pos + prime) if off == 11 else (prime * (const * (pos + 1 if tmp < 11 else 0) + tmp) )//const 330 | del_mult(tmptk[off], start, prime) 331 | # 30k + 13 332 | if tk13[pos]: 333 | prime = cpos + 13 334 | p.append(prime) 335 | lastadded = 13 336 | for off in offsets: 337 | tmp = d[(13, off)] 338 | start = (pos + prime) if off == 13 else (prime * (const * (pos + 1 if tmp < 13 else 0) + tmp) )//const 339 | del_mult(tmptk[off], start, prime) 340 | # 30k + 17 341 | if tk17[pos]: 342 | prime = cpos + 17 343 | p.append(prime) 344 | lastadded = 17 345 | for off in offsets: 346 | tmp = d[(17, off)] 347 | start = (pos + prime) if off == 17 else (prime * (const * (pos + 1 if tmp < 17 else 0) + tmp) )//const 348 | del_mult(tmptk[off], start, prime) 349 | # 30k + 19 350 | if tk19[pos]: 351 | prime = cpos + 19 352 | p.append(prime) 353 | lastadded = 19 354 | for off in offsets: 355 | tmp = d[(19, off)] 356 | start = (pos + prime) if off == 19 else (prime * (const * (pos + 1 if tmp < 19 else 0) + tmp) )//const 357 | del_mult(tmptk[off], start, prime) 358 | # 30k + 23 359 | if tk23[pos]: 360 | prime = cpos + 23 361 | p.append(prime) 362 | lastadded = 23 363 | for off in offsets: 364 | tmp = d[(23, off)] 365 | start = (pos + prime) if off == 23 else (prime * (const * (pos + 1 if tmp < 23 else 0) + tmp) )//const 366 | del_mult(tmptk[off], start, prime) 367 | # 30k + 29 368 | if tk29[pos]: 369 | prime = cpos + 29 370 | p.append(prime) 371 | lastadded = 29 372 | for off in offsets: 373 | tmp = d[(29, off)] 374 | start = (pos + prime) if off == 29 else (prime * (const * (pos + 1 if tmp < 29 else 0) + tmp) )//const 375 | del_mult(tmptk[off], start, prime) 376 | # now we go back to top tk1, so we need to increase pos by 1 377 | pos += 1 378 | cpos = const * pos 379 | # 30k + 1 380 | if tk1[pos]: 381 | prime = cpos + 1 382 | p.append(prime) 383 | lastadded = 1 384 | for off in offsets: 385 | tmp = d[(1, off)] 386 | start = (pos + prime) if off == 1 else (prime * (const * pos + tmp) )//const 387 | del_mult(tmptk[off], start, prime) 388 | # time to add remaining primes 389 | # if lastadded == 1, remove last element and start adding them from tk1 390 | # this way we don't need an "if" within the last while 391 | if lastadded == 1: 392 | p.pop() 393 | # now complete for every other possible prime 394 | while pos < len(tk1): 395 | cpos = const * pos 396 | if tk1[pos]: p.append(cpos + 1) 397 | if tk7[pos]: p.append(cpos + 7) 398 | if tk11[pos]: p.append(cpos + 11) 399 | if tk13[pos]: p.append(cpos + 13) 400 | if tk17[pos]: p.append(cpos + 17) 401 | if tk19[pos]: p.append(cpos + 19) 402 | if tk23[pos]: p.append(cpos + 23) 403 | if tk29[pos]: p.append(cpos + 29) 404 | pos += 1 405 | # remove exceeding if present 406 | pos = len(p) - 1 407 | while p[pos] > N: 408 | pos -= 1 409 | if pos < len(p) - 1: 410 | del p[pos+1:] 411 | # return p list 412 | return p 413 | 414 | def sieveOfEratosthenes(n): 415 | """sieveOfEratosthenes(n): return the list of the primes < n.""" 416 | # Code from: , Nov 30 2006 417 | # http://groups.google.com/group/comp.lang.python/msg/f1f10ced88c68c2d 418 | if n <= 2: 419 | return [] 420 | sieve = range(3, n, 2) 421 | top = len(sieve) 422 | for si in sieve: 423 | if si: 424 | bottom = (si*si - 3) // 2 425 | if bottom >= top: 426 | break 427 | sieve[bottom::si] = [0] * -((bottom - top) // si) 428 | return [2] + [el for el in sieve if el] 429 | 430 | def sieveOfAtkin(end): 431 | """sieveOfAtkin(end): return a list of all the prime numbers , improved 434 | # Code: http://krenzel.info/?p=83 435 | # Info: http://en.wikipedia.org/wiki/Sieve_of_Atkin 436 | assert end > 0 437 | lng = ((end-1) // 2) 438 | sieve = [False] * (lng + 1) 439 | 440 | x_max, x2, xd = int(sqrt((end-1)/4.0)), 0, 4 441 | for xd in xrange(4, 8*x_max + 2, 8): 442 | x2 += xd 443 | y_max = int(sqrt(end-x2)) 444 | n, n_diff = x2 + y_max*y_max, (y_max << 1) - 1 445 | if not (n & 1): 446 | n -= n_diff 447 | n_diff -= 2 448 | for d in xrange((n_diff - 1) << 1, -1, -8): 449 | m = n % 12 450 | if m == 1 or m == 5: 451 | m = n >> 1 452 | sieve[m] = not sieve[m] 453 | n -= d 454 | 455 | x_max, x2, xd = int(sqrt((end-1) / 3.0)), 0, 3 456 | for xd in xrange(3, 6 * x_max + 2, 6): 457 | x2 += xd 458 | y_max = int(sqrt(end-x2)) 459 | n, n_diff = x2 + y_max*y_max, (y_max << 1) - 1 460 | if not(n & 1): 461 | n -= n_diff 462 | n_diff -= 2 463 | for d in xrange((n_diff - 1) << 1, -1, -8): 464 | if n % 12 == 7: 465 | m = n >> 1 466 | sieve[m] = not sieve[m] 467 | n -= d 468 | 469 | x_max, y_min, x2, xd = int((2 + sqrt(4-8*(1-end)))/4), -1, 0, 3 470 | for x in xrange(1, x_max + 1): 471 | x2 += xd 472 | xd += 6 473 | if x2 >= end: y_min = (((int(ceil(sqrt(x2 - end))) - 1) << 1) - 2) << 1 474 | n, n_diff = ((x*x + x) << 1) - 1, (((x-1) << 1) - 2) << 1 475 | for d in xrange(n_diff, y_min, -8): 476 | if n % 12 == 11: 477 | m = n >> 1 478 | sieve[m] = not sieve[m] 479 | n += d 480 | 481 | primes = [2, 3] 482 | if end <= 3: 483 | return primes[:max(0,end-2)] 484 | 485 | for n in xrange(5 >> 1, (int(sqrt(end))+1) >> 1): 486 | if sieve[n]: 487 | primes.append((n << 1) + 1) 488 | aux = (n << 1) + 1 489 | aux *= aux 490 | for k in xrange(aux, end, 2 * aux): 491 | sieve[k >> 1] = False 492 | 493 | s = int(sqrt(end)) + 1 494 | if s % 2 == 0: 495 | s += 1 496 | primes.extend([i for i in xrange(s, end, 2) if sieve[i >> 1]]) 497 | 498 | return primes 499 | 500 | def ambi_sieve_plain(n): 501 | s = range(3, n, 2) 502 | for m in xrange(3, int(n**0.5)+1, 2): 503 | if s[(m-3)/2]: 504 | for t in xrange((m*m-3)/2,(n>>1)-1,m): 505 | s[t]=0 506 | return [2]+[t for t in s if t>0] 507 | 508 | def sundaram3(max_n): 509 | # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/2073279#2073279 510 | numbers = range(3, max_n+1, 2) 511 | half = (max_n)//2 512 | initial = 4 513 | 514 | for step in xrange(3, max_n+1, 2): 515 | for i in xrange(initial, half, step): 516 | numbers[i-1] = 0 517 | initial += 2*(step+1) 518 | 519 | if initial > half: 520 | return [2] + filter(None, numbers) 521 | 522 | ################################################################################ 523 | # Using Numpy: 524 | def ambi_sieve(n): 525 | # http://tommih.blogspot.com/2009/04/fast-prime-number-generator.html 526 | s = np.arange(3, n, 2) 527 | for m in xrange(3, int(n ** 0.5)+1, 2): 528 | if s[(m-3)/2]: 529 | s[(m*m-3)/2::m]=0 530 | return np.r_[2, s[s>0]] 531 | 532 | def primesfrom3to(n): 533 | # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 534 | """ Returns a array of primes, p < n """ 535 | assert n>=2 536 | sieve = np.ones(n/2, dtype=np.bool) 537 | for i in xrange(3,int(n**0.5)+1,2): 538 | if sieve[i/2]: 539 | sieve[i*i/2::i] = False 540 | return np.r_[2, 2*np.nonzero(sieve)[0][1::]+1] 541 | 542 | def primesfrom2to(n): 543 | # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188 544 | """ Input n>=6, Returns a array of primes, 2 <= p < n """ 545 | sieve = np.ones(n/3 + (n%6==2), dtype=np.bool) 546 | sieve[0] = False 547 | for i in xrange(int(n**0.5)/3+1): 548 | if sieve[i]: 549 | k=3*i+1|1 550 | sieve[ ((k*k)/3) ::2*k] = False 551 | sieve[(k*k+4*k-2*k*(i&1))/3::2*k] = False 552 | return np.r_[2,3,((3*np.nonzero(sieve)[0]+1)|1)] 553 | 554 | if __name__=='__main__': 555 | import itertools 556 | import sys 557 | 558 | def test(f1,f2,num): 559 | print('Testing {f1} and {f2} return same results'.format( 560 | f1=f1.func_name, 561 | f2=f2.func_name)) 562 | if not all([a==b for a,b in itertools.izip_longest(f1(num),f2(num))]): 563 | sys.exit("Error: %s(%s) != %s(%s)"%(f1.func_name,num,f2.func_name,num)) 564 | 565 | n=1000000 566 | test(sieveOfAtkin,sieveOfEratosthenes,n) 567 | test(sieveOfAtkin,ambi_sieve,n) 568 | test(sieveOfAtkin,ambi_sieve_plain,n) 569 | test(sieveOfAtkin,sundaram3,n) 570 | test(sieveOfAtkin,sieve_wheel_30,n) 571 | test(sieveOfAtkin,primesfrom3to,n) 572 | test(sieveOfAtkin,primesfrom2to,n) 573 | test(sieveOfAtkin,rwh_primes,n) 574 | test(sieveOfAtkin,rwh_primes1,n) 575 | test(sieveOfAtkin,rwh_primes2,n) 576 | 577 | 执行每一种方法都会得到同一个结果。 578 | 579 | ### 在Python中,自增和自减操作符的表现 580 | 581 | 问题[链接](http://stackoverflow.com/questions/1485841/behaviour-of-increment-and-decrement-operators-in-python) 582 | 583 | `++`不是一个操作符。只是两个`+`操作符, `+`操作符是一个同一性的操作符,什么都做。(解释一下:`+`和`-`作为一元操作符,只对数字起效,但是我假定你不会期望`++`操作符对于字符串也起效) 584 | 585 | ++count 586 | 587 | 其实就是 588 | 589 | +(+count) 590 | 591 | 统一翻译为 592 | 593 | count 594 | 595 | 你可以使用稍微长一点的`+=`操作符来实现你的需求: 596 | 597 | count += 1 598 | 599 | 我怀疑`++`和`--`的存在是为了一致性和简单性。我不能确定Guido van Rossum做这个决定的原因,但是我猜测有以下原因: 600 | 601 | - 只是简单的解析。严格来说,`++count`是模糊的,因为它是`+`,`+`,`count`(两个一元`+`操作符)简化为`++`和`count`(只是一元的`++`操作符),不是什么严重的语病,但是他确实存在。 602 | 603 | - 简单说。`++`只不过是`+= 1`的同义词。它是一个简短的发明,因为C编译器太蠢不能把`a += 1`优化为几乎所有电脑都有的`inc`。这个年代,优化编译器和字节码的解释语言,向语言中添加操作符允许程序员优化他们的代码这种事情通常会引起不满,尤其是像Python这种设计为解释和阅读型的语言。 604 | 605 | - 混乱的副作用。在含有`++`的语言中一个常见的新手错误就是混合了它和pre-,post-自增/自减操作符的区别(无论是优先级,还是返回值),而且Python喜欢消除一些语言陷阱。前期增量后期增量的优先级在C语言中表现的非常糟糕,而且难以置信的容易出错。 606 | 607 | -------------------------------------------------------------------------------- /contents/qa-oop.md: -------------------------------------------------------------------------------- 1 | 2 | ### Python 'self' 解释 3 | 4 | 问题 [链接](http://stackoverflow.com/questions/2709821/python-self-explained) 5 | 6 | 7 | self关键字的作用是什么? 8 | 我理解他用户在创建class时具体化实例,但我无法理解为何需要给每个方法加入self作为参数. 9 | 10 | 举例,在ruby中,我这么做: 11 | 12 | class myClass 13 | def myFunc(name) 14 | @name = name 15 | end 16 | end 17 | 18 | 我可以很好地理解,非常简单.但是在Python中,我需要去加入self: 19 | 20 | class myClass: 21 | def myFunc(self, name): 22 | self.name = name 23 | 24 | 有谁能解释下么? 25 | 26 | 使用self关键字的原因是,Python没有@语法用于引用实例属性.Python决定用一种方式声明方法:实例对象自动传递给属于它的方法,但不是接收自动化:方法的第一个参数是调用这个方法的实例对象本身.这使得方法整个同函数一致,并且由你自己决定真实的名(虽然self是约定,但当你使用其他名的时候,通常人们并不乐意接受).self对于代码不是特殊的,只是另一个对象. 27 | 28 | Python本来可以做一些用来区分真实的名字和属性的区别 —— 像Ruby有的特殊语法,或者像C++/Java的命令声明,或者其他可能的的语法 —— 但是Python没有这么做.Python致力于使事情变得明确简单,让事情是其本身,虽然并不是全部地方都这么做,但是实例属性是这么做的!这就是为什么给一个实例属性赋值时需要知道是给哪个实例赋值,并且,这就是为什么需要self 29 | 30 | 举例 31 | 32 | class Vector(object): 33 | def __init__(self, x, y): 34 | self.x = x 35 | self.y = y 36 | def length(self): 37 | return math.sqrt(self.x ** 2 + self.y ** 2) 38 | 39 | 等价于 40 | 41 | def length_global(vector): 42 | return math.sqrt(vector.x ** 2 + vector.y ** 2) 43 | 44 | 另外 45 | 46 | v_instance.length() 47 | 转为 48 | Vector.length(v_instance) 49 | ### 为什么Python的'private'方法并不是真正的私有方法 50 | 51 | 问题 [链接](http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private) 52 | 53 | Python允许我们创建'private' 函数:变量以两个下划线开头,像这样: *__myPrivateMethod()*. 54 | 但是,如何解释: 55 | 56 | >>> class MyClass: 57 | ... def myPublicMethod(self): 58 | ... print 'public method' 59 | ... def __myPrivateMethod(self): 60 | ... print 'this is private!!' 61 | ... 62 | >>> obj = MyClass() 63 | >>> obj.myPublicMethod() 64 | public method 65 | >>> obj.__myPrivateMethod() 66 | Traceback (most recent call last): 67 | File "", line 1, in 68 | AttributeError: MyClass instance has no attribute '__myPrivateMethod' 69 | >>> dir(obj) 70 | ['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod'] 71 | >>> obj._MyClass__myPrivateMethod() 72 | this is private!! 73 | 74 | 75 | dir(obj) 和 obj._MyClass__myPrivateMethod() 76 | 77 | 78 | 回答 79 | 80 | ‘private'只是用作,确保子类不会意外覆写父类的私有方法和属性.不是为了保护外部意外访问而设计的! 81 | 82 | 例如: 83 | 84 | >>> class Foo(object): 85 | ... def __init__(self): 86 | ... self.__baz = 42 87 | ... def foo(self): 88 | ... print self.__baz 89 | ... 90 | >>> class Bar(Foo): 91 | ... def __init__(self): 92 | ... super(Bar, self).__init__() 93 | ... self.__baz = 21 94 | ... def bar(self): 95 | ... print self.__baz 96 | ... 97 | >>> x = Bar() 98 | >>> x.foo() 99 | 42 100 | >>> x.bar() 101 | 21 102 | >>> print x.__dict__ 103 | {'_Bar__baz': 21, '_Foo__baz': 42} 104 | 105 | 当然,这对于两个同名的类没有作用 106 | 107 | 另外,可以查看diveintopython的解释 [入口](http://www.faqs.org/docs/diveintopython/fileinfo_private.html#d0e11521) 108 | 109 | ### Python中类方法的作用是什么 110 | 111 | 问题 [链接](http://stackoverflow.com/questions/38238/what-are-class-methods-in-python-for) 112 | 113 | 114 | 我现在意识到,我不需要像我在使用java的static方法那样使用类方法,但是我不确定什么时候使用 115 | 116 | 谁能通过一个好的例子解释下Python中的类方法,至少有人能告诉我什么时候确实需要使用类方法 117 | 118 | 119 | 类方法用在:当你需要使用不属于任何明确实例的方法,但同时必须涉及类.有趣的是,你可以在子类中覆写,这在Java的static方法和Python的模块级别函数中是不可能做到的 120 | 121 | 如果你有一个MyClass, 并且一个模块级别函数操作MyClass(工厂,依赖注入桩等等), 声明一个类方法.然后这个类方法可以在子类中调用 122 | 123 | ### Python中 __new__ 和 __init__的用法 124 | 125 | 问题 [链接](http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init) 126 | 127 | 我很疑惑,为何__init__总是在__new__之后调用 128 | 129 | 如下 130 | 131 | class A(object): 132 | _dict = dict() 133 | 134 | def __new__(cls): 135 | if 'key' in A._dict: 136 | print "EXISTS" 137 | return A._dict['key'] 138 | else: 139 | print "NEW" 140 | return super(A, cls).__new__(cls) 141 | 142 | def __init__(self): 143 | print "INIT" 144 | A._dict['key'] = self 145 | print "" 146 | 147 | a1 = A() 148 | a2 = A() 149 | a3 = A() 150 | 151 | 输出 152 | 153 | NEW 154 | INIT 155 | 156 | EXISTS 157 | INIT 158 | 159 | EXISTS 160 | INIT 161 | 162 | 有木有人可以解释一下 163 | 164 | 来自 [链接](http://mail.python.org/pipermail/tutor/2008-April/061426.html) 165 | 166 | 167 | 使用__new__,当你需要控制一个实例的生成 168 | 169 | 使用__init__,当你需要控制一个实例的初始化 170 | 171 | __new__是实例创建的第一步.最先被调用,并且负责返回类的一个新实例. 172 | 173 | 相反的,__init__不返回任何东西,只是负责在实例创建后进行初始化 174 | 175 | 通常情况下,你不必重写__new__除非你写一个子类继承不可变类型,例如str,int,unicode或tuple 176 | 177 | 178 | 你必须了解到,你尝试去做的用[Factory](http://en.wikipedia.org/wiki/Factory_object)可以很好地解决,并且是最好的解决方式.使用__new__不是一个简洁的处理方式,一个[factory例子](http://code.activestate.com/recipes/86900/) 179 | 180 | 181 | ### 如何获取一个实例的类名 182 | 183 | 问题 [链接](http://stackoverflow.com/questions/510972/getting-the-class-name-of-an-instance-in-python) 184 | 185 | x.__class__.__name__ 186 | 187 | ### @staticmethod和@classmethod的区别 188 | 189 | 问题 [链接](http://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python) 190 | 191 | staticmethod,静态方法在调用时,对类及实例一无所知 192 | 193 | 仅仅是获取传递过来的参数,没有隐含的第一个参数,在Python里基本上用处不大,你完全可以用一个模块函数替换它 194 | 195 | classmethod, 在调用时,将会获取到其所在的类,或者类实例,作为其第一个参数 196 | 197 | 当你想将函数作为一个类工厂时,这非常有用: 第一个参数是类,你可以实例化出对应实例对象,甚至子类对象。 198 | 199 | 可以观察下 dict.fromkey(),是一个类方法,当子类调用时,返回子类的实例 200 | 201 | >>> class DictSubclass(dict): 202 | ... def __repr__(self): 203 | ... return "DictSubclass" 204 | ... 205 | >>> dict.fromkeys("abc") 206 | {'a': None, 'c': None, 'b': None} 207 | >>> DictSubclass.fromkeys("abc") 208 | DictSubclass 209 | >>> 210 | 211 | ### 如何定义静态方法(static method) 212 | 213 | 问题 [链接](http://stackoverflow.com/questions/735975/static-methods-in-python) 214 | 215 | 使用 [staticmethod](http://docs.python.org/2/library/functions.html#staticmethod)装饰器 216 | 217 | 218 | class MyClass(object): 219 | @staticmethod 220 | def the_static_method(x): 221 | print x 222 | MyClass.the_static_method(2) # outputs 2 223 | 224 | ### Python中的类变量(环境变量) 225 | 226 | 问题 [链接](http://stackoverflow.com/questions/68645/static-class-variables-in-python) 227 | 228 | 在类中定义的变量,不在方法定义中,成为类变量或静态变量 229 | 230 | >>> class MyClass: 231 | ... i = 3 232 | ... 233 | >>> MyClass.i 234 | 3 235 | 236 | i是类级别的变量,但这里要和实例级别的变量i区分开 237 | 238 | >>> m = MyClass() 239 | >>> m.i = 4 240 | >>> MyClass.i, m.i 241 | >>> (3, 4) 242 | 243 | 这和C++/java完全不同,但和C#区别不大,C#不允许类实例获取静态变量 244 | 245 | 具体见 [what the Python tutorial has to say on the subject of classes and class objects](http://docs.python.org/2/tutorial/classes.html#SECTION0011320000000000000000) 246 | 247 | 另外,静态方法 248 | 249 | class C: 250 | @staticmethod 251 | def f(arg1, arg2, ...): ... 252 | 253 | ### 如何判断一个对象是否拥有某个属性 254 | 255 | 问题 [链接](http://stackoverflow.com/questions/610883/how-to-know-if-an-object-has-an-attribute-in-python) 256 | 257 | if hasattr(a, 'property'): 258 | a.property 259 | 260 | 两种风格 261 | 262 | EAFP(easier to ask for forgiveness than permission) 263 | 264 | LBYL(look before you leap) 265 | 266 | 相关内容 267 | [EAFP vs LBYL (was Re: A little disappointed so far)](http://web.archive.org/web/20070929122422/http://mail.python.org/pipermail/python-list/2003-May/205182.html) 268 | [EAFP vs. LBYL @Code Like a Pythonista: Idiomatic Python](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#eafp-vs-lbyl) 269 | 270 | try: 271 | doStuff(a.property) 272 | except AttributeError: 273 | otherStuff() 274 | or 275 | 276 | if hasattr(a, 'property'): 277 | doStuff(a.property) 278 | else: 279 | otherStuff() 280 | 281 | ### Python中有没有简单优雅的方式定义单例类 282 | 283 | 问题 [链接](http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python) 284 | 285 | 我不认为有必要,一个拥有函数的模块(不是类)可以作为很好的单例使用,它的所有变量被绑定到这个模块,无论如何都不能被重复实例化 286 | 287 | 如果你确实想用一个类来实现,在python中不能创建私有类或私有构造函数,所以你不能隔离多个实例而仅仅通过自己的API来访问属性 288 | 289 | 我还是认为将函数放入模块,并将其作为一个单例来使用是最好的办法 290 | 291 | ### 理解Python的Super()和init方法 292 | 293 | 问题 [链接](http://stackoverflow.com/questions/576169/understanding-python-super-and-init-methods) 294 | 295 | 尝试着去理解super().从表面上看,两个子类都能正常创建.我只是好奇他们两者之间的不同点 296 | 297 | class Base(object): 298 | def __init__(self): 299 | print "Base created" 300 | 301 | class ChildA(Base): 302 | def __init__(self): 303 | Base.__init__(self) 304 | 305 | class ChildB(Base): 306 | def __init__(self): 307 | super(ChildB, self).__init__() 308 | 309 | print ChildA(),ChildB() 310 | 311 | 回答 312 | 313 | Super让你避免明确地引用基类,这是一点。最大的优势是,当出现多重继承的时候,各种[有趣的情况](http://www.artima.com/weblogs/viewpost.jsp?thread=236275)就会出现。查看super[官方文档](http://docs.python.org/library/functions.html#super). 314 | 315 | 另外注意,在Python3.0中,可以使用super().__init__() 代替 super(ChildB, self).__init__().IMO略有优势. 316 | 317 | 318 | ### 在Python中,如何判断一个对象iterable? 319 | 320 | 问题 [链接](http://stackoverflow.com/questions/1952464/in-python-how-do-i-determine-if-an-object-is-iterable) 321 | 322 | 1. 检查__iter__对序列类型有效,但是对例如string,无效 323 | 324 | 325 | try: 326 | iterator = iter(theElement) 327 | except TypeError: 328 | # not iterable 329 | else: 330 | # iterable 331 | 332 | # for obj in iterator: 333 | # pass 334 | 335 | 2. 使用collections 336 | 337 | import collections 338 | 339 | if isinstance(e, collections.Iterable): 340 | # e is iterable 341 | 342 | ### 构建一个基本的Python迭代器 343 | 344 | 问题[链接](http://stackoverflow.com/questions/19151/build-a-basic-python-iterator) 345 | 346 | 在Python中,迭代器对象遵循迭代器协议,这意味着它提供了两种方法: `__iter__()`和`next()`。`__iter__()`返回一个迭代器对象并且在循环开始时就隐式的被调用。`next()`方法返回下一个值,并在循环的每一次增量中被调用。当没有值需要返回时,`next()`引发一个StopIteration异常,这个异常被循环结构隐式的捕获从而停止迭代。 347 | 348 | 这有一个简单计数例子: 349 | 350 | class Counter: 351 | def __init__(self, low, high): 352 | self.current = low 353 | self.high = high 354 | 355 | def __iter__(self): 356 | return self 357 | 358 | def next(self): # Python 3: def __next__(self) 359 | if self.current > self.high: 360 | raise StopIteration 361 | else: 362 | self.current += 1 363 | return self.current - 1 364 | 365 | for c in Counter(3, 8): 366 | print c 367 | 368 | 上述会打印出: 369 | 370 | 3 371 | 4 372 | 5 373 | 6 374 | 7 375 | 8 376 | 377 | 这个用生成器写会更简单一些,下面是之前答案的翻写: 378 | 379 | def counter(low, high): 380 | current = low 381 | while current <= high: 382 | yield current 383 | current += 1 384 | 385 | for c in counter(3, 8): 386 | print c 387 | 388 | 打印出来的内容是一样的。在后台,生成器对象支持迭代器协议,大体上对Counter类做一些同样事情。 389 | 390 | [Iterators and Simple Generators](http://www.ibm.com/developerworks/library/l-pycon.html),David Mertz的这篇文章,是一篇对迭代器非常好的介绍。 391 | 392 | ### 在Python中,抽象类和接口有什么区别? 393 | 394 | 问题[链接](http://stackoverflow.com/questions/372042/difference-between-abstract-class-and-interface-in-python) 395 | 396 | 看看下面这个: 397 | 398 | class Abstract1(object): 399 | """Some description that tells you it's abstract, 400 | often listing the methods you're expected to supply.""" 401 | def aMethod(self): 402 | raise NotImplementedError( "Should have implemented this" ) 403 | 404 | 因为在Python中没有(也不需要)一个正式的接口协议,类Java的抽象类和接口的区别并不存在。如果有人尝试定义一个正式的接口,它其实也是一个抽象类。唯一的不同就是在文档注释的表述。 405 | 406 | 并且当你使用鸭子类型时,抽象类和接口的区别有点吹毛求疵了。 407 | 408 | Java使用接口是因为它没有多重继承。 409 | 410 | 因为Python有多重继承,你可能还会看到类似这样的东西: 411 | 412 | class SomeAbstraction( object ): 413 | pass # lots of stuff - but missing something 414 | 415 | class Mixin1( object ): 416 | def something( self ): 417 | pass # one implementation 418 | 419 | class Mixin2( object ): 420 | def something( self ): 421 | pass # another 422 | 423 | class Concrete1( SomeAbstraction, Mixin1 ): 424 | pass 425 | 426 | class Concrete2( SomeAbstraction, Mixin2 ): 427 | pass 428 | 429 | 这是一种使用混合抽象超类去创建不相交的具体子类的方法。 430 | 431 | ### Python 的__slots__ 432 | 433 | 问题[链接](http://stackoverflow.com/questions/472000/python-slots) 434 | 435 | 引用[Jacob Hallen](http://code.activestate.com/lists/python-list/531365/): 436 | 437 | `__slots__`的正确使用方法是保存对象的空间。取代使用允许任何时间给类添加属性的动态字典,有一种在创建之后不允许添加的静态结构。使用slots节省了给所有对象同一个字典的系统开销。有时候这是一个很有效的优化,但它也会变得毫无用处,前提是Python的解释器足够动态化,可以在确实需要为对象增加某些东西时只需要字典。 438 | 439 | 不幸的是,使用slots有一个副作用。他们通过一种方法改变了那些带有slots的对象的表现形式,使它们被古怪的控制者和细小的静态归类滥用。这很糟糕,因为古怪的控制者应该滥用元类,而细小的静态归类应该滥用生成器。但是从Python开始,只有这一种显著的方法了。 440 | 441 | 将CPython做的很聪明,聪明到可以不用`__slots__`保存空间,是一个主要的工作,这也就是为什么它不在P3k的更改列表中(到目前为止)。 442 | 443 | ### Python中,新式类和旧式类的区别 444 | 445 | 问题[链接](http://stackoverflow.com/questions/54867/what-is-the-difference-between-old-style-and-new-style-classes-in-python) 446 | 447 | 根据[https://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes](https://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classeshttps://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes): 448 | 449 | Up to Python 2.1, old-style classes were the only flavour available to the user. The concept of (old-style) class is unrelated to the concept of type: if x is an instance of an old-style class, then x.__class__ designates the class of x, but type(x) is always . This reflects the fact that all old-style instances, independently of their class, are implemented with a single built-in type, called instance. 450 | 451 | New-style classes were introduced in Python 2.2 to unify classes and types. A new-style class neither more nor less than a user-defined type. If x is an instance of a new-style class, then type(x) is the same as x.__class__. 452 | 453 | The major motivation for introducing new-style classes is to provide a unified object model with a full meta-model. It also has a number of immediate benefits, like the ability to subclass most built-in types, or the introduction of "descriptors", which enable computed properties. 454 | 455 | For compatibility reasons, classes are still old-style by default. New-style classes are created by specifying another new-style class (i.e. a type) as a parent class, or the "top-level type" object if no other parent is needed. The behaviour of new-style classes differs from that of old-style classes in a number of important details in addition to what type returns. Some of these changes are fundamental to the new object model, like the way special methods are invoked. Others are "fixes" that could not be implemented before for compatibility concerns, like the method resolution order in case of multiple inheritance. 456 | 457 | Python 3 only has new-style classes. No matter if you subclass from object or not, classes are new-style in Python 3. It is however recommended that you still subclass from object. 458 | 459 | ### Python中,@property和设置-获取哪一个更好 460 | 461 | 问题[链接](http://stackoverflow.com/questions/6618002/python-property-versus-getters-and-setters) 462 | 463 | 用属性更好,这也是他们存在的原因。 464 | 465 | 原因是在Python中,所有属性都是公共的。名字由单下划线或双下划线开始的,只不过是一个警告,表示这个属性的值在只是一个执行细节,在未来的版本中可能不会保持一致。他并没有阻止你去获取或者设置这个属性。因此,标准的属性访问途径便是是公认最好的,Pythonic的。 466 | 467 | 属性的优点是他们和访问属性的语法上保持一致,所以你可以在不改变客户端的情况下把属性从一个改变成另一个值。你甚至可以有一个不再生产环境版本的类用来保存属性,不用改变代码就可以使用它们(用来debug或者上下文代码)。同时,你不需要为所有东西写获取和设置因为在之后你可能需要更好的控制。 468 | 469 | ### 在Python中,链式调用父类构造器 470 | 471 | 问题[链接](http://stackoverflow.com/questions/904036/chain-calling-parent-constructors-in-python) 472 | 473 | 你正在做的事情,确实是值得推荐的(对于Python 2.x来说) 474 | 475 | 是否把类明确的传递给`super`是一个风格而不是功能上的问题。把类明确的传递给`super`符合Python哲学的“明了胜于晦涩”。 476 | 477 | ### Python中,一个对象前面带单下划线和双下划线的含义 478 | 479 | 问题[链接](http://stackoverflow.com/questions/1301346/the-meaning-of-a-single-and-a-double-underscore-before-an-object-name-in-python) 480 | 481 | 单下划线 482 | 483 | 在一个类中,单下划线开头的单纯为了告诉其他程序员,这些属性或者方法意味着私有的。然而,这些属性或者方法本身并没什么特别的。 484 | 485 | 引述[PEP-8](http://www.python.org/dev/peps/pep-0008/): 486 | 487 | _single_leading_underscore: weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an underscore. 488 | 489 | 双下划线 490 | 491 | 来自[Python文档](http://docs.python.org/tutorial/classes.html#private-variables-and-class-local-references): 492 | 493 | Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methods, variables stored in globals, and even variables stored in instances. private to this class on instances of other classes. 494 | 495 | 同一页还有一个警告: 496 | 497 | Name mangling is intended to give classes an easy way to define “private” instance variables and methods, without having to worry about instance variables defined by derived classes, or mucking with instance variables by code outside the class. Note that the mangling rules are designed mostly to avoid accidents; it still is possible for a determined soul to access or modify a variable that is considered private. 498 | 499 | 举例 500 | 501 | >>> class MyClass(): 502 | ... def __init__(self): 503 | ... self.__superprivate = "Hello" 504 | ... self._semiprivate = ", world!" 505 | ... 506 | >>> mc = MyClass() 507 | >>> print mc.__superprivate 508 | Traceback (most recent call last): 509 | File "", line 1, in 510 | AttributeError: myClass instance has no attribute '__superprivate' 511 | >>> print mc._semiprivate 512 | , world! 513 | >>> print mc.__dict__ 514 | {'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'} 515 | 516 | ### 在一个已存在的对象里,加一个方法 517 | 518 | 问题[链接](http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object) 519 | 520 | 在Python中,函数和约束方法还是有一些区别。 521 | 522 | >> def foo(): 523 | ... print "foo" 524 | ... 525 | >>> class A: 526 | ... def bar( self ): 527 | ... print "bar" 528 | ... 529 | >>> a = A() 530 | >>> foo 531 | 532 | >>> a.bar 533 | > 534 | >>> 535 | 536 | 约束方法被约束到一个实例上,当方法调用时这个实例会被当做第一个参数传入。 537 | 538 | 在类(与实例相反)中,那些作为属性的可调用者仍然能是有限制的,尽管,你可以随时修改这个类的定义。 539 | 540 | >>> def fooFighters( self ): 541 | ... print "fooFighters" 542 | ... 543 | >>> A.fooFighters = fooFighters 544 | >>> a2 = A() 545 | >>> a2.fooFighters 546 | > 547 | >>> a2.fooFighters() 548 | fooFighters 549 | 550 | 这样之前定义的实例也回随着更新(只要他们没有重写这个属性): 551 | 552 | >>> a.fooFighters() 553 | fooFighters 554 | 555 | 问题出现在当你想把一个方法固定在某一个实例时: 556 | 557 | >>> def barFighters( self ): 558 | ... print "barFighters" 559 | ... 560 | >>> a.barFighters = barFighters 561 | >>> a.barFighters() 562 | Traceback (most recent call last): 563 | File "", line 1, in 564 | TypeError: barFighters() takes exactly 1 argument (0 given) 565 | 566 | 当你想直接固定到一个实例上时,函数不是自动约束的: 567 | 568 | >>> a.barFighters 569 | 570 | 571 | 为了绑定它,我盟可以用[types模块中的方法类函数](http://docs.python.org/library/types.html?highlight=methodtype#module-types): 572 | 573 | >>> import types 574 | >>> a.barFighters = types.MethodType( barFighters, a ) 575 | >>> a.barFighters 576 | > 577 | >>> a.barFighters() 578 | barFighters 579 | 580 | 这时候,类的其他实例不会受到影响: 581 | 582 | >>> a2.barFighters() 583 | Traceback (most recent call last): 584 | File "", line 1, in 585 | AttributeError: A instance has no attribute 'barFighters' 586 | 587 | 更多的信息,可以在阅读[descriptors](http://users.rcn.com/python/download/Descriptor.htm)和[metaclass](http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html)以及[programming](http://www.gnosis.cx/publish/programming/metaclass_2.html)中发现。 588 | 589 | ### 在Python中,metaclass是什么 590 | 591 | 问题[链接](http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python/6581949#6581949) 592 | 593 | **类对象** 594 | 595 | 在理解metaclass之前,你需要掌握Python中的类。而且Python的类的设计,非常的特别,借鉴了Smalltalk语言。 596 | 597 | 大多数语言中,类只是一段代码用来描述如何生产一个对象。在Python中也有几分这个意思: 598 | 599 | >>> class ObjectCreator(object): 600 | ... pass 601 | ... 602 | 603 | >>> my_object = ObjectCreator() 604 | >>> print(my_object) 605 | <__main__.ObjectCreator object at 0x8974f2c> 606 | 607 | 但是Python中的类不仅仅如此。类,也是对象。 608 | 609 | 对,对象。 610 | 611 | 当你使用`class`这个关键字时,Python执行它并创造一个对象,示例: 612 | 613 | >>> class ObjectCreator(object): 614 | ... pass 615 | ... 616 | 617 | 在内存中创建了一个对象名字是"ObjectCreator"。 618 | 619 | 这个对象(类)有能力创造对象(实例),这也是为什么它是类。 620 | 621 | 但它仍然是一个类,因此: 622 | 623 | - 你可以把它当做一个变量 624 | 625 | - 你可以复制它 626 | 627 | - 你可以给它添加属性 628 | 629 | - 你可以把它当成一个函数的参数 630 | 631 | 举例: 632 | 633 | >>> print(ObjectCreator) # you can print a class because it's an object 634 | 635 | >>> def echo(o): 636 | ... print(o) 637 | ... 638 | >>> echo(ObjectCreator) # you can pass a class as a parameter 639 | 640 | >>> print(hasattr(ObjectCreator, 'new_attribute')) 641 | False 642 | >>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class 643 | >>> print(hasattr(ObjectCreator, 'new_attribute')) 644 | True 645 | >>> print(ObjectCreator.new_attribute) 646 | foo 647 | >>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable 648 | >>> print(ObjectCreatorMirror.new_attribute) 649 | foo 650 | >>> print(ObjectCreatorMirror()) 651 | <__main__.ObjectCreator object at 0x8997b4c> 652 | 653 | 动态创建类 654 | 655 | 类就是对象,你可以快速创建它,像任何其他对象一样。 656 | 657 | 首先,你可以在一个函数里创建一个类,用`class`: 658 | 659 | >>> def choose_class(name): 660 | ... if name == 'foo': 661 | ... class Foo(object): 662 | ... pass 663 | ... return Foo # return the class, not an instance 664 | ... else: 665 | ... class Bar(object): 666 | ... pass 667 | ... return Bar 668 | ... 669 | >>> MyClass = choose_class('foo') 670 | >>> print(MyClass) # the function returns a class, not an instance 671 | 672 | >>> print(MyClass()) # you can create an object from this class 673 | <__main__.Foo object at 0x89c6d4c> 674 | 675 | 但是它不是很动态,你仍然需要手写你的类。 676 | 677 | 既然类是对象,他们一定可以被什么东西生成。 678 | 679 | 当你使用`class`关键字时,Python自动创建了这个对象,但是像Python中的其他东西一样,它给你了一个方法手动实现。 680 | 681 | 还记得`type`函数吗。一个让你知道对象类型的古老的函数: 682 | 683 | >>> print(type(1)) 684 | 685 | >>> print(type("1")) 686 | 687 | >>> print(type(ObjectCreator)) 688 | 689 | >>> print(type(ObjectCreator())) 690 | 691 | 692 | 哦,`type`有另外一种完全不同的功能,它也可以迅速创建类。`type`可以把类的描述作为参数,并返回一个类。 693 | 694 | (我知道同一个函数根据你传入的值有两种不同的用法是很蠢的,但是它是Python中的一种向后兼容的问题) 695 | 696 | `type`这样工作: 697 | 698 | type(name of the class, 699 | tuple of the parent class (for inheritance, can be empty), 700 | dictionary containing attributes names and values) 701 | 702 | 举个例子 703 | 704 | >>> class MyShinyClass(object): 705 | ... pass 706 | 707 | 可以通过这种方法手动生成: 708 | 709 | >>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object 710 | >>> print(MyShinyClass) 711 | 712 | >>> print(MyShinyClass()) # create an instance with the class 713 | <__main__.MyShinyClass object at 0x8997cec> 714 | 715 | 你可能会注意到我们使用"MyShinyClass"做为类的名字并且作为变量并且作为类的参考。他们可以不同,但是没有必要把事情搞复杂。 716 | 717 | `type`接受一个字典,定义一个类的参数,所以: 718 | 719 | >>> class Foo(object): 720 | ... bar = True 721 | 722 | 可以理解成: 723 | 724 | >>> Foo = type('Foo', (), {'bar':True}) 725 | 726 | 并且可以当成一个普通类来使用: 727 | 728 | >>> print(Foo) 729 | 730 | >>> print(Foo.bar) 731 | True 732 | >>> f = Foo() 733 | >>> print(f) 734 | <__main__.Foo object at 0x8a9b84c> 735 | >>> print(f.bar) 736 | True 737 | 738 | 当然,你可以继承它,所以: 739 | 740 | >>> class FooChild(Foo): 741 | ... pass 742 | 743 | 可以是: 744 | 745 | >>> FooChild = type('FooChild', (Foo,), {}) 746 | >>> print(FooChild) 747 | 748 | >>> print(FooChild.bar) # bar is inherited from Foo 749 | True 750 | 751 | 最后你可能想要在你的类里添加方法。只要适当的定义一个函数,然后把它标记为属性。 752 | 753 | >>> def echo_bar(self): 754 | ... print(self.bar) 755 | ... 756 | >>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar}) 757 | >>> hasattr(Foo, 'echo_bar') 758 | False 759 | >>> hasattr(FooChild, 'echo_bar') 760 | True 761 | >>> my_foo = FooChild() 762 | >>> my_foo.echo_bar() 763 | True 764 | 765 | 可以回顾一下:在Python中,类就是对象,你可以动态的创造一个类。 766 | 767 | 这就是当你使用`class`关键字时Python做的事情,使用metaclass时,也是一样的。 768 | 769 | **什么是metaclass(最终版本)** 770 | 771 | Metaclass是创建类的原料。 772 | 773 | 你定义类就是为了创建对象,对不对? 774 | 775 | 但是我们知道Python类本身就是对象。 776 | 777 | 所以,这些对象就是metaclass创建的。他们是类的类,你可以这样表述: 778 | 779 | MyClass = MetaClass() 780 | MyObject = MyClass() 781 | 782 | 刚才你看到了`type`允许你做类似这样的事情: 783 | 784 | MyClass = type('MyClass', (), {}) 785 | 786 | 这是因为`type`这个函数实际上是一个metaclass。`type`就是metaclass -- Python用来在后台创造一切类。 787 | 788 | 现在你知道为什么这个东西他喵的写成小写的,而不是`Type`了吧。 789 | 790 | 嗯,我想同样的问题可能发生在用来创造字符串对象的`str`这个类上,`int`是创造整数对象的类,`type`是用来创造类对象的类。 791 | 792 | 通过查看`__class__`参数验证。 793 | 794 | 所有的东西,我是说所有,在Python中都是对象。包括整数,字符串,函数,类。他们全是对象。他们全都由一个类创造而来: 795 | 796 | >>> age = 35 797 | >>> age.__class__ 798 | 799 | >>> name = 'bob' 800 | >>> name.__class__ 801 | 802 | >>> def foo(): pass 803 | >>> foo.__class__ 804 | 805 | >>> class Bar(object): pass 806 | >>> b = Bar() 807 | >>> b.__class__ 808 | 809 | 810 | 现在,看看所有的`__class__`的`__class__`是什么? 811 | 812 | >>> age.__class__.__class__ 813 | 814 | >>> name.__class__.__class__ 815 | 816 | >>> foo.__class__.__class__ 817 | 818 | >>> b.__class__.__class__ 819 | 820 | 821 | 所以,metaclass就是用来创造类对象的原料。 822 | 823 | 如果你想,你可以把他叫做类工厂。 824 | 825 | `type`是Python使用的内建的metaclass,当然,你可以创造你自己的metaclass。 826 | 827 | **`__metaclass__`属性** 828 | 829 | 你可以给你写的类添加一个`__metaclass__`属性: 830 | 831 | class Foo(object): 832 | __metaclass__ = something... 833 | [...] 834 | 835 | 如果你这样做,Python会使用metaclass创建`Foo`这个类。 836 | 837 | 小心点,这很复杂。 838 | 839 | 你先写了`class Foo(object)`,但是现在在内存中,还没有创建这个类对象`Foo`。 840 | 841 | Python会在类的定义时,检查`__metaclass__`。如果找到了,Python就用它创造一个类对象`Foo`。如果没有,就用`type`创造类。 842 | 843 | 多读几次。 844 | 845 | 当你这样: 846 | 847 | class Foo(Bar): 848 | pass 849 | 850 | Python会做下面这些事情: 851 | 852 | `Foo`里面有`__metaclass__`这个属性吗? 853 | 854 | 如果有,在内存中创建一个类对象(我是说一个类对象,与我同在)通过使用`__metaclass__`创建一个同样的名字`Foo`。 855 | 856 | 如果Python找不到`__metaclass__`,它会在模块层找这个`__metaclass__`,试图通过同样的方式。(但是仅对于那些没有继承任何东西的类,基本上都是旧式类) 857 | 858 | 之后,如果哪都找不到`__metaclass__`,就使用`Bar`(第一层父类)自带的metaclass(有可能就是缺省的`type`)来创建类对象。 859 | 860 | 注意,这里的`__metaclass__`不会被继承,父类的会被继承(`Bar.__class__`)。如果`Bar`使用一个用`type`(而不是`type.__new__()`)创建`Bar`本身的`__metaclass__`属性,那么子类不会继承这个行为。 861 | 862 | 现在一个大问题出现了,你可以在`__metaclass__`里面放什么呢? 863 | 864 | 答案是:一些可以创建类的东西。 865 | 866 | 然而什么可以创建类的呢?`type`或者是它的任何子类,或者使用它的东西。 867 | 868 | **惯用的metaclass ** 869 | 870 | 一个metaclass的主要目的就是当一个类创建的时候,自动的改变它。 871 | 872 | 你通常对接口做这些事情,比如你想要创建一个符合当前上下文的类。 873 | 874 | 试想一个愚蠢的例子,你决定让你的模块里的所有类的所有属性都用大写。有几种方法可以实现,其中一种是在模块层使用`__metaclass__`。 875 | 876 | 通过这种方法,该模块的所有类在创建时都会使用这个metaclass,而我们只需要告诉metaclass把所有属性都变成大写。 877 | 878 | 幸运的是,`__metaclass__`可以通过任何方式调用,不需要一个正规的类(我知道,有些名字里带着class的东西不一定是类,想想看吧,它很有用)。 879 | 880 | 所以我们通过一个函数,从简单的例子开始: 881 | 882 | # the metaclass will automatically get passed the same argument 883 | # that you usually pass to `type` 884 | def upper_attr(future_class_name, future_class_parents, future_class_attr): 885 | """ 886 | Return a class object, with the list of its attribute turned 887 | into uppercase. 888 | """ 889 | 890 | # pick up any attribute that doesn't start with '__' and uppercase it 891 | uppercase_attr = {} 892 | for name, val in future_class_attr.items(): 893 | if not name.startswith('__'): 894 | uppercase_attr[name.upper()] = val 895 | else: 896 | uppercase_attr[name] = val 897 | 898 | # let `type` do the class creation 899 | return type(future_class_name, future_class_parents, uppercase_attr) 900 | 901 | __metaclass__ = upper_attr # this will affect all classes in the module 902 | 903 | class Foo(): # global __metaclass__ won't work with "object" though 904 | # but we can define __metaclass__ here instead to affect only this class 905 | # and this will work with "object" children 906 | bar = 'bip' 907 | 908 | print(hasattr(Foo, 'bar')) 909 | # Out: False 910 | print(hasattr(Foo, 'BAR')) 911 | # Out: True 912 | 913 | f = Foo() 914 | print(f.BAR) 915 | # Out: 'bip' 916 | 917 | 现在,我们做同样的事情,但是对metaclass使用真正的类: 918 | 919 | # remember that `type` is actually a class like `str` and `int` 920 | # so you can inherit from it 921 | class UpperAttrMetaclass(type): 922 | # __new__ is the method called before __init__ 923 | # it's the method that creates the object and returns it 924 | # while __init__ just initializes the object passed as parameter 925 | # you rarely use __new__, except when you want to control how the object 926 | # is created. 927 | # here the created object is the class, and we want to customize it 928 | # so we override __new__ 929 | # you can do some stuff in __init__ too if you wish 930 | # some advanced use involves overriding __call__ as well, but we won't 931 | # see this 932 | def __new__(upperattr_metaclass, future_class_name, 933 | future_class_parents, future_class_attr): 934 | 935 | uppercase_attr = {} 936 | for name, val in future_class_attr.items(): 937 | if not name.startswith('__'): 938 | uppercase_attr[name.upper()] = val 939 | else: 940 | uppercase_attr[name] = val 941 | 942 | return type(future_class_name, future_class_parents, uppercase_attr) 943 | 944 | 但是这并不符合面向对象的思想。我们直接调用`type`,不重写或者调用父类的`__new__`方法。试一下: 945 | 946 | class UpperAttrMetaclass(type): 947 | 948 | def __new__(upperattr_metaclass, future_class_name, 949 | future_class_parents, future_class_attr): 950 | 951 | uppercase_attr = {} 952 | for name, val in future_class_attr.items(): 953 | if not name.startswith('__'): 954 | uppercase_attr[name.upper()] = val 955 | else: 956 | uppercase_attr[name] = val 957 | 958 | # reuse the type.__new__ method 959 | # this is basic OOP, nothing magic in there 960 | return type.__new__(upperattr_metaclass, future_class_name, 961 | future_class_parents, uppercase_attr) 962 | 963 | 你可能会主要到多余的参数`upperattr_metaclass`。它没什么特殊的:一个方法总是接受当前的实例作为第一个参数。就像你在普通的方法中使用`self`。 964 | 965 | 当然,我这里使用这么长的名字是为了更清楚,但是像`self`一样,所有参数有惯用的名字。所以一个真正的生产环境的metaclass看起来可能是这样: 966 | 967 | class UpperAttrMetaclass(type): 968 | 969 | def __new__(cls, clsname, bases, dct): 970 | 971 | uppercase_attr = {} 972 | for name, val in dct.items(): 973 | if not name.startswith('__'): 974 | uppercase_attr[name.upper()] = val 975 | else: 976 | uppercase_attr[name] = val 977 | 978 | return type.__new__(cls, clsname, bases, uppercase_attr) 979 | 980 | 我们可以通过使用`super`简化继承,让它更清晰。(因此,你可以拥有metaclasses,继承metaclass,继承type) 981 | 982 | class UpperAttrMetaclass(type): 983 | 984 | def __new__(cls, clsname, bases, dct): 985 | 986 | uppercase_attr = {} 987 | for name, val in dct.items(): 988 | if not name.startswith('__'): 989 | uppercase_attr[name.upper()] = val 990 | else: 991 | uppercase_attr[name] = val 992 | 993 | return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr) 994 | 995 | 差不多就这样,metaclass真没什么更多的内容了。 996 | 997 | 使用metaclass的代码非常复杂的背后原因不是metaclass本身,而是你把metaclass用在了那些自我实现,多重继承的东西上,比如`__dict__`等等。 998 | 999 | 总之,metaclass有特殊的技巧实现黑魔法,当然包括复杂的东西。但是对他们自己来说,他们很简单: 1000 | 1001 | - 拦截一个类的创建 1002 | 1003 | - 装饰一个类 1004 | 1005 | - 返回装饰过的类 1006 | 1007 | **为什么使用metaclass替代函数** 1008 | 1009 | 既然`__metaclass__`可以接受任何调用,为什么你还要使用明显更复杂的类呢? 1010 | 1011 | 有几个原因: 1012 | 1013 | - 目的更明确。当你看到`UpperAttrMetaclass(type)`的时候就,你知道接下去会发生什么 1014 | 1015 | - 你可以使用面向对象,metaclass可以继承metaclass,重写父类的方法,Metaclass也可以使用metaclass。 1016 | 1017 | - 你可以更好的组织你的代码结构。不要像上面的例子哪样琐碎的使用metaclass。对某些东西来说它通常是复杂的。创造几个方法并把它们整合到一个类里是很有用的,可以让代码更易读。 1018 | 1019 | - 关联使用`__new__`,`__init__`,和`__call__`。它们允许你做不同的东西,尽管你可以把它们都做在`__new__`里面,有些人用`__init__`更舒服。 1020 | 1021 | - 这些都叫metaclass,靠,它们肯定很有意义。 1022 | 1023 | **你他喵为什么会使用metaclass** 1024 | 1025 | 现在有一个大问题,为什么使用这种倾向于引起不清晰的错误的特性? 1026 | 1027 | 通常你不会这样: 1028 | 1029 | Metaclass的99%的使用者都不必担心它的深度魔法。如果你不知道你是否需要它们,就别用(那些需要它们的人知道为何用它们,而且不需要解释) 1030 | 1031 | *Python Guru Tim Peters* 1032 | 1033 | metaclass的主要作用就是创造一个接口。典型的用法就是Django ORM。 1034 | 1035 | 它允许你这样定义这些东西: 1036 | 1037 | class Person(models.Model): 1038 | name = models.CharField(max_length=30) 1039 | age = models.IntegerField() 1040 | 1041 | 但是你这样用: 1042 | 1043 | guy = Person(name='bob', age='35') 1044 | print(guy.age) 1045 | 1046 | 它不会返回一个`IntegerField`对象。它会返回一个`int`,甚至能直接从数据库里拿。 1047 | 1048 | 这可能是由于`models.Model`为它定义了`__metaclass__`,使用一些魔法方法,让你可以定义一些可以做复杂的事情的简单声明关联数据库。 1049 | 1050 | Django让一些复杂的事情看起来很简单,通过暴露一个简单的接口,使用metaclass,重构了接口的代码让真正的行为在幕后执行。 1051 | 1052 | **结语** 1053 | 1054 | 首先你知道类是对象而且可以创建实例。 1055 | 1056 | 实际上,类本身也是实例,是metaclass的实例。 1057 | 1058 | >>> class Foo(object): pass 1059 | >>> id(Foo) 1060 | 142630324 1061 | 1062 | 所有的东西都是对象,在Python中,它们不是一个类的实例,就是metaclass的实例。 1063 | 1064 | 除了`type`。 1065 | 1066 | `type`是它自己的metaclass。这些东西在纯净的Python环境下是看不到的,他们在执行层做了一些交互来实现。 1067 | 1068 | 第二,metaclass是复杂的。你不需要在每一个简单的类里使用它。你可以用两种不同的方法来改变一个类: 1069 | 1070 | - [monkey patching](http://en.wikipedia.org/wiki/Monkey_patch) 1071 | 1072 | - 类的装饰器 1073 | 1074 | 99%的当你需要改变一个类的时刻,你需要用这些东西。 1075 | 1076 | 但是99%的时间里,你不根本不需要改变一个类。 1077 | 1078 | ### Python的"最小惊奇":多重默认参数 1079 | 1080 | 问题[链接](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) 1081 | 1082 | 实际上,这不是一个设计瑕疵,而且不它不是因为内部或者表现问题。 1083 | 1084 | 它单纯是来自Python中,函数是第一梯队的对象的事实,而且不仅仅是一段代码。 1085 | 1086 | 从这个角度,你会发现它很明智:一个函数是一个对象取决于它的定义;默认参数是一种类似丛书数据,而且它们的状态可能从一次到另一次的调用过程中发生改变-和在其他对象中一样。 1087 | 1088 | 不管怎样,Effbot在[Default Parameter Values in Python](http://effbot.org/zone/default-values.htm)中对这种表现有一个很好的解释。 1089 | 1090 | 我发现它很干净,我强烈推荐阅读以下,并且对函数对象是如何工作的掌握更多知识。 --------------------------------------------------------------------------------