do_you_really_know_python

本文是对 你真的会python嘛? 提问回答的一个尝试,同时也是总结学习一下

在什么时候需要使用OOP?

OOP 作为一种编程思想,个人感觉很难说清什么时候该用,什么时候不用。使用类作为一个其中的一个点来说, 有时候单单使用函数来完成会显得有点散,OOP 要求合适的封装和复用,抽象出一个模型来,而且还可以使用继承, ABC, 元类来减少代码冗余。

在什么时候使用类装饰器?

你用过元类嘛?

colors.py 中有用到元类,提供了一个简单的 property 生成。

在什么时候用静态方法什么时候使用类方法?

类方法的话,感觉就是和实例无关,而是属于类的方法,不需要实例化;

静态方法的话,和类,实例都没有关系(不需要self 或 cls), 但是逻辑上可能还是与这个类相关的;

你了解那些管理属性? __call__ , __init__ , __new__都是在什么时候被触发?__getattr__和__getattribute__应用有什么不同?

你知道标准库里面的多少个模块?你能在需要的时候知道这个功能其实标准库里面已经实现了?

什么时候用回调?

异步处理

什么时候用signal?假如你会django你知道django的signal是什么?你了解orm嘛?

signal 的话可以想到 flask 中的 signal,使用 blinker 实现的。sender, receiver,decople。

orm (object relational mapping) 使用类来映射数据库中的表。

asyncore,contextlib, functools, collections, heapq,itertools, SocketServer, weakref,operator(知道3个就算)这些你会几个?

functools — Higher-order functions and operations on callable objects

Transform an old-style comparison function to a key function.

python 3.x 中 comparison functions 已经不支持了(cmp=func),现在使用 (key=cmp_to_func(func)) 吧。

你定义一个或多个 rich comparison ordering 方法,其他的它会帮你生成, 一般是必须定义 __lt__(), __le__(), __gt__(), or __ge__() 中一个加上 __eq__()

和自带的 reduce 效果相同,为了便于更好的向前兼容。

collections — High-performance container datatypes

普通的 tuple 要通过 index 来得到 value,这容易出错,并且在代码中的可读性不好, 使用 namedtuple 你就可以通过 field_name 来获取 value 啦

namedtuple 是继承自 tuple,除了该有的方法,namedtuple 还有三个额外的方法和一个属性,它们是:

_make() _asdict() _replace() _fields

double-ended queue, supports thread-safe, memory efficient appends and pops from either side of the deque with approximately the same O(1) performance in either direction.

for counting hashable objects.

a dict that remembers the order that keys were first inserted. e.g. can be used in conjuction with sorting to make a sorted dictionary

正如其名,可以提供为未定义的键提供 default,类型由 default_factory 指定。其具体实现由 __missing__ 完成, 你也可以重写它来自定义自己的。当未指定 default_factory 时,也是会抛出 KeyError 错误的,而且只能当以 d["key"], d.__getitem__("key") 这样的形式调用时,才能够提供默认值。

__missing__(key) # Called by __getitem__ for missing key; pseudo-code:
    if self.default_factory is None: raise KeyError((key,))
    self[key] = value = self.default_factory()
    return value

operator - Standard operators as functions

python 标准操作符的函数形式,它们可以分为 object comparisons, logical operations, mathematical operations, sequence operations, and abstract type tests.

提一下几个不太熟悉可能有用的函数

itertools — Functions creating iterators for efficient looping

python的多态是什么?

在什么场景可以尝试python的设计模式中的XX(能想到2个场景就算)?

在什么时候可以使用Mixin?

mixin 在 wekzeug 中用的比较多,比如说 ImmutableList, ImmutableDict 等数据结构都是通过混入相应的 ImmutableListMixin, ImmutableDictMixin 来实现的

class ImmutableList(ImmutableListMixin, list):
    pass

class ImmutableDict(ImmutableDictMixin, dict):
    pass

还有比较经典的是 werkzeug.wrappers 中提供了很多 mixin,有 AcceptMixin,ETagRequestMixin, UserAgentMixin 等,你可以使用一个非常基本的请求类 BaseRequest,然后自己选择需要的功能,混入相应的 mixin 就行了。

参考

在什么时候可以使用python的闭包?

你曾经用过yield嘛?生成器和迭代器的区别和应用场景是什么?

An external iterator may be thought of as a type of pointer that has two primary operations: referencing one particular element in the object collection (called element access), and modifying itself so it points to the next element (called element traversal)

The primary purpose of an iterator is to allow a user to process every element of a container while isolating the user from the internal structure of the container

Most iterators are naturally expressible as generators, but because generators preserve their local state between invocations, they're particularly well-suited for complicated, stateful iterators, such as tree traversers.

迭代器可以让你遍历 container(list, tunple, file, string...) 中的元素

比如你有一个很长的列表,在你使用迭代器迭代的时候,不会像列表一样一次性获得所有值,在效率和空间上都是开销相对较大的, 使用迭代器,可以让你一个接一个来。

在什么可以使用python的函数式编程?

__future__模块里面都有什么定义的用法?

首先我们应该认识到的是,以下的几个在 python 3.x 中都是默认的行为,__future__ 模块的存在是为了解决以后的兼容性问题,即 2.x && 3.x compatible

nested_scopes(mandatory in 2.2)

generators(mandatory in 2.3)

with_statement(mandatory in 2.6)

division

python 2.x 中 3 / 2 = 1,是整除,python 3.x 中 3 / 2 = 1.5,在 python 2.x 中 from __future__ import division 使得能够获得与 3.x 中一致的结果。

# python 3.x
>>> 3 / 2
1.5
>>> 3 // 2
1

# python 2.x
>>> 3 / 2
1
>>> from __future__ import division
>>> 3 / 2
1.5
>>> 3 // 2
1

absolute_import

举个例子,你的 package 的结构是这样子的:

pkg/
    __init__.py
    main.py
    string.py

# main.py
import string
string.print_hello()

# string.py
def print_hello():
    print("Hello, world.")

当你在 main.py 中使用 import string 的时候,python 首先会在当前目录下尝试进行 relative import, 所以在 pkg.main 的 namespace 中 stirng 已经被绑定到 pkg.string 这个模块了,而不是 python 自带的 string 模块。

我们可以在 main.py 前面加上 from __future__ import absolute_import 来默认使用 absolute import. absolute import 是什么呢,就是只会在 sys.path 中来寻找要 import 的模块, sys.path 是什么呢,自己执行一下看看吧 :)

使用 relative import 存在问题是有时候会造成歧义,我们读代码的时候不能确定我们要 import 的是 sys.path 的呢, 还是当前 package 内的。对于写代码的呢,就是要当心自己定义的模块名字不要和标准库中重复,防止标准库的中被 shadow 掉, 就算你避开了当前版本内的标准库,你也不能保证以后的版本呢。

所以 absolute import 就来了。它消除了歧义性,使得代码更加清晰明确。

当然 relative import 也有存在的意义,比如说在对很大的 package 进行结构的组织变更时,我们不必对其子模块再做修改; 还有一个用处是,一个 package 内的一个模块如果不使用 relative import 的话,import 它自己可能会比较困难。

关于使用 relative import 时,. 一个表示当前目录,加一个表示其父目录,以此递增。

具体的 import 用法不再说明,只是注意 relative import 一定是 from <> mport <>, import <> 一定是 absolte,当然 from <> import <> 也可以是 absolute 啦。

    # python 2.x
    >>> print('hello', 'world')
    ('hello', 'world)
    >>> from __future__ import print_function
    >>> print('hello', 'world')
    hello world

unicode_literals

参考