美文网首页
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