错误处理

Exception: All built-in, non-system-exiting exceptions are derived from this class. All user-defined exceptions should also be derived from this class

class NotFound(Exception):
    pass

def getheadnum(idlist, head):
    i = 0
    for id in idlist:
        if head in id:
            return i
        i = i+1
    raise NotFound('not found head: %s' % head)
try:
    pass
except NotFound as e:
    print('except:', e)
except Another as e:
    pass
else:
    pass
finally:
    pass

List Comprehension

[x*x for x in range(0, 10)]
[x*x for x in range(0, 10) if x%2 != 0]
[m+n for m in range(0, 10) for n in range[0, 10]]
[k+'='+v for k, v in d.items()]

对比

def getidlist():
    l = []
    with open('id.xml', 'r') as f:
        for line in f.readlines():
            l.append(line.strip())
    return l
def getidlist():
    with open('id.xml', 'r') as f:
        return [line.strip() for line in f.readlines()]

Generator Expression

将列表生成式的[]换为()

(x*x for x in range(0, 10))

Iterable Iterator

凡是可作用于for循环的对象都是Iterable类型,for循环先使用iter()获得一个Iterator对象,然后通过不断对该Iterator对象调用next()函数获得下一个值,例如:

for x in [1, 2, 3, 4, 5]:
    pass

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        del it
        break

也就是说,要想被Python的for访问,首先要定义__iter__方法,这个方法返回一个Iterator对象(也就是说,对象内部定义了__next__方法)

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

另外,实现__getitem__方法的对象也是Iterable

包含__next__方法的对象为Iterator对象,可通过next()方法调用。类如果定义__iter__方法返回一个可迭代对象,则可以使用for ... in class,会不断调用该可迭代对象的__next__方法,直到遇到StopIteration错误时退出循环(复杂的generator)

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1  # 初始化两个计数器a,b

    def __iter__(self):
        return self  # 实例本身就是迭代对象,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b  # 计算下一个值
        if self.a > 100:  # 退出循环的条件
            raise StopIteration()
        return self.a  # 返回下一个值

for n in Fib():
    print(n)

iter()

如果iter()只有一个参数,则这个参数必须有__iter____getitem__方法(__getitem__使用从0开始的参数);如果使用iter()的第二个参数,则第一个参数必须是callable object,调用第一个参数返回一个iterator,如果iterator返回的value等于第二个参数,则raise StopIteration。

例如,读一个文件,检测到文件为空则停止(readline在读完文件后会不断返回''):

with open('mydata.txt') as fp:
    for line in iter(fp.readline, ''):
        process_line(line)

函数式常用方法

1. Iterator = map(fn, Iterable…)

r = map(abs, range(0,-10,-1))

map是常用generator expressions的另一种形式,上式相当于:

r = (abs(x) for x in range(0,-10-1))

如果提供多个Iterable,则fn必须接受多个参数:

r = map(cmp, iter1, iter2)

r = (cmp(a, b) for a,b in zip(iter1, iter2))

2. Iterator = filter(fn, Iterable)

Construct an iterator from those elements of iterable for which function returns true

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]
(item for item in iterable if fn(item))

3. reduce

>>> from functools import reduce
>>> def add(x, y):
...     return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

4. lambda

lambda x: x * x

变量命名

  1. 实例的私有变量(private)以双下划线开头,只能内部访问,如__name, 一般内部访问为self.__name 一般在外部可用_类名__name访问, 通过dir(实例)可以查看到
  2. 以双下划线开头和结尾的变量为特殊变量,不是私有变量,外部可访问,如__name__
  3. 以单下划线开头的变量可以外部访问,但其约定为私有变量,如_name
  4. 如果与Python关键字或内置变量重名,在变量后加单下划线,如name_

oop

  1. @classmethod修饰的类方法,类内部方法使用cls.property访问类属性,以cls为第一参数,可以被类或实例调用
  2. @staticmethod修饰的方法,不以selfcls为第一参数,而是任意参数,可以被类或实例调用
  3. 使用self.property访问实例属性
  4. 使用__slots__限制类属性:

     class Student(object):
         __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    

    使用__slots__要注意,slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的: 除非在子类中也定义__slots,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。

  5. 使用@property

     class Student(object):
    
         @property
         def birth(self):
             return self._birth
    
         @birth.setter
         def birth(self, value):
             self._birth = value
    
         @property
         def age(self):
             return 2015 - self._birth
    
  6. 记得多重继承是优先使用Mixin
  7. 类的特殊方法:
    • __str__: print(class)时调用
    • __repr__: class时调用
    • __iter____next__
    • __getitem__
    • __call__

global

Python中在函数外定义的变量,如函数内无同名变量,可在函数内引用(reference)

s = "hello"

def foo():
    print(s)    # 引用外部变量s

def bar():
    s = 'world' # 新定义了内部变量s

但如果即想引用,又想在原有基础上修改,可以使用global在函数内声明为global变量

s = "hello"

def change_it(n):
    global s         # 声明s为global变量
    s = s + 'world'  # 先引用s,之后修改s

如果不进行声明,会报错UnboundLocalError: local variable 's' referenced before assignment

建议无论是什么情况,使用global变量一定进行声明

点滴

  1. 使用isinstance判断类型
  2. 比较:
    1. 可以直接使用1<x<9
    2. isis not
    3. innot in
  3. 1, 2, 3 ....不用加括号,即为tuple,所以可以使用return 1, 2, 3yield 1, 2, 3会返回tuple(1, 2, 3),长度任意,同时可实现a, b = b, a完成交换
  4. (“spam “ “eggs”) == “spam eggs”,可以用来将长字符串分割为多行
  5. x if x<y else y等同于C中x<y ? x:y
  6. 文本以str类型表示,二进制数据以bytes类型表示

        --> encdoe('utf-8') -->
       /                       \
     str                      bytes
       \                       /
        <-- decode('utf-8') <--
    
  7. json

        ----> json.loads ---->
       /                       \
     str                      object
       \                       /
        <---- json.dumps <----
    
  8. 使用 \ 分割过长的行(Shell Script、Python在分割的第一行,vimscript在分割的第二行)
  9. docstring:
    1. ”"”triple double quotes”””
    2. Use r”"”raw triple double quotes””” if you use any backslashes in your docstrings
    3. For Unicode docstrings, use u”"”Unicode triple-quoted strings”””
  10. 我的Python安装目录为D:\Python35第三方扩展安装目录为D:\Python35\Lib\site-packages
  11. python3 -m http.server 8080
  12. *

    a, b, *rest = range(5)
    
    def fun(*args):
        pass
    t = (1, 2)
    fun(*t)
    
  13. from module import *如果module中有__all__,则只会引入__all__中的项。如果没有__all__则会引入除以下划线开头的项。

@functools.wraps

使用装饰器,一定记得加@functools.wraps,平时不注意,觉得被装饰函数的__name__属性改变也没什么,等到定义路由时就发现,__name__一变,路由处理函数就就找不到了。

import functools

def all_computers_refresh(func): # 定义装饰器,更新所有电脑信息
    @functools.wraps(func)
    def wrapper(*args, **kw):
        computer_list = Computer.query.all()
        for computer in computer_list:
            computer.refresh()
            db.session.add(computer)
        return func(*args, **kw)
    return wrapper

@manage.route('/all_computers')
@all_computers_refresh
def all_computers():
    return render_template('manage/all_computers.html',
                           computer_list=Computer.query.all())

我在上面的路由处理函数中遇到的问题,直接粘过来。