Python 基础小抄

Python 命名规范

# 见: PEP 8

# 类 (class)
#
# 推荐:
#   MyClass
# 不推荐:
#   myClass, my_class
MyClass

# 方法 (func), 模块 (module), 包 (package), 变量 (variables)
#
# 推荐:
#   var_underscore_separate
# 不推荐:
#   varCamel, VarCamel
var_underscore_separate

# 公有变量
var

# 内部变量
_var

# 避免和关键字冲突
var_

# 类的私有变量
__var

# 类的保护变量
_var_

# "magic" 方法或属性
# 例: __init__, __file__, __main__
__var__

# 内部一次性变量
# 通常在循环中使用
# 例: [_ for _ in range(10)]
# 根本不用的变量(占位符)
# for _, a in [(1,2),(3,4)]: print a
_

使用 __future__ 向后移植(backport) 特性

# PEP 236 - Back to the __future__

# 在 python2 中使用 python3 的 print 方法

>>> print "Hello World"  # print 是一个语句(statement)
Hello World
>>> from __future__ import print_function
>>> print "Hello World"
  File "<stdin>", line 1
    print "Hello World"
                      ^
SyntaxError: invalid syntax
>>> print("Hello World") # print 是方法
Hello World

# python2 中使用 python3 的 unicode_literals

>>> type("Guido") # python 3 中string 类型是 str
<type 'str'>
>>> from __future__ import unicode_literals
>>> type("Guido") # string 类型变成 unicode
<type 'unicode'>

# backport PEP 238 -- 除法操作修改

>>> 1/2
0
>>> from __future__ import division
>>> 1/2   # 返回浮点数 (正常人理解的除法)
0.5
>>> 1//2  # 返回一个整型 (floor 除法)
0

Note

from __future__ import feature 是一个 future 语句。 和一般的 import 不同,它用于在当前版本的 python 版本中引入之后版本的新特性

查看对象属性

# 查看列表属性
>>> dir(list)
['__add__', '__class__', ...]

定义 __doc__ 方法

# 定义函数说明
>>> def Example():
...   """ This is an example function """
...   print "Example function"
...
>>> Example.__doc__
' This is an example function '

# 使用 help 方法
>>> help(Example)

检查实例类型

>>> ex = 10
>>> isinstance(ex,int)
True

检查、获取、赋值属性

>>> class Example(object):
...   def __init__(self):
...     self.name = "ex"
...   def printex(self):
...     print "This is an example"
...

# 检查对象是否有某种属性
# hasattr(obj, 'attr')
>>> ex = Example()
>>> hasattr(ex,"name")
True
>>> hasattr(ex,"printex")
True
>>> hasattr(ex,"print")
False

# 获取对象属性
# getattr(obj, 'attr')
>>> getattr(ex,'name')
'ex'

# 给对象某种属性赋值
# setattr(obj, 'attr', value)
>>> setattr(ex,'name','example')
>>> ex.name
'example'

继承检查

>>> class Example(object):
...   def __init__(self):
...     self.name = "ex"
...   def printex(self):
...     print "This is an Example"
...
>>> issubclass(Example, object)
True

查询所有 global 变量

# globals() 返回一个字典
# {'variable name': variable value}
>>> globals()
{'args': (1, 2, 3, 4, 5), ...}

检查 callable

>>> a = 10
>>> def fun():
...   print "I am callable"
...
>>> callable(a)
False
>>> callable(fun)
True

获取方法名、类名

>>> class ExampleClass(object):
...   pass
...
>>> def example_function():
...   pass
...
>>> ex = ExampleClass()
>>> ex.__class__.__name__
'ExampleClass'
>>> example_function.__name__
'example_function'

__new__ & __init__

# __init__ 会被调用
>>> class ClassA(object):
...     def __new__(cls, arg):
...         print '__new__ ' + arg
...         return object.__new__(cls, arg)
...     def __init__(self, arg):
...         print '__init__ ' + arg
...
>>> o = ClassA("Hello")
__new__ Hello
__init__ Hello

# __init__ 不会被调用
>>> class ClassB(object):
...     def __new__(cls, arg):
...         print '__new__ ' + arg
...         return object
...     def __init__(self, arg):
...         print '__init__ ' + arg
...
>>> o = ClassB("Hello")
__new__ Hello

菱形继承问题

# 多继承 MRO(Method Resolution Order):方法解析顺序
# 采用 C3 算法

>>> def foo_a(self):
...     print("This is ClsA")
...
>>> def foo_b(self):
...     print("This is ClsB")
...
>>> def foo_c(self):
...     print("This is ClsC")
...
>>> class Type(type):
...     def __repr__(cls):
...         return cls.__name__
...
>>> ClsA = Type("ClsA", (object,), {'foo': foo_a})
>>> ClsB = Type("ClsB", (ClsA,), {'foo': foo_b})
>>> ClsC = Type("ClsC", (ClsA,), {'foo': foo_c})
>>> ClsD = Type("ClsD", (ClsB, ClsC), {})
>>> ClsD.mro()
[ClsD, ClsB, ClsC, ClsA, <type 'object'>]
>>> ClsD().foo()
This is ClsB

类呈现方法

>>> class Example(object):
...    def __str__(self):
...       return "Example __str__"
...    def __repr__(self):
...       return "Example __repr__"
...
>>> print str(Example())
Example __str__
>>> Example()
Example __repr__

长字符串分割

# 长字符串
>>> s = 'This is a very very very long python string'
>>> s
'This is a very very very long python string'

# 使用反斜杠
>>> s = "This is a very very very " \
...     "long python string"
>>> s
'This is a very very very long python string'

# 使用括号
>>> s = ("This is a very very very "
...      "long python string")
>>> s
'This is a very very very long python string'

# 使用 '+'
>>> s = ("This is a very very very " +
...      "long python string")
>>> s
'This is a very very very long python string'

# 使用三引号加反斜杠
>>> s = '''This is a very very very \
... long python string'''
>>> s
'This is a very very very long python string'

优雅地 获取列表元素

>>> a = [1, 2, 3, 4, 5]
>>> a[0]
1
>>> a[-1]
5
>>> a[0:]
[1, 2, 3, 4, 5]
>>> a[:-1]
[1, 2, 3, 4]

# a[start:end:step]
>>> a[0:-1:2]
[1, 3]

# 使用 slice 对象
# slice(start,end,step)
>>> s = slice(0, -1, 2)
>>> a[s]
[1, 3]

# 获取循环中索引和对象
>>> a = range(3)
>>> for idx, item in enumerate(a):
...   print (idx,item),
...
(0, 0) (1, 1) (2, 2)

# 将两个队列转换成元组队列
>>> a = [1, 2, 3, 4, 5]
>>> b = [2, 4, 5, 6, 8]
>>> zip(a, b)
[(1, 2), (2, 4), (3, 5), (4, 6), (5, 8)]

# 过滤器
>>> [x for x in range(5) if x > 1]
[2, 3, 4]
>>> l = ['1', '2', 3, 'Hello', 4]
>>> predicate = lambda x: isinstance(x, int)
>>> filter(predicate, l)
[3, 4]

# 列表去重
>>> a = [1, 2, 3, 3, 3]
>>> list({_ for _ in a})
[1, 2, 3]
# 或者
>>> list(set(a))
[1, 2, 3]

# 列表翻转
>>> a = [1, 2, 3, 4, 5]
>>> a[::-1]
[5, 4, 3, 2, 1]

优雅地 获取字典元素

# 获取字典所有的键值
>>> a = {"1":1, "2":2, "3":3}
>>> b = {"2":2, "3":3, "4":4}
>>> a.keys()
['1', '3', '2']

# 元组方式获取字典键值对
>>> a.items()
[('1', 1), ('3', 3), ('2', 2)]

# 获取两个字典相同的键
>>> [_ for _ in a.keys() if _ in b.keys()]
['3', '2']
# 更优雅的方式
>>> c = set(a).intersection(set(b))
>>> list(c)
['3', '2']
# 或者
>>> [_ for _ in a if _ in b]
['3', '2']

# 更新字典
>>> a.update(b)
>>> a
{'1': 1, '3': 3, '2': 2, '4': 4}

优雅地 给列表、字典赋值

# 初始化列表
>>> ex = [0] * 10
>>> ex
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

# 合并列表
>>> a = [1, 2, 3]; b = ['a', 'b']
>>> a + b
[1, 2, 3, 'a', 'b']

# 列表推导式
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> fn = lambda x: x**2
>>> [fn(x) for x in range(5)]
[0, 1, 4, 9, 16]
>>> {'{0}'.format(x): x for x in range(3)}
{'1': 1, '0': 0, '2': 2}

# 使用内建函数“map”
>>> map(fn, range(5))
[0, 1, 4, 9, 16]

命名元组(NamedTuple)

# namedtuple(typename, field_names)
# 定义没有方法的类
>>> from collections import namedtuple
>>> Example = namedtuple("Example",'a b c')
>>> e = Example(1, 2, 3)
>>> print e.a, e[1], e[1] + e.b
1 2 4

__iter__ - 代理迭代器

# __iter__ 返回一个迭代器对象
# 注意: 列表是一个 “可迭代” 对象,不是一个迭代器
>>> class Example(object):
...    def __init__(self,list_):
...       self._list = list_
...    def __iter__(self):
...      return iter(self._list)
...
>>> ex = Example([1, 2, 3, 4, 5])
>>> for _ in ex: print _,
...
1 2 3 4 5

像迭代器一样使用生成器

# 见: PEP289
>>> a = (_ for _ in range(10))
>>> for _ in a: print _,
...
0 1 2 3 4 5 6 7 8 9

# 等价于
>>> def generator():
...   for _ in range(10):
...     yield _
...
>>> for _ in generator(): print _,
...
0 1 2 3 4 5 6 7 8 9

仿写列表

>>> class EmuList(object):
...   def __init__(self, list_):
...     self._list = list_
...   def __repr__(self):
...     return "EmuList: " + repr(self._list)
...   def append(self, item):
...     self._list.append(item)
...   def remove(self, item):
...     self._list.remove(item)
...   def __len__(self):
...     return len(self._list)
...   def __getitem__(self, sliced):
...     return self._list[sliced]
...   def __setitem__(self, sliced, val):
...     self._list[sliced] = val
...   def __delitem__(self, sliced):
...     del self._list[sliced]
...   def __contains__(self, item):
...     return item in self._list
...   def __iter__(self):
...     return iter(self._list)
...
>>> emul = EmuList(range(5))
>>> emul
EmuList: [0, 1, 2, 3, 4]
>>> emul[1:3]  #  __getitem__
[1, 2]
>>> emul[0:4:2]  #  __getitem__
[0, 2]
>>> len(emul)  #  __len__
5
>>> emul.append(5)
>>> emul
EmuList: [0, 1, 2, 3, 4, 5]
>>> emul.remove(2)
>>> emul
EmuList: [0, 1, 3, 4, 5]
>>> emul[3] = 6  # __setitem__
>>> emul
EmuList: [0, 1, 3, 6, 5]
>>> 0 in emul  # __contains__
True

仿写字典

>>> class EmuDict(object):
...   def __init__(self, dict_):
...     self._dict = dict_
...   def __repr__(self):
...     return "EmuDict: " + repr(self._dict)
...   def __getitem__(self, key):
...     return self._dict[key]
...   def __setitem__(self, key, val):
...     self._dict[key] = val
...   def __delitem__(self, key):
...     del self._dict[key]
...   def __contains__(self, key):
...     return key in self._dict
...   def __iter__(self):
...     return iter(self._dict.keys())
...
>>> _ = {"1":1, "2":2, "3":3}
>>> emud = EmuDict(_)
>>> emud  # __repr__
EmuDict: {'1': 1, '2': 2, '3': 3}
>>> emud['1']  # __getitem__
1
>>> emud['5'] = 5  # __setitem__
>>> emud
EmuDict: {'1': 1, '2': 2, '3': 3, '5': 5}
>>> del emud['2']  # __delitem__
>>> emud
EmuDict: {'1': 1, '3': 3, '5': 5}
>>> for _ in emud: print emud[_],  # __iter__
...
1 3 5
>>> '1' in emud  # __contains__
True

仿写矩阵乘法

# PEP 465 - 使用 "@" 表示矩阵乘法
#
# Python-3.5 以上版本

>>> class Arr:
...     def __init__(self, *arg):
...         self._arr = arg
...     def __matmul__(self, other):
...         if not isinstance(other, Arr):
...             raise TypeError
...         if len(self) != len(other):
...             raise ValueError
...         return sum([x*y for x, y in zip(self._arr, other._arr)])
...     def __imatmul__(self, other):
...         if not isinstance(other, Arr):
...             raise TypeError
...         if len(self) != len(other):
...             raise ValueError
...         res = sum([x*y for x, y in zip(self._arr, other._arr)])
...         self._arr = [res]
...         return self
...     def __len__(self):
...         return len(self._arr)
...     def __str__(self):
...         return self.__repr__()
...     def __repr__(self):
...         return "Arr({})".format(repr(self._arr))
...
>>> a = Arr(9, 5, 2, 7)
>>> b = Arr(5, 5, 6, 6)
>>> a @ b  # __matmul__
124
>>> a @= b  # __imatmul__
>>> a
Arr([124])

装饰器

# 见: PEP318
>>> from functools import wraps
>>> def decorator(func):
...   @wraps(func)
...   def wrapper(*args, **kwargs):
...     print "Before calling {}.".format(func.__name___)
...     ret = func(*args, **kwargs)
...     print "After calling {}.".format(func.__name___)
...     return ret
...   return wrapper
...
>>> @decorator
... def example():
...   print "Inside example function."
...
>>> example()
Before calling example.
Inside example function.
After calling example.

# 等价于
... def example():
...   print "Inside example function."
...
>>> example = decorator(example)
>>> example()
Before calling example.
Inside example function.
After calling example.

Note

@wraps 保留了原函数的属性, 否则被修饰函数的属性会被 装饰函数 替换

# 不使用 @wraps
>>> def decorator(func):
...     def wrapper(*args, **kwargs):
...         print('wrap function')
...         return func(*args, **kwargs)
...     return wrapper
...
>>> @decorator
... def example(*a, **kw):
...     pass
...
>>> example.__name__  # 函数属性改变
'wrapper'

# 使用 @wraps
>>> from functools import wraps
>>> def decorator(func):
...     @wraps(func)
...     def wrapper(*args, **kwargs):
...         print('wrap function')
...         return func(*args, **kwargs)
...     return wrapper
...
>>> @decorator
... def example(*a, **kw):
...     pass
...
>>> example.__name__  # 函数属性保留
'example'

带参数的装饰器

>>> from functools import wraps
>>> def decorator_with_argument(val):
...   def decorator(func):
...     @wraps(func)
...     def wrapper(*args, **kwargs):
...       print "Val is {0}".format(val)
...       return func(*args, **kwargs)
...     return wrapper
...   return decorator
...
>>> @decorator_with_argument(10)
... def example():
...   print "This is example function."
...
>>> example()
Val is 10
This is example function.

# 等价于
>>> def example():
...   print "This is example function."
...
>>> example = decorator_with_argument(10)(example)
>>> example()
Val is 10
This is example function.

for-else 语句

# 见文章: More Control Flow Tools
# for 循环的 else 在没有 break 产生的情况下执行
>>> for _ in range(5):
...   print _,
... else:
...   print "\nno break occurred"
...
0 1 2 3 4
no break occurred
>>> for _ in range(5):
...   if _ % 2 == 0:
...     print "break occurred"
...     break
... else:
...   print "no break occurred"
...
break occurred

# 等价于
flag = False
for _ in range(5):
    if _ % 2 == 0:
        flag = True
        print "break occurred"
        break
if flag == False:
    print "no break occurred"

try-else 语句

# 没有异常是执行 else 中的语句
>>> try:
...   print "No exception"
... except:
...   pass
... else:
...   print "No exception occurred"
...
No exception
No exception occurred

Lambda 表达式

>>> fn = lambda x: x**2
>>> fn(3)
9
>>> (lambda x: x**2)(3)
9
>>> (lambda x: [x*_ for _ in range(5)])(2)
[0, 2, 4, 6, 8]
>>> (lambda x: x if x>3 else 3)(5)
5

# 多行 lambda 表达式
>>> (lambda x:
... True
... if x>0
... else
... False)(3)
True

不定参数 - (*args, **kwargs)

>>> def example(a, b=None, *args, **kwargs):
...   print a, b
...   print args
...   print kwargs
...
>>> example(1, "var", 2, 3, word="hello")
1 var
(2, 3)
{'word': 'hello'}
>>> a_tuple = (1, 2, 3, 4, 5)
>>> a_dict = {"1":1, "2":2, "3":3}
>>> example(1, "var", *a_tuple, **a_dict)
1 var
(1, 2, 3, 4, 5)
{'1': 1, '2': 2, '3': 3}

type() 声明(创建) class

>>> def fib(self, n):
...     if n <= 2:
...         return 1
...     return fib(self, n-1) + fib(self, n-2)
...
>>> Fib = type('Fib', (object,), {'val': 10,
...                               'fib': fib})
>>> f = Fib()
>>> f.val
10
>>> f.fib(f.val)
55

# 等价于
>>> class Fib(object):
...     val = 10
...     def fib(self, n):
...         if n <=2:
...             return 1
...         return self.fib(n-1)+self.fib(n-2)
...
>>> f = Fib()
>>> f.val
10
>>> f.fib(f.val)
55

Callable 对象

>>> class CallableObject(object):
...   def example(self, *args, **kwargs):
...     print "I am callable!"
...   def __call__(self, *args, **kwargs):
...     self.example(*args, **kwargs)
...
>>> ex = CallableObject()
>>> ex()
I am callable!

上下文管理 - with 语句

# 代替 try: ... finally: ...
# 见: PEP343
# 常用于 open 和 close 操作

import socket

class Socket(object):
    def __init__(self,host,port):
        self.host = host
        self.port = port

    def __enter__(self):
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind((self.host,self.port))
        sock.listen(5)
        self.sock = sock
        return self.sock

    def __exit__(self, *exc_info):
        if exc_info[0] is not None:
            import traceback
            traceback.print_exception(*exc_info)
        self.sock.close()

if __name__=="__main__":
    host = 'localhost'
    port = 5566
    with Socket(host, port) as s:
        while True:
            conn, addr = s.accept()
            msg = conn.recv(1024)
            print msg
            conn.send(msg)
            conn.close()

使用 @contextmanager

from contextlib import contextmanager

@contextmanager
def opening(filename, mode='r'):
   f = open(filename, mode)
   try:
      yield f
   finally:
      f.close()

with opening('example.txt') as fd:
   fd.read()

with 语句打开文件

>>> with open("/etc/passwd",'r') as f:
...    content = f.read()

Property - 管理属性

>>> class Example(object):
...     def __init__(self, value):
...        self._val = value
...     @property
...     def val(self):
...         return self._val
...     @val.setter
...     def val(self, value):
...         if not isintance(value, int):
...             raise TypeError("Expected int")
...         self._val = value
...     @val.deleter
...     def val(self):
...         del self._val
...
>>> ex = Example(123)
>>> ex.val = "str"
Traceback (most recent call last):
  File "", line 1, in
  File "test.py", line 12, in val
    raise TypeError("Expected int")
TypeError: Expected int

# 等价于
>>> class Example(object):
...     def __init__(self, value):
...        self._val = value
...
...     def _val_getter(self):
...         return self._val
...
...     def _val_setter(self, value):
...         if not isintance(value, int):
...             raise TypeError("Expected int")
...         self._val = value
...
...     def _val_deleter(self):
...         del self._val
...
...     val = property(fget=_val_getter, fset=_val_setter, fdel=_val_deleter, doc=None)
...

计算属性(延迟加载) - 使用 property

>>> class Example(object):
...   @property
...   def square3(self):
...     return 2**3
...
>>> ex = Example()
>>> ex.square3
8

Note

@property 在我们需要的时候才会计算属性的值, 并不是事先就在内存中存储

描述器 - 管理属性

>>> class Integer(object):
...   def __init__(self, name):
...     self._name = name
...   def __get__(self, inst, cls):
...     if inst is None:
...       return self
...     else:
...       return inst.__dict__[self._name]
...   def __set__(self, inst, value):
...     if not isinstance(value, int):
...       raise TypeError("Expected int")
...     inst.__dict__[self._name] = value
...   def __delete__(self,inst):
...     del inst.__dict__[self._name]
...
>>> class Example(object):
...   x = Integer('x')
...   def __init__(self, val):
...     self.x = val
...
>>> ex1 = Example(1)
>>> ex1.x
1
>>> ex2 = Example("str")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __init__
  File "<stdin>", line 11, in __set__
TypeError: Expected an int
>>> ex3 = Example(3)
>>> hasattr(ex3, 'x')
True
>>> del ex3.x
>>> hasattr(ex3, 'x')
False

@staticmethod, @classmethod

# @classmethod: 绑定 class
# @staticmethod: 和 python 方法类似,只是在类里面
>>> class example(object):
...   @classmethod
...   def clsmethod(cls):
...     print "I am classmethod"
...   @staticmethod
...   def stmethod():
...     print "I am staticmethod"
...   def instmethod(self):
...     print "I am instancemethod"
...
>>> ex = example()
>>> ex.clsmethod()
I am classmethod
>>> ex.stmethod()
I am staticmethod
>>> ex.instmethod()
I am instancemethod
>>> example.clsmethod()
I am classmethod
>>> example.stmethod()
I am staticmethod
>>> example.instmethod()
Traceback (most recent call last):
  File "", line 1, in
TypeError: unbound method instmethod() ...

抽象方法 - 元类(Metaclass)

# 通常用于定义抽象方法(没有实现的方法)
>>> from abc import ABCMeta, abstractmethod
>>> class base(object):
...   __metaclass__ = ABCMeta
...   @abstractmethod
...   def absmethod(self):
...     """ Abstract method """
...
>>> class example(base):
...   def absmethod(self):
...     print "abstract"
...
>>> ex = example()
>>> ex.absmethod()
abstract

# 更优雅定义抽象类的方法
>>> class base(object):
...   def absmethod(self):
...     raise NotImplementedError
...
>>> class example(base):
...   def absmethod(self):
...     print "abstract"
...
>>> ex = example()
>>> ex.absmethod()
abstract

常用 Magic 方法

# 见 python 文档: data model
# 一般类
__main__
__name__
__file__
__module__
__all__
__dict__
__class__
__doc__
__init__(self, [...)
__str__(self)
__repr__(self)
__del__(self)

# 描述
__get__(self, instance, owner)
__set__(self, instance, value)
__delete__(self, instance)

# 上线文管理
__enter__(self)
__exit__(self, exc_ty, exc_val, tb)

# 仿写容器
__len__(self)
__getitem__(self, key)
__setitem__(self, key, value)
__delitem__(self, key)
__iter__(self)
__contains__(self, value)

# 属性操作
__getattr__(self, name)
__setattr__(self, name, value)
__delattr__(self, name)
__getattribute__(self, name)

# Callable 对象
__call__(self, [args...])

# 比较
__cmp__(self, other)
__eq__(self, other)
__ne__(self, other)
__lt__(self, other)
__gt__(self, other)
__le__(self, other)
__ge__(self, other)

# 数学操作
__add__(self, other)
__sub__(self, other)
__mul__(self, other)
__div__(self, other)
__mod__(self, other)
__and__(self, other)
__or__(self, other)
__xor__(self, other)

分析 csv

# python2 和 python3 兼容

>>> try:
...     from StringIO import StringIO  # python2 用法
... except ImportError:
...     from io import StringIO  # python3 用法
...
>>> import csv
>>> s = "foo,bar,baz"
>>> f = StringIO(s)
>>> for x in csv.reader(f): print(x)
...
['foo', 'bar', 'baz']

# 或者

>>> import csv
>>> s = "foo,bar,baz"
>>> for x in csv.reader([s]): print(x)
...
['foo', 'bar', 'baz']