美文网首页
Python进阶

Python进阶

作者: 无心Y | 来源:发表于2019-12-26 20:30 被阅读0次

    编程风格

    • 分号

      • 不要在行尾加分号
      • 不要使用分号将两行连在一起
    • 行长度

      • 行长度不超过80个字符
      • 长的URL链接,例外
      • 长的模块导入语句,例外
      • 不要使用换行符连接两行,可使用'()'隐式连接
    • 括号

      • 不要在返回语句或条件语句中使用'()'
    • 缩进

      • 用4个空格代替缩进
      • 不要使用tab来缩进
    • 空行

      • 顶级定义(模块变量、函数、类定义)之间空两行
      • 方法定义之间空一行
    • 空格

      • 括号内不要有空格
      • ',',':'前不要有空格
      • 参数列表、索引、切片的左括号前不要加空格
      • 二元操作符(<, <=, ==, !=, and, not, or, in, is)的两边要加上空格
      • '='用户关键字参数时,两边不要加空格
      • '='用户赋值语句是,两边要加空格
    • 注释(文档字符串)

      • 模块--每个文件都应该包含许可样板
      • 函数和方法
        • Args: 列出每个参数的名字和描述
        • Returns: 描述返回值的类型和定义
        • Raises: 列出与接口有关的所有异常
        • 类应该在其定义下有一串描述类功能的字符串
        • 如果类有公共属性使用Attributions描述属性
      • 块注释和行注释
        • 对于复杂的操作, 应该在其操作开始前写上若干行注释
        • 对于不是一目了然的代码, 应在其行尾添加注释.
    class SampleClass(object):
        """Summary of class here.
    
        Longer class information....
        Longer class information....
    
        Attributes:
            likes_spam: A boolean indicating if we like SPAM or not.
            eggs: An integer count of the eggs we have laid.
        """
    
        def __init__(self, likes_spam=False):
            """Inits SampleClass with blah."""
            self.likes_spam = likes_spam
            self.eggs = 0
    
        def public_method(self):
            """Performs operation blah."""
    
    • TODO注释

      • 为临时代码使用TODO注释
      • 为将来要做的某件事使用TODO注释,并确保包含了一个具体日期或触发条件
    • 字符串

      • 使用%和format方法格式化字符串
      • 避免在循环中使用 '+' 或 '+='连接字符串,使用列表保存,结束后用join连接
      • 同一文件中,保持字符串引号一致性,要么全部使用单引号,要么全部使用双引号
      • 为多行字符串使用三重双引号
      • 如果一个类不能显式的继承自其它类,那么将显式继承object类
      • 内部类也遵循以上规则
    • 文件和sockets

      • 推荐使用with语句管理文件和类文件对象
      • 不支持with语句的对象可使用contextlib.closing()显示关闭
    • 导入格式

      • 每个导入独占一行
      • 导入语句在文件顶部
      • 导入顺序分别为:标准库、第三方库、指定文件
    • 命名

    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

    编码处理

    • python2中unicode表示字符串,str表示字节码

    • python3中str表示字符串,bytes表示字节码

    • 不要对字符串进行decode, 不要对字节码进行encode

    • 输入时将所有的字符转为字符串进行处理,输出时根据不同平台进行编码

      • decode early
      • uicode(py2), str(py3) everywhere
      • encode later
    • 声明文件编码 # -*- coding: utf-8 -*-

    • 获取和修改系统默认编码

    import sys
    print(sys.getdefaultencoding())
    
    sys.setdefaultencoding('utf-8') # 慎用此方法
    print(sys.getdefaultencoding())
    

    魔方方法

    • 基本定制
    class A():
        def __init__(self):        # 初始化实例
            print "call __init__"
            self.a = 1
    
        def __new__(cls):         # 构造函数,创建实例
            print "call __new__"
    
        def __del__(self):         # 析构函数,删除实例
            print "call __del__"
    
        def __str__(self):         # 打印字符输出,内建函数str()
            print "call __str__"
            return "class A str"
    
        def __repr__(self):        # 运行时字符串输出,内建函数repr()
            print "call __repr__"
            return "class A repr"
    
        def __unicode__(self):     # 返回字符串,内建函数unicode()
            print "call __unicode__"
            return "class A unicode"
    
        def __nozero__(self):      # obj的布尔值,内建函数bool()
            print "call __nozero__"
            return 1
    
        def __len__(self):         # 返回obj的长度,内建函数len()
            print "call __len__"
            return 1
    
        def __call__(self, *args): # 对象是否可调用
            print "call __call__"
    
            
    a = A()
    print a
    repr(a)
    unicode(a)
    print(bool(a))
    print(len(a))
    print(callable(a))
    
    • __init__和 __new__

      • __new__ 创建对象实例,相当于构造函数,先调用
      • __init__ 初始化实例对象,给对象赋值,后调用
    • 对象比较

    class A():
        def __init__(self, value):
            self.value = value
    
        def __cmp__(self, obj):      # 内建cmp()
            print "call __cmp__"
            return self.value - obj.value
    
        def __lt__(self, obj):       # <
            print "call __lt__"
            return self.value < obj.value
    
        def __gt__(self, obj):       # >
            print "call __gt__"
            return self.value > obj.value
    
        def __eq__(self, obj):       # ==
            print "call __eq__"
            return self.value == obj.value
    
    a1 = A(1)
    a2 = A(2)
    print(cmp(a1,a2))
    print(a1 < a2)
    print(a1 > a2)
    print(a1 == a2)
    
    • 属性操作
    class A():
        def __init__(self):
            self.value = 1
    
        def __getattr__(self, name):         # 内建getattr();仅当属性没有找到时调用
            print "call __getattr__"
            try:
                return self.__dict__[name]
            except:
                return "not found"
    
        def __setattr__(self, name, value):  # 内建setattr()
            print "call __setattr__"
            self.__dict__[name] = value
    
        def __delattr__(self, name):
            print "call __delattr__"
            del self.__dict__[name]
    
        def __getattribute__(self, name):    # 内建getattr(),总是被调用
            print "call __getattribute__"
            return self.__dict__[name]
    
        def __get__(self, name):             # 描述符
            pass
        def __set__(self, name, value):
            pass
        def __del__(self):
            pass
    
    a = A()
    print(getattr(a, "value"))
    print(getattr(a, "name"))
    del a.value
    
    • get、getattr、getattribute

      • __getattribute__ 无条件被调用,通过实例访问属性
      • __getattr__ 仅当属性找不到时调用,返回一个值或AttributionError
      • __get__ 定义了该方法的类自动变成描述符
        • 描述符是为处理重复的属性方法,编写单独的类来处理
        • 定义了__get__,__set__,__delete__,__set_name__方法的为数据描述符,只定义了__get__方法的为非数据描述符
        • 描述符要定义在类变量中
        • 描述符类中使用弱引用(weakref)来存储实例属性,防止内存泄漏
        • 使用实例对象访问属性时,默认调用__getattribute__方法,该方法查找属性的顺序依次为:类属性 -> 数据描述符 -> 实例属性 -> 非数据描述符 -> __getattr__
    • 数值和二进制

    C.__*add__(self, obj)         # 加;+操作符
    C.__*sub__(self, obj)         # 减;-操作符
    C.__*mul__(self, obj)         # 乘;*操作符
    C.__*div__(self, obj)         # 除;/操作符
    C.__*truediv__(self, obj)     # True 除;/操作符
    C.__*floordiv__(self, obj)    # Floor 除;//操作符
    C.__*mod__(self, obj)         # 取模/取余;%操作符
    C.__*divmod__(self, obj)      # 除和取模;内建divmod()
    C.__*pow__(self, obj[, mod])  # 乘幂;内建pow();**操作符
    C.__*lshift__(self, obj)      # 左移位;<<操作符
    C.__*rshift__(self, obj)      # 右移;>>操作符
    C.__*and__(self, obj)         # 按位与;&操作符
    C.__*or__(self, obj)          # 按位或;|操作符
    C.__*xor__(self, obj)         # 按位与或;^操作符
    
    • 序列
    C.__len__(self)                  # 序列中项的数目
    C.__getitem__(self, ind)         # 得到单个序列元素
    C.__setitem__(self, ind,val)     # 设置单个序列元素
    C.__delitem__(self, ind)         # 删除单个序列元素
    
    C.__getslice__(self, ind1,ind2)  # 得到序列片断
    C.__setslice__(self, i1, i2,val) # 设置序列片断
    C.__delslice__(self, ind1,ind2)  # 删除序列片断
    C.__contains__(self, val) f      # 测试序列成员;内建in 关键字
    C.__*add__(self,obj)             # 串连;+操作符
    C.__*mul__(self,obj)             # 重复;*操作符
    C.__iter__(self)                 # 创建迭代类;内建iter()
    
    • 映射
    C.__len__(self)                  # mapping 中的项的数目
    C.__hash__(self)                 # 散列(hash)函数值
    C.__getitem__(self,key)          # 得到给定键(key)的值
    C.__setitem__(self,key,val)      # 设置给定键(key)的值
    C.__delitem__(self,key)          # 删除给定键(key)的值
    C.__missing__(self,key)          # 给定键如果不存在字典中,则提供一个默认值
    

    装饰器

    • 函数特点

      • python中一切皆对象,函数也是对象
      • 函数可作为参数和返回值
      • 装饰器就是在不改变原有函数实现的前提下,给函数添加额外的功能
    • 不带参数的装饰器

    from functools import wraps
    
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('do something here')
            return func(*args, **kwargs)
        return wrapper
    
    @decorator
    def say(sth):
        print('say %s' % sth)
    
    • 带参数的装饰器
    from functools import wraps
    
    def decorator(arg)
        def wrapper(func):
            @wraps(func)
            def inner_wrapper(*args, **kwargs):
                print('do something here with %s' % arg)
                return func(*args, **kwargs)
            return inner_wrapper
        return wrapper
    
    @decorator('argument')
    def say(sth):
        print('say %s' % sth)
    
    • 装饰器类
    class decorator(object):
        def __init__(self, arg='ARGU'):
            self.arg = arg
            
        def __call__(self, func):
            def wrapper(*args, **kwargs):
                print("%s: enter function %s()" % (self.arg, func.__name__))
                func(*args, **kwargs)
            return wrapper  
    
    @decorator(arg='ARGU')
    def say(sth):
        print('say %s' % sth)
    
    • 内置装饰器

      • @property定义一个属性
      • @staticmethod, 定义一个静态方法,返回一个staticmethod对象
      • @classmethod, 定义一个类方法,返回一个classmethod对象
      • 不能在@staticmethod或@classmethod外再使用装饰器,因为他们返回不是一个callable对象
    • 装饰器生效顺序

      • 从上至下,由外到内
    • 使用wrapt优化装饰器

    import wrapt
    
    def logging(level):
        @wrapt.decorator
        def wrapper(wrapped, instance, args, kwargs):
            print "[{}]: enter {}()".format(level, wrapped.__name__)
            return wrapped(*args, **kwargs)
        return wrapper
    
    @logging(level="INFO")
    def do(work): pass
    

    容器、可迭代对象、迭代器、生成器

    • 关联关系
      • 列表、集合、字典解析会生成一个容器
      • 大部分容器是一个可迭代的对象, Bloom Filter(布隆过滤器)不是
      • 可迭代的对象通过iter()方法可以返回一个迭代器
      • 迭代器永远是一个可迭代的对象,迭代器通过next()方法返回元素
      • 生成器是一种特殊的迭代器
    iterator.png
    • 容器

      • 是一个把多个元素组织在一起的数据结构
      • 大部分容器是可迭代的对象,容器中的元素可以逐个迭代获取,for ... in
      • 可以通过in, not in 判断元素是否在容器中
      • 常见容器对象 str, list, tuple, dict, set, frozenset, dequeue, nametuple, defaultdict, OrderedDict, Counter
    • 可迭代对象

      • 实现了__iter__()方法的对象,称之为可迭代对象
      • 可迭代对象可通过for语句迭代
      • 可迭代对象通过内置方法iter()返回一个迭代器
    >>> x = [1, 2, 3]
    >>> y = iter(x)
    >>> z = iter(x)
    >>> next(y)
    1
    >>> next(y)
    2
    >>> next(z)
    1
    >>> type(x)
    <class 'list'>
    >>> type(y)
    <class 'list_iterator'>
    
    • 迭代器
      • 实现了__iter__()方法和__next__()方法的对象称之为迭代器
      • __iter__()方法返回迭代器本身,__next__()方法返回容器中的下一个元素,如果没有将抛出StopIteration异常
      • 迭代器内部保存一个状态,用来记录当前迭代的位置(位置指针)
      • 迭代器是懒加载的,只有在每次询问使用下一个元素时才返回
      • 已返回的元素是通过pop的方式
    class Fib:
        def __init__(self):
            self.prev = 0
            self.curr = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            value = self.curr
            self.curr += self.prev
            self.prev = value
            return value
    
    >>> f = Fib()
    >>> list(islice(f, 0, 10))
    [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    
    • 生成器
      • 生成器是一种特殊的迭代器,它的返回值不是通过return,而是通过yield
      • 使用生成器表达式可以返回生成器对象 (x for x in seq)
      • yield表达式是生成器的关键,它是生成器暂停恢复的点,代码从yield处恢复,又在下一个yield处暂停,使用send(value)方法可以将值显式的传给yield表达式
    def fib():
        prev, curr = 0, 1
        while True:
            yield curr
            prev, curr = curr, curr + prev
    
    >>> f = fib()
    >>> list(islice(f, 0, 10))
    [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    

    itertools

    • 无限迭代器(count, cycle, repeat)
    from itertools import *
    
    # count(start=0, step=1), 返回一个生成器,生成从0开始的连续整数
    for i in izip(count(1), ['a', 'b', 'c']):
        print(i)
    
    (1, 'a')
    (2, 'b')
    (3, 'c')
    
    # cycle(iterable) 返回一个生成器,对可迭代对象中的元素重复
    i = 0 
    for item in cycle(['a', 'b', 'c']):
        i += 1
        print('%d, %s' % (i, item))
        if i == 6:
            break
    (1, 'a')
    (2, 'b')
    (3, 'c')
    (4, 'a')
    (5, 'b')
    (6, 'c')
    
    # repeat(obj, times=None) 重复obj指定次数,未指定无限重复
    
    for i in repeat('loda', 3):
        print(i)
    
    'loda'
    'loda'
    'loda'
    
    
    • 序列处理迭代器(chain, compress, groupby, ifilter, islice, imap, izip, tee)
    from itertools import *
    
    # chain(*iterables), 将多个迭代器合并,产生所有迭代器的元素
    for i in chain([1, 2, 3], ('a', 'b')):
        print(i)
    1
    2
    3
    'a'
    'b'
    
    # compress(iterable, selector) 根据selector对原始数据筛选
    data = ['a', 'b', 'c', 'd', 'e']
    selector = [1, 0, 1, 0, 0]
    for i in compress(data, selector):
        print(i)
    
    'a'
    'c'
    
    # groupby(iterable, key) 返回一个按照key进行分组后的值集合的迭代器
    a = ['aa', 'ab', 'abc', 'bcd', 'abcde']
    for i, k in groupby(a, len):
        print i, list(k)
    
    2 ['aa', 'ab']
    3 ['abc', 'bcd']
    5 ['abcde']
    
    # ifilter(filter_func, iterable) 返回一个filter函数过滤后为true的项  ifilterfalse相反
    for i in ifilter(lambda x: x > 1, [ -1, 0, 1, 2, 3, 4, 1, -2 ]):
        print(i)
    
    2
    3
    4
    
    # islice(iterable, start, stop[, step]) 切片返回迭代器
    for i in islice(count(), 0, 10, 3):
        print(i)
    
    0
    3
    6
    9
    
    # imap(func, *iterables) 使用func作用于每一项,返回一个迭代器
    for i in imap(lambda x: x * 2, xrange(3)):
        print(i)
    
    0
    2
    4
    
    # izip(*iterables) 合并多个迭代对象为元组,并返回该迭代器
    for i in izip(['a', 'b', 'c'], [1, 2, 3]):
        print(i)
    
    ('a', 1)
    ('b', 2)
    ('c', 3)
    
    # tee(iterable[, n=2]) 返回n个独立的迭代器,迭代器和原始迭代器的元素一样
    i1, i2 = tee(islice(count(), 1, 4))
    for i in i1:
        print(i)
    for i in i2:
        print(i)
    
    1
    2
    3
    1
    2
    3
    
    
    • 组合生成器(prduct, permutations, combinations)
    from itertools import *
    
    # product(*iterable) # 生成多个迭代器的笛卡尔积
    c = product((1, 2, 3), ('a', 'b'))
    for i in c:
        print(i)
    
    (1, 'a')
    (1, 'b')
    (2, 'a')
    (2, 'b')
    (3, 'a')
    (3, 'b')
    
    # permutations(iterable[,r]) 返回序列中任意r个元素的全排列
    permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    
    # combinations(iterable[,r]) 返回序列中任意r个元素的组合(不含重复值)
    combinations('ABCD', 2) --> AB AC AD BC BD CD
    
    

    functools

    • functools.partial
    # 通过包装手法,允许我们 “重新定义” 函数签名
    # 用一些默认参数包装一个可调用对象,返回结果是可调用对象,并且可以像原始对象一样对待
    import functools
    
    def add(a, b):
        return a + b
    
    add(4, 2)
    6
    
    plus3 = functools.partial(add, 3)
    plus5 = functools.partial(add, 5)
    
    plus3(4)
    7
    
    plus5(10)
    15
    
    • functools.update_wrapper
    # 默认partial对象没有name和doc
    # 使用update_wrapper(),从原始对象拷贝name、module、doc和 dict 加入现有partial对象
    
    #!/usr/bin/env python
    # encoding: utf-8
    
    def wrap(func):
        def call_it(*args, **kwargs):
            """wrap func: call_it"""
            print 'before call'
            return func(*args, **kwargs)
        return call_it
    
    @wrap
    def hello():
        """say hello"""
        print 'hello world'
    
    from functools import update_wrapper
    def wrap2(func):
        def call_it(*args, **kwargs):
            """wrap func: call_it2"""
            print 'before call'
            return func(*args, **kwargs)
        return update_wrapper(call_it, func)
    
    @wrap2
    def hello2():
        """test hello"""
        print 'hello world2'
    
    if __name__ == '__main__':
        hello()
        print hello.__name__
        print hello.__doc__
    
        print
        hello2()
        print hello2.__name__
        print hello2.__doc__
    
    before call
    hello world
    call_it
    wrap func: call_it
    
    before call
    hello world2
    hello2
    test hello
    
    • functools.wraps
    # 同update_wrapper
    
    from functools import wraps
    def wrap3(func):
        @wraps(func)
        def call_it(*args, **kwargs):
            """wrap func: call_it2"""
            print 'before call'
            return func(*args, **kwargs)
        return call_it
    
    @wrap3
    def hello3():
        """test hello 3"""
        print 'hello world3'
    

    内存管理

    • 引用计数

      • 引用计数增加
        • 对象被创建 a = 2
        • 对象被引用 b = a
        • 对象作为函数参数 sys.getrefcount(a)
        • 对象作为容器元素 lst = [1, a, b]
      • 引用计数减少
        • 对象被显式销毁 del a
        • 对象引用发生变化 a = 2, a = []
        • 对象作用域结束
        • 容器被销毁或对象被容器删除
      • 引用计数为0的对象会被垃圾回收
    • 标记清除

      • 解决循环引用的问题
      • 标记
        • 标记阶段,从根节点(调用栈、寄存器、全局变量)出发,遍历所有的对象,如果可达(还有其他对象引用),则标记为reachable
        • 维护一个引用计数副本,如果有对象引用自己,则遍历时副本引用计数-1(解环),副本引用计数为0的对象标记为unreachable,不可达
        • 调整,从可达对象出发,它所引用的所有的对象都标记为可达
      • 清除
        • 清除阶段再次遍历所有对象,将不可达的对象清除
    • 分代回收

      • 以空间换时间,较少垃圾回收的次数,提高回收效率(存在越久的对象越不可能是垃圾)
      • 对象存在三代(0新, 1青, 2老),新建的对象都处在第0代,当新建对象和释放对象之间的差值到达某个阈值时,自动触发垃圾回收,未被回收的对象会移动到下一代
      • 经过N次0代回收后会进行一次0代和1代回收
      • 经过N次1代回收后会进行一次0代 1代 2代回收
      • 默认值是(700, 10 ,10), gc.get_threshold()

    相关文章

      网友评论

          本文标题:Python进阶

          本文链接:https://www.haomeiwen.com/subject/nfiloctx.html