Pypi镜像

解决国内访问pypi速度慢的问题,注意要加上--trusted-host pypi.mirrors.ustc.edu.cn 因为有些不提供安全连接,或者证书不可信

  1. http://pypi.douban.com/simple 豆瓣
  2. http://pypi.hustunique.com/simple 华中理工大学
  3. http://pypi.sdutlinux.org/simple 山东理工大学
  4. http://pypi.mirrors.ustc.edu.cn/simple 中国科学技术大学
  1. pip3.4 install -i http://pypi.mirrors.ustc.edu.cn/simple --trusted-host pypi.mirrors.ustc.edu.cn flask-restful

模块

from import

  • 如果module1中有变量X,module2用from来导入module1,则在赋值X的时候并不会改动module1中的X,而用import可以。

  • from会导致reload失效,因为from导入的模块拿的只是一个被reload的引用,必须在reload之后再执行一次from import

  • 子类并不会自动调用父类的构造函数,需要显示的调用。

  • 类的赋值操作并不会查询搜索树。

  • init 函数不支持重载,因为python支持可变参数

  • 两个下划线开头的是伪私有类属性, 他会变成_ClassName__X

内建属性

  1. __class__ # 返回类名
  2. __base__ # 父类
  3. __dict__ # 属性字典,dir()
  4. __slot__ # 禁止生成dict树
  5. __getattr__ # X.undefined
  6. __getattribute__ # X.any
  7. __contain__ # item in X
  8. __call__ # 可以直接这样使用 class_object_name()

委托

  1. class Super:
  2. def delegate(self):
  3. self.action() #action需要被实现
  4. class Provider(Super):
  5. def action(self):
  6. print('in provider.action')

函数

闭包

  1. def func():
  2. _x = "attr"
  3. def printf():
  4. print(_x)
  5. return printf

Decorator

Singleton

  1. def singleton(cls, *args, **kw):
  2. _instance = {}
  3. def wrapper():
  4. if cls not in _instance:
  5. _instance[cls] = cls(*args, **kw)
  6. return _instance[cls]
  7. return wrapper
  8. @singleton
  9. class MyClass(gentoo.LXRPClientHandler):
  • 缺点是MyClass实际上是一个函数(wrapper),所以不能直接通过MyClass取类中属性

  • m = MyClass(); n = MyClass(); o = type(n)(); then m == n && m != o && n != o

  • @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。

  • @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。

规范

命名规则

Type Public Internal
Modules lower_with_under _lower_with_under
Packages lower_with_under
Classes CapWords _CapWords
Exceptions CapWords
Functions lower_with_under() _lower_with_under()
Global/Class Constants CAPS_WITH_UNDER _CAPS_WITH_UNDER
Global/Class Variables lower_with_under _lower_with_under
Instance Variables lower_with_under _lower_with_under (protected) or __lower_with_under (private)
Method Names lower_with_under() _lower_with_under() (protected) or __lower_with_under() (private)
Function/Method Parameters lower_with_under
Local Variables lower_with_under
  1. single_trailing_underscore_ : used by convention to avoid conflicts with Python keyword, e.g.
  1. Tkinter.Toplevel(master, class_='ClassName')
  1. __double_leading_underscore : when naming a class attribute, invokes name mangling (inside class FooBar, __boo becomes _FooBar_boo).

  2. __double_leading_and_trailing_underscore__ : “magic” objects or attributes that live in user-controlled namespaces. E.g. init , import or file . Never invent such names; only use them as documented.

  3. _single_leading_underscore : weak “internal use” indicator. E.g. from M import * does not import objects whose name starts with an underscore.

编程规范

  • 每行80字符,注释72字符

  • 参数多的时候要换行,少数情况下要用\

  • 使用 if not alist 检查是否为空,而不是用if len(alist) == 0

import顺序

不要一行import多个包

Imports should be grouped in the following order:

  1. standard library imports

  2. related third party imports

  3. local application/library specific imports

  4. Wildcard imports ( from import * ) should be avoided

类设计

如果在不确定函数或者属性是public还是non-public,尽量还是先声明为non-public,从non到public很容易,反过来则很难

Programming Recommendations

  1. Yes:
  2. def f(x): return 2*x
  3. No:
  4. f = lambda x: 2*x

The first form means that the name of the resulting function object is specifically ‘f’ instead of the generic ‘’. This is more useful for tracebacks and string representations in general. The use of the assignment statement eliminates the sole benefit a lambda expression can offer over an explicit def statement (i.e. that it can be embedded inside a larger expression)

  • Use exception chaining appropriately. In Python 3, “raise X from Y” should be used to indicate explicit replacement without losing the original traceback.

  • Derive exceptions from Exception rather than BaseException . Direct inheritance from BaseException is reserved for exceptions where catching them is almost always the wrong thing to do.

  • Additionally, for all try/except clauses, limit the try clause to the absolute minimum amount of code necessary. Again, this avoids masking bugs.

  1. Yes:
  2. try:
  3. value = collection[key]
  4. except KeyError:
  5. return key_not_found(key)
  6. else:
  7. return handle_value(value)
  8. No:
  9. try:
  10. # Too broad!
  11. return handle_value(collection[key])
  12. except KeyError:
  13. # Will also catch KeyError raised by handle_value()
  14. return key_not_found(key)
  • Object type comparisons should always use isinstance() instead of comparing types directly.
  1. Yes: if isinstance(obj, int):
  2. No: if type(obj) is type(1):
  • For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
  1. Yes: if not seq:
  2. if seq:
  3. No: if len(seq)
  4. if not len(seq)
  • Don’t compare boolean values to True or False using == .
  1. Yes: if greeting:
  2. No: if greeting == True:
  3. Worse: if greeting is True:

Class 继承

当一个类被设计为基类的时候,要考虑到那些方法是要被子类覆盖的,那些是给子类用的(subclass API),那些只是基类用的

  • 公共属性,前面不应该有一个下划线

  • 如果你的属性名与keyword或者其他什么的冲突,则可以考虑在尾部加一个下划线

  • 对于简单的公共属性,直接用属性名访问,而不要像jave一样定义一些accessor/mutator methods,如果之后需要对于这个属性进行额外处理, 那么可以使用@property来强化这个属性(防止用property来计算复杂属性)

  • 如果你的类可能被继承,则把那些不想被子类使用的属性和方法用两个下划线开头

super() 还是 BaseClass()

  1. class Base:
  2. name = "Base"
  3. def __init__(self):pass
  4. class Sub(Base):
  5. def __init__(self):
  6. #Base.__init__(self)
  7. super().__init__()

这两种方法都可以用作调用父类初始化函数,但是super()更好,不会在菱形继承中导致一些重复初始化的问题

为了弄清它的原理,我们需要花点时间解释下Python是如何实现继承的。对于你定义的每一个类而已,Python会计算出一个所谓的方法解析顺序(MRO)列表。 这个MRO列表就是一个简单的所有基类的线性顺序表。例如:

  1. C.__mro__
  2. (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
  3. <class '__main__.Base'>, <class 'object'>)

为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个MRO列表的构造是通过一个C3线性化算法来实现的。 我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

  • 子类会先于父类被检查

  • 多个父类会根据它们在列表中的顺序被检查

  • 如果对下一个类存在两个合法的选择,选择第一个父类

当你使用 super() 函数时,Python会在MRO列表上继续搜索下一个类。 只要每个重定义的方法统一使用 super() 并只调用它一次, 那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次。

我们来看下super的实现,可以发现他在找这个列表里后一个class

  1. def super(cls, inst):
  2. mro = inst.__class__mro()
  3. return mro[mro.index(cls)+1]
  1. class Base:
  2. name = "Base"
  3. def __init__(self):pass
  4. a = Base()
  5. print(a.name)
  6. a.name = "Base c"
  7. print(a.name)
  8. print(Base.name)
  9. print('--------')
  10. class Sub(Base):
  11. def __init__(self):
  12. Base.__init__(self)
  13. @property
  14. def name(self):
  15. print('property name')
  16. print(Base.name)
  17. Base.name = 'abc'
  18. print(super(Sub,self).name)
  19. b = Sub()
  20. b.name
  21. print(b.__dict__)
  22. print(Base.name)
  23. print('--------')
  24. class Sub2(Sub):
  25. def __init__(self):
  26. Base.__init__(self)
  27. print(super(Sub, self).name)
  28. c = Sub2()
  29. c.name
  30. print(c.__class__.mro())

结果是:

  1. Base
  2. Base c
  3. Base
  4. --------
  5. property name
  6. Base
  7. abc
  8. {}
  9. abc
  10. --------
  11. abc
  12. property name
  13. abc
  14. abc
  15. [<class '__main__.Sub2'>, <class '__main__.Sub'>, <class '__main__.Base'>, <class 'object'>]

weakref

List和Dict不支持weakref,但是他们的子类可以

Unicode

为了解决多国语言的问题,ASCII显然已经不适合,他是用一个字节代表一个字符,这远远不够世界各种语言使用,Unicode是一个更大的集合,他包含了ASCII,因此他是一个变长的编码方式
我们有两种方式来声明一个str

  1. str = abcd # 这是一个str
  2. uni = uHi \u2119\u2602 # 这是一个unicode类型
  • unicode.encode(‘UTF-8’) -> bytes

  • bytes.decode(‘UTF-8’) -> unicode

  1. u'abcd'.encode('ascii', 'replace') #不能被encode就会变成一个`?`
  2. u'abcd'.encode('ascii', 'xmlcharrefreplace') #produces an HTML/XML character entity reference
  3. u'abcd'.encode('ascii', 'ignore') #ignore
  • Python 2 will automatically decode the byte string to produce a second unicode string, then will complete the operation with the two unicode strings.

  • So “str” in Python 2 is now called “bytes,” and “unicode” in Python 2 is now called “str”. This makes more sense than the Python 2 names, since Unicode is how you want all text stored, and byte strings are only for when you are dealing with bytes.
    [Pragmatic Unicode][http://nedbatchelder.com/text/unipain.html]

元类

type是所有类的元类(metaclass)

TIP

in

if elem in alist 用来检查元素是否在列表里,但是注意这里的elem必须是一个元素,不能是alist列表中的一个子集,他是不能够检查子集的。

yeild

generator可以包含一个return语句,但是他会导致generator不再能返回任何结果,而且return不能有返回值,return 5会报一个syntax error

_ 占位符

可以像Haskell一样有个占位符_ 来表示不关心的内容

Flask

获得message body

  1. request.form
  2. request.json
  3. request.headers

Functional programming

generator expression and list comprehensions

  1. # Generator expression -- returns iterator
  2. stripped_iter = (line.strip() for line in line_list)
  3. # List comprehension -- returns list
  4. stripped_list = [line.strip() for line in line_list]

List comprehension 会一次性返回所有的值,而generator expression返回一个可迭代的对象,他不会一次性返回所有值,只会根据需要获取,适合处理无限长度的数据。

Passing values into a generator

In Python 2.4 and earlier, generators only produced output. Once a generator’s code was invoked to create an iterator, there was no way to pass any new information into the function when its execution is resumed. You could hack together this ability by making the generator look at a global variable or by passing in some mutable object that callers then modify, but these approaches are messy.
In Python 2.5 there’s a simple way to pass values into a generator. yield became an expression, returning a value that can be assigned to a variable or otherwise operated on:

  1. val = (yield i)

I recommend that you always put parentheses around a yield expression when you’re doing something with the returned value, as in the above example. The parentheses aren’t always necessary, but it’s easier to always add them instead of having to remember when they’re needed.

(PEP 342 explains the exact rules, which are that a yield-expression must always be parenthesized except when it occurs at the top-level expression on the right-hand side of an assignment. This means you can write val = yield i but have to use parentheses when there’s an operation, as in val = (yield i) + 12.)

Values are sent into a generator by calling its send(value) method. This method resumes the generator’s code and the yield expression returns the specified value. If the regular next() method is called, the yield returns None.

Here’s a simple counter that increments by 1 and allows changing the value of the internal counter.

  1. def counter (maximum):
  2. i = 0
  3. while i < maximum:
  4. val = (yield i)
  5. # If value provided, change counter
  6. if val is not None:
  7. i = val
  8. else:
  9. i += 1

And here’s an example of changing the counter:

  1. >>>
  2. >>> it = counter(10)
  3. >>> print it.next()
  4. 0
  5. >>> print it.next()
  6. 1
  7. >>> print it.send(8)
  8. 8
  9. >>> print it.next()
  10. 9
  11. >>> print it.next()
  12. Traceback (most recent call last):
  13. File "t.py", line 15, in ?
  14. print it.next()
  15. StopIteration

Because yield will often be returning None, you should always check for this case. Don’t just use its value in expressions unless you’re sure that the send() method will be the only method used to resume your generator function.

In addition to send(), there are two other new methods on generators:

  • throw(type, value=None, traceback=None) is used to raise an exception inside the generator; the exception is raised by the yield expression where the generator’s execution is paused.

  • close() raises a GeneratorExit exception inside the generator to terminate the iteration. On receiving this exception, the generator’s code must either raise GeneratorExit or StopIteration; catching the exception and doing anything else is illegal and will trigger a RuntimeError. close() will also be called by Python’s garbage collector when the generator is garbage-collected.

If you need to run cleanup code when a GeneratorExit occurs, I suggest using a try: … finally: suite instead of catching GeneratorExit.

The cumulative effect of these changes is to turn generators from one-way producers of information into both producers and consumers.

Generators also become coroutines, a more generalized form of subroutines. Subroutines are entered at one point and exited at another point (the top of the function, and a return statement), but coroutines can be entered, exited, and resumed at many different points (the yield statements).

getattr

  • getattr(object, name[, default])
    Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.

class type(object)

  • class type(object)

  • class type(name, bases, dict)
    With one argument, return the type of an object. The return value is a type object and generally the same object as returned by object.class.

The isinstance() built-in function is recommended for testing the type of an object, because it takes subclasses into account.

With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the name attribute; the bases tuple itemizes the base classes and becomes the bases attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the dict attribute. For example, the following two statements create identical type objects:

  1. >>>
  2. >>> class X:
  3. ... a = 1
  4. ...
  5. >>> X = type('X', (object,), dict(a=1))

monkey patch

monkey patch指的是在运行时动态替换,一般是在startup的时候.

用过gevent就会知道,会在最开头的地方gevent.monkey.patch_all();把标准库中的thread/socket等给替换掉.这样我们在后面使用socket的时候可以跟平常一样使用,无需修改任何代码,但是它变成非阻塞的了. 之前做的一个游戏服务器,很多地方用的import json,后来发现ujson比自带json快了N倍,于是问题来了,难道几十个文件要一个个把import json改成import ujson as json吗? 其实只需要在进程startup的地方monkey patch就行了.是影响整个进程空间的.

同一进程空间中一个module只会被运行一次.

  1. import json
  2. import ujson
  3. def monkey_patch_json():
  4. json.__name__ = 'ujson'
  5. json.dumps = ujson.dumps
  6. json.loads = ujson.loads
  7. monkey_patch_json()
  8. print 'main.py',json.__name__
  9. import sub

sub.py

  1. import json
  2. print 'sub.py',json.__name__

with

如下情况 with一旦结束,那么as后面的对象就会被清除,即便是赋值给了c.response,那只是一个引用,除非用deepcopy

  1. with urllib.request.urlopen(c.request, context=context) as response:
  2. c.response = response
  3. return c
  4. #print(c.response.read())
  5. #return c

pdb

可以通过代用set_trace()来设置一个断点,然后运行的时候就会自动进入pdb,然后就可以调试啦

  1. import inspect
  2. import pdb
  3. class a:pass
  4. class b(a):
  5. class c(a):
  6. def hell(self):
  7. print(inspect.getmodule(self))
  8. def guess(self):
  9. self.hell()
  10. def __call__(self):
  11. cc = self.c()
  12. pdb.set_trace()
  13. cc.guess()
  14. cc()

函数式编程

map

从python3开始map变得lazy,如果你不主动调用next或者使用它 它是不会马上返回结果的,跟Haskell一样

  1. class Test
  2. def __init__(self, string)
  3. print(string)
  4. x = map(Test, ['ggg','rrr']) //return only a map object
  5. x.next()
  6. list(x)// will get a result.

TIP

OrderedDict.move_to_end(key, last=False)

这种方式并不能用于排序,在把某个元素放到最后的同时也会改变其他元素的顺序

  1. x=OrderedDict({'a':1,'b':2,'c':3})
  2. x.move_to_end('a')
  3. print(x)
  4. >>OrderedDict([('c', 3), ('b', 2), ('a', 1)])

raise new_exc from original_exc

When raising a new exception (rather than using a bare raise to re-raise the exception currently being handled), the implicit exception context can be supplemented with an explicit cause by using from with raise:

and & or

  1. x = 1
  2. y = 2
  3. x and y # 返回的不是bool, 而是2

工具

  • python -m http.server 启动一个httpserver提供当前文件夹访问

Reference

  1. PEP 0008 — Style Guide for Python Code