• 流畅的python(笔记)


    流畅的python中有很多奇技淫巧,整本书都在强调如何最大限度地利用Python 标准库。介绍了很多python的不常用的数据类型、操作、库等,对于入门python后想要提升对python的认识应该有帮助。目前读一遍记录了一些有共鸣的操作:

    Python内置序列类型的主要分类:

    按可存放的元素类型分为:容器序列和扁平序列

    1. 容器序列,就是什么都能作为元素往里放,包括另一个序列。需要注意的是,如果元素是序列类型,那么存放的往往是引用,需要小心。
    常见的容器序列包括:list,tuple,array.array,collections.deque等。
    
    2. 扁平序列,存放的都是原子级元素,此时存放的是值而不会是引用。
    常见的扁平序列包括:str,bytes,bytearray, memoryview, array.array等。
    

    按序列能否被修改分为:可变序列与不可变序列

    1. 可变序列:可以进行增、删、改等操作的序列,包括list, bytearray, array.array, collections.deque, memoryview等。
    2. 不可变序列:不可进行上述操作的序列,包括tuple, str, bytes等。
    

    字典的变种

    标准库里collections模块中提供了很多与字典类型相似的变种。
    
    OrderDict: 这个类型在添加键的时候,会保存顺序,因此键的迭代顺序总是一致的
    
    ChainMap: 该类型可以容纳数个不同的映射对像,在进行键的查找时,这些对象会被当做一个整体逐个查找,直到键被找到为止
    
    Counter: 这个映射类型会给键准备一个整数技术器,每次更行一个键的时候都会增加这个计数器,所以这个类型可以用来给散列表对象计数,或者当成多重集来用。
    
    UserDict: 这个类其实就是把标准的dict用Python又写了一遍。一般用来给程序员想要通过继承dict创建自己的dict时,代替dict使用的。主要是因为直接继承原生dict会出现bug。
    
    defaultdict:处理找不到的键的一个选择
    当某个键不在映射里, 我们也希望也能得到一个默认值. 这就是 defaultdict , 它是 dict 的子类, 并实现了 __missing__ 方法.
    

    dict的实现以及导致的结果

    1. 键必须是可散列的:
    一个可散列的对象必须满足以下要求。
        (1) 支持 hash() 函数,并且通过 __hash__() 方法所得到的散列值是不变的。
        (2) 支持通过 __eq__() 方法来检测相等性。
        (3) 若 a == b 为真,则 hash(a) == hash(b) 也为真。
        所有由用户自定义的对象默认都是可散列的,因为它们的散列值由 id() 来获取,而
        且它们都是不相等的。
    2. 字典在内存上开销很大(用内存换效率)。
        元组取代字典就能节省空间的原因有两个:
        (1) 避免了散列表所耗费的空间,
        (2) 无需把记录中字段的名字在每个元素里都存一遍。
    3. 键的查询很快
    4. 键的次序取决于添加顺序
    5. 往字典里添加新键可能会改变已有键的顺序
    

    set的实现以及导致的结果

    1. 结合的元素必须是可散列的
    2. 集合和消耗内存
    3. 可以很高效的判断元素是否存在于某个集合
    4. 元素的次序取决于被添加到集合里的顺序
    5. 往集合里添加元素,可能会改变集合里已有的元素次序
    

    collections.namedtuple 可以用来构建一个带字段名的元组和一个有名字的类

    创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。后者
    可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。

    >>> from collections import namedtuple
    >>> City = namedtuple('City', 'name country population coordinates')
    >>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667)) 
    >>> tokyo
    City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722,
    139.691667))
    >>> tokyo.population 
    36.933
    >>> tokyo.coordinates
    (35.689722, 139.691667)
    >>> tokyo[1]
    'JP'
    
    >>> City = namedtuple('City_Name', 'name country population coordinates')
    >>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
    >>> tokyo
    City_Name(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
    

    当列表不是首选时

    1. 如果我们需要一个只包含数字的列表,那么 array.array 比 list 更高效。数组支持所
      有跟可变序列有关的操作,包括 .pop、.insert 和 .extend。另外,数组还提供从文件
      读取和存入文件的更快的方法,如 .frombytes 和 .tofile。
    2. set 专为检查元素是否存在做过优化
    3. memoryview 是一个内置类,它能让用户在不复制内容的情况下操作同一个数组的不同切
      片。
    4. 使用NumPy和SciPy提供的高阶数组和矩阵操作
    5. 使用双向队列和其他形式的队列(collections.deque 双向队列类、queue类中的 Queue、LifoQueue和PriorityQueue、multiprocessing. Queue、heapq可以把可变序列当作堆队列或者优先队列来使用)

    Python 格式化输出

    在进行格式化输出时,%r 与 %s 的区别就好比 repr() 函数处理对象与 str() 函数处理对象的差别。

    • %s -> str(),比较智能;
    • %r -> repr(),处理较为简单和直接; 处理一些简单对象时,二者几乎没有差别.

    本文重点列举一些二者的差异化用法:

    1. 处理字符串时
    >> s = 'world'
    
    >> print('hello %s'%s)
    hello world
    >> print('hello %r'%s)
    hello 'world'
    
    >> str(s)
    'world'
    >> repr(s)
    "'world'"
    2. datetime 库中的 datetime 对象
    >> from datetime import datetime 
    >> timeinfo = datetime.today()
    
    >> timeinfo
    datetime.datetime(2016, 6, 7, 21, 17, 34, 925488)
    >> type(timeinfo)
    datetime.datetime
    
    >> repr(timeinfo)
    'datetime.datetime(2016, 6, 7, 21, 17, 34, 925488)'
    >> str(timeinfo)
    '2016-06-07 21:17:34.925488'
    

    反汇编函数 python opcode

    Python dis 模块支持对Python代码进行反汇编, 生成字节码指令。

    In[1]: def test():
    ...         x = 1
    ...         if x < 3:
    ...             return "yes"
    ...         else:
    ...             return "no"
    
    In[2]: dis.dis(test)
      2           0 LOAD_CONST               1 (1)
                  3 STORE_FAST               0 (x)
     
      3           6 LOAD_FAST                0 (x)
                  9 LOAD_CONST               2 (3)
                 12 COMPARE_OP               0 (<)
                 15 POP_JUMP_IF_FALSE       22
     
      4          18 LOAD_CONST               3 ('yes')
                 21 RETURN_VALUE        
     
      6     >>   22 LOAD_CONST               4 ('no')
                 25 RETURN_VALUE        
                 26 LOAD_CONST               0 (None)
                 29 RETURN_VALUE        
    
    >>> def add(a, b = 0):
    ...     return a + b
    ... 
    >>> 
    
    >>> dis.dis(add)
      2           0 LOAD_FAST                0 (a)
                  2 LOAD_FAST                1 (b)
                  4 BINARY_ADD
                  6 RETURN_VALUE
    >>>
    
    
    

    class memoryview(obj)是python的内置类,如果要用memoryview 去引用一个object, 那么这个object 必须支持buffer protocol, python3 中原生(built-in) 支持buffer protocol的obj有bytes和bytearray,memoryview可以使用不同的方式读取和操作同一块内存,并且原有的内存字节不会随意移动。类似于C中的强转,好处是不会有内存拷贝。

    例如,使用memoryview修改一个短整型有符号整数数组的数据。

    from array import array
    from random import random
    
    numbers = array('h', [-2, -1, 0, 1, 2]) #signed short
    memv = memoryview(numbers)      #5个短整型有符号整数的数组创建一个memoryview
    print (len(memv))               #打印长度
    print (memv.tolist())           #转换成列表形式
    
    memv_oct = memv.cast('B')       #内存共享 转换成无符号字符类型
    print (memv_oct.tolist())
    
    memv_oct[5] = 4                 #把位置5的字节赋值成4
    print (numbers)                 #因为我们把占 2 个字节的整数的高位字节改成了 4,所以这个有符号整数的值就变成了 1024
    
    输出如下:
    
    5                       #数组长度
    [-2, -1, 0, 1, 2]       #列表形式显示
    [254, 255, 255, 255, 0, 0, 1, 0, 2, 0]#长度扩大一倍 转换为无符号字符类型
    array('h', [-2, -1, 1024, 1, 2])   #原来的数组被修改
    
    

    bytearray是可变(mutable)的字节序列,相对于Python2中的str,但str是不可变(immutable)的。
    在Python3中由于str默认是unicode编码,所以只有通过bytearray才能按字节访问。
    下面两种行为的对比:
    简单点就是,str和bytearray的切片操作会产生新的切片str和bytearry并拷贝数据,使用memoryview之后不会。

    python2中的例子

    不使用memoryview
    >> a = 'aaaaaa'
    >> b = a[:2]    # 会产生新的字符串
    
    >> a = bytearray('aaaaaa')
    >> b = a[:2]    # 会产生新的bytearray
    >> b[:2] = 'bb' # 对b的改动不影响a
    >> a
    bytearray(b'aaaaaa')
    >> b
    bytearray(b'bb')
    
    使用memoryview
    >> a = 'aaaaaa'
    >> ma = memoryview(a)
    >> ma.readonly  # 只读的memoryview
    True
    >> mb = ma[:2]  # 不会产生新的字符串
    
    >> a = bytearray('aaaaaa')
    >> ma = memoryview(a)
    >> ma.readonly  # 可写的memoryview
    False
    >> mb = ma[:2]      # 不会会产生新的bytearray
    >> mb[:2] = 'bb'    # 对mb的改动就是对ma的改动
    >> mb.tobytes()
    'bb'
    >> ma.tobytes()
    'bbaaaa'
    

    Python 中有各种各样可调用的类型,因此判断置的 callable() 函数:

    >>> abs, str, 13
    (<built-in function abs>, <class 'str'>, 13)
    >>> [callable(obj) for obj in (abs, str, 13)]
    [True, True, False]
    
    random.shuffle 打乱序列
    >>> import random
    >>> a=range(10)
    >>> random.shuffle(a)
    >>> a
    [1, 0, 8, 5, 6, 7, 9, 3, 2, 4]
    >>> random.shuffle(a)
    >>> a
    [7, 5, 6, 2, 1, 8, 9, 0, 3, 4]
    

    vim常用快捷

    • 0 → 数字零,到行头
    • $ → 到本行行尾
    • a → 在光标后插入
    • o → 在当前行后插入一个新行
    • O → 在当前行前插入一个新行
    • cw → 替换从光标所在位置后到一个单词结尾的字符
    • . → (小数点) 可以重复上一次的命令
    • NG → 到第 N 行 (注意命令中的G是大写的,另我一般使用 : N 到第N行,如 :137 到第137行)
    • gg → 到第一行。(相当于1G,或 :1)
    • G → 到最后一行。
    • 在 Insert 模式下,你可以输入一个词的开头,然后按或是,自动补齐功能就出现了…

    内置函数

    Math
    Function	Description
    abs()	Returns absolute value of a number
    divmod()	Returns quotient and remainder of integer division
    max()	Returns the largest of the given arguments or items in an iterable
    min()	Returns the smallest of the given arguments or items in an iterable
    pow()	Raises a number to a power
    round()	Rounds a floating-point value
    sum()	Sums the items of an iterable
    
    Type Conversion
    Function	Description
    ascii()	Returns a string containing a printable representation of an object
    bin()	Converts an integer to a binary string
    bool()	Converts an argument to a Boolean value
    chr()	Returns string representation of character given by integer argument
    complex()	Returns a complex number constructed from arguments
    float()	Returns a floating-point object constructed from a number or string
    hex()	Converts an integer to a hexadecimal string
    int()	Returns an integer object constructed from a number or string
    oct()	Converts an integer to an octal string
    ord()	Returns integer representation of a character
    repr()	Returns a string containing a printable representation of an object
    str()	Returns a string version of an object
    type()	Returns the type of an object or creates a new type object
    
    Iterables and Iterators
    Function	Description
    all()	Returns True if all elements of an iterable are true
    any()	Returns True if any elements of an iterable are true
    enumerate()	Returns a list of tuples containing indices and values from an iterable
    filter()	Filters elements from an iterable
    iter()	Returns an iterator object
    len()	Returns the length of an object
    map()	Applies a function to every item of an iterable
    next()	Retrieves the next item from an iterator
    range()	Generates a range of integer values
    reversed()	Returns a reverse iterator
    slice()	Returns a slice object
    sorted()	Returns a sorted list from an iterable
    zip()	Creates an iterator that aggregates elements from iterables
    
    Composite Data Type
    Function	Description
    bytearray()	Creates and returns an object of the bytearray class
    bytes()	Creates and returns a bytes object (similar to bytearray, but immutable)
    dict()	Creates a dict object
    frozenset()	Creates a frozenset object
    list()	Constructs a list object
    object()	Returns a new featureless object
    set()	Creates a set object
    tuple()	Creates a tuple object
    
    Classes, Attributes, and Inheritance
    Function	Description
    classmethod()	Returns a class method for a function
    delattr()	Deletes an attribute from an object
    getattr()	Returns the value of a named attribute of an object
    hasattr()	Returns True if an object has a given attribute
    isinstance()	Determines whether an object is an instance of a given class
    issubclass()	Determines whether a class is a subclass of a given class
    property()	Returns a property value of a class
    setattr()	Sets the value of a named attribute of an object
    super()	Returns a proxy object that delegates method calls to a parent or sibling class
    
    Input/Output
    Function	Description
    format()	Converts a value to a formatted representation
    input()	Reads input from the console
    open()	Opens a file and returns a file object
    print()	Prints to a text stream or the console
    
    Variables, References, and Scope
    Function	Description
    dir()	Returns a list of names in current local scope or a list of object attributes
    globals()	Returns a dictionary representing the current global symbol table
    id()	Returns the identity of an object
    locals()	Updates and returns a dictionary representing current local symbol table
    vars()	Returns __dict__ attribute for a module, class, or object
    
    Miscellaneous
    Function	Description
    callable()	Returns True if object appears callable
    compile()	Compiles source into a code or AST object
    eval()	Evaluates a Python expression
    exec()	Implements dynamic execution of Python code
    hash()	Returns the hash value of an object
    help()	Invokes the built-in help system
    memoryview()	Returns a memory view object
    staticmethod()	Returns a static method for a function
    __import__()	Invoked by the import statement
    

    跟运算符无关的特殊方法

    类别 方法名
    字符串 / 字节序列表示形式 __repr__、__str__、__format__、__bytes__
    数值转换 __abs__、__bool__、__complex__、__int__、__float__、__hash__、__index__
    集合模拟 __len__、__getitem__、__setitem__、__delitem__、__contains__
    迭代枚举 __iter__、__reversed__、__next__
    可调用模拟 __call__
    上下文管理 __enter__、__exit__
    实例创建和销毁 __new__、__init__、__del__
    属性管理 __getattr__、__getattribute__、__setattr__、__delattr__、__dir__
    属性描述符 __get__、__set__、__delete__
    跟类相关的服务 __prepare__、__instancecheck__、__subclasscheck__
    

    Bisect模块管理有序的序列

    bisect.bisect_left(a,x, lo=0, hi=len(a)) :
    查找在有序列表 a 中插入 x 的index。lo 和 hi 用于指定列表的区间,默认是使用整个列表。如果 x 已经存在,在其左边插入。返回值为 index。
    bisect.bisect_right(a,x, lo=0, hi=len(a))
    bisect.bisect(a, x,lo=0, hi=len(a)) :
    这2个函数和 bisect_left 类似,但如果 x 已经存在,在其右边插入。
    bisect.insort_left(a,x, lo=0, hi=len(a)) :
    在有序列表 a 中插入 x。和 a.insert(bisect.bisect_left(a,x, lo, hi), x) 的效果相同。
    bisect.insort_right(a,x, lo=0, hi=len(a))
    bisect.insort(a, x,lo=0, hi=len(a)) :
    和 insort_left 类似,但如果 x 已经存在,在其右边插入。
    Bisect 模块提供的函数可以分两类: bisect* 只用于查找 index, 不进行实际的插入;而 insort* 则用于实际插入。
    

    当list不是最优选择时,dict是python的核心类型,但它是以空间换时间的结果,比较占内存,tuple是dict结构比较好的替代,set用来做是否包含和去重很合适。(不要把可变对象放在元组里面,如果你可能改变这个可变对象的话,因为增量赋值或其他操作可能不是一个原子操作触发了tuple异常但又改变了tuple)

    from array import array  
    from random import random
    floats = array('d', (random() for i in range(10**7)))  
    fp = open('floats.bin', 'wb')
    floats.tofile(fp)  
    fp.close()
    floats2 = array('d')  
    fp = open('floats.bin', 'rb')
    floats2.fromfile(fp, 10**7)  
    fp.close()
    floats2 == floats
    
    # Python2.7 - Python3.7  都有这个问题
    ``
    >>> a=(1,2,[1,2,3,4,5])
    >>> a[2]+=[1,1,1]
    Traceback (most recent call last):
      File "<pyshell#1>", line 1, in <module>
        a[2]+=[1,1,1]
    TypeError: 'tuple' object does not support item assignment
    >>> a
    (1, 2, [1, 2, 3, 4, 5, 1, 1, 1])
    >>> a[2].extend([2,2,2])
    >>> a
    (1, 2, [1, 2, 3, 4, 5, 1, 1, 1, 2, 2, 2])
    >>>
    ```
    

    Python_内置四种队列

    from queue import Queue #LILO队列
    q = Queue() #创建队列对象
    q.put(0)    #在队列尾部插入元素
    q.put(1)
    q.put(2)
    print('LILO队列',q.queue)  #查看队列中的所有元素
    print(q.get())  #返回并删除队列头部元素
    print(q.queue)
    
    from queue import LifoQueue #LIFO队列
    lifoQueue = LifoQueue()
    lifoQueue.put(1)
    lifoQueue.put(2)
    lifoQueue.put(3)
    print('LIFO队列',lifoQueue.queue)
    lifoQueue.get() #返回并删除队列尾部元素
    lifoQueue.get()
    print(lifoQueue.queue)
    
    from queue import PriorityQueue #优先队列
    priorityQueue = PriorityQueue() #创建优先队列对象
    priorityQueue.put(3)    #插入元素
    priorityQueue.put(78)   #插入元素
    priorityQueue.put(100)  #插入元素
    print(priorityQueue.queue)  #查看优先级队列中的所有元素
    priorityQueue.put(1)    #插入元素
    priorityQueue.put(2)    #插入元素
    print('优先级队列:',priorityQueue.queue)  #查看优先级队列中的所有元素
    priorityQueue.get() #返回并删除优先级最低的元素
    print('删除后剩余元素',priorityQueue.queue)
    priorityQueue.get() #返回并删除优先级最低的元素
    print('删除后剩余元素',priorityQueue.queue)  #删除后剩余元素
    priorityQueue.get() #返回并删除优先级最低的元素
    print('删除后剩余元素',priorityQueue.queue)  #删除后剩余元素
    priorityQueue.get() #返回并删除优先级最低的元素
    print('删除后剩余元素',priorityQueue.queue)  #删除后剩余元素
    priorityQueue.get() #返回并删除优先级最低的元素
    print('全部被删除后:',priorityQueue.queue)  #查看优先级队列中的所有元素
    
    from collections import deque   #双端队列
    dequeQueue = deque(['Eric','John','Smith'])
    print(dequeQueue)
    dequeQueue.append('Tom')    #在右侧插入新元素
    dequeQueue.appendleft('Terry')  #在左侧插入新元素
    print(dequeQueue)
    dequeQueue.rotate(2)    #循环右移2次
    print('循环右移2次后的队列',dequeQueue)
    dequeQueue.popleft()    #返回并删除队列最左端元素
    print('删除最左端元素后的队列:',dequeQueue)
    dequeQueue.pop()    #返回并删除队列最右端元素
    print('删除最右端元素后的队列:',dequeQueue)
    
    
    以上队列在多线程中可以使用的且线程安全,但在多进程中都不能用于通信。在多进程中,需要这样使用:
    from multiprocessing import Process, Queue
    myqueue = Queue(100)
    
    
    ## 参考
    
    https://blog.csdn.net/sinat_38682860/article/details/80392493 
    https://www.cnblogs.com/cmnz/p/6936181.html
    

    关键字

    from keyword import kwlist
    print(kwlist)
    

    builtins模块

    import builtins
    dir(builtins)
    

    Python locals() 的陷阱

    https://segmentfault.com/a/1190000012724861
    
    def test():
        globals()['a2'] = 4
    test()
    print a2   # 输出 4
    
    
    def aaaa():
        print locals()
        for i in ['a', 'b', 'c']:
            locals()[i] = 1
        print locals()
        print a # 错误:NameError: global name 'a' is not defined
    aaaa()
    

    动态地进行变量赋值时,locals() 看到的, 的确是函数的局部命名空间的内容, 但是它本身不能代表局部命名空间, 这就好像一个代理, 它收集了A, B, C的东西, 展示给我看, 但是我却不能简单的通过改变这个代理, 来改变A, B, C真正拥有的东西!
    这也就是为什么, 当我们通过locals()[i] = 1的方式去动态赋值时, print a却触发了NameError异常, 而相反的, globals()确实真正的全局命名空间,
    所以一般会说locals() 只读, globals() 可读可写。

    x += y vs x = x + y

    对于一般不可变类型的变量来说这两个方法没啥区别,但对于可变类型如list(列表),dict(字典)就有区别了,x += y 就地改变了list的值,而x = x + y创建了一个新的list并重新将x绑定上去,通过id(x)就可以看出。

    l = l + [3, 4, 5]    这种背后就是BINARY_ADD
    l += [3, 4, 5]     这种背后就是INPLACE_ADD
    

    +=实际上应该能算是一个加强版的+, 因为它比+多了一个写回本身的功能.不过是否能够写回本身, 还是得看对象自身是否支持, 也就是说是否具备Py_NotImplemented标识, 是否支持sq_inplace_concat, 如果具备, 才能实现, 否则, 也就是和 + 效果一样而已.

    不仅仅是这些,当混合使用可变类型和不可变类型的时候,你会有更加惊奇的发现:

    >>> t = ([],)
    >>> t[0] += [2, 3]
    Traceback (most recent call last):
      File "<input>", line 1, in ?
    TypeError: object doesn't support item assignment
    >>> t
    ([2, 3],)
    

    明显的,元组不支持对其中元素的赋值——但是在对他使用+=后,元组里的list确实改变了!原因依然是+=就地改变list的值。但是元组的赋值不被允许,当异发生时,元组中的list已经被就地改变了。
    这就是一个我个人觉得非常致命的陷阱。
    解决方法:干脆避免使用+=,或者仅仅在整数时使用它。

    使用()创建tuple

    >>> a=(1) # 错误姿势
    >>> type(a)
    <type 'int'>
    
    >>> a=(1,) # 正确姿势
    >>> type(a)
    <type 'tuple'>
    
    # python中 not, and, or 的优先级
    
    not > and > or
    
    # 全为 true 的情况下:
    and:取大
    >>>3 and 4
    4
    >>> 5 and 6
    6
    or:取前
    >>>3 or 4
    3
    >>>6 or 5
    
    In [17]: 2 or 3 or 4
    Out[17]: 2
    
    In [18]: 2 and 3 and 4
    Out[18]: 4
    
    # 几种格式可以与dict互转
    In [145]: c=((1,2),(3,4))
    In [146]: dict(c)
    Out[146]: {1: 2, 3: 4}
    
    In [151]: a=[[1,2],[3,4]]
    In [152]: dict(a)
    Out[152]: {1: 2, 3: 4}
    
    In [153]: a=[(1,2),(3,4)]
    In [154]: dict(a)
    Out[154]: {1: 2, 3: 4}
    
    In [155]: a=([1,2],[3,4])
    In [156]: dict(a)
    Out[156]: {1: 2, 3: 4}
    
    
    In [162]: b={1: 2, 3: 4}
    In [163]: set(b)
    Out[163]: {1, 3}
    In [164]: list(b)
    Out[164]: [1, 3]
    
    
    # {} 是dict 非空就是set
    In [175]: type({})
    Out[175]: dict
    
    In [176]: type({1,2,3})
    Out[176]: set
    
    In [177]: type(())
    Out[177]: tuple
    
    In [178]: type([])
    Out[178]: list
    

    Python的list循环遍历中,删除数据的正确方法

    通用的解决方案:

    num_list = [1, 2, 3, 4, 5, 2, 2, 4]
    
    1. 倒序循环遍历
    
    for i in range(len(num_list) - 1, -1, -1):  # 讲究
        if num_list[i] == 2:
            num_list.pop(i)
    print(num_list)
    
    2. 遍历拷贝的list,操作原始的list。对于过大的list,拷贝后可能很占内存,可以用倒序遍历的方法来实现。
    
    for item in num_list[:]:    # 保证可以把num_list从头遍历到尾
        if item == 2:
            num_list.remove(item) # 从头删除遇到的第一个item
    print(num_list)
    
    
    3. 对原来的列表做过滤,生成一个新的列表(假设determine(x)为判断条件的函数):
    
    list = [x for x in list if not determine(x)]
    
    4. 在原来列表上做切片,仅保留需要的元素
    
    list[:] = [x for x in list if not determine(x)]
    
    5. python2.x ifilterfalse()方法
    
    from itertools import ifilterfalse()
    list[:] = ifilterfalse(determine, list)
    
    6. Python3 filterfalse()方法
    
    from itertools import filterfalse
    list[:] = filterfalse(determine, list)
    
    方法5,6对列表的修改会反应到其他对此列表的引用上。
    

    作用域解析是基于LEGB规则,分别是Local、Enclosing、Global、Built-in

    函数内定义的局部变量必须global申明才能使用全局变量

    def local_var_err():
        b += [3]  # UnboundLocalError: local variable 'b' referenced before assignment
        b = b + [2]  # UnboundLocalError: local variable 'b' referenced before assignment
    

    不遍历情况下迭代器与生成器的性能比较

    In [109]: %timeit -n100 a = (i for i in range(100000))
    100 loops, best of 3: 659 µs per loop
    
    In [110]: %timeit -n100 b = [i for i in range(100000)]
    100 loops, best of 3: 2.68 ms per loop
    

    遍历情况下迭代器与生成器的性能比较

    In [112]: %timeit -n100 for x in (i for i in range(100000)):pass
    100 loops, best of 3: 4.23 ms per loop
    
    In [113]: %timeit -n100 for x in [i for i in range(100000)]:pass
    100 loops, best of 3: 3.49 ms per loop
    

    空间换时间

    尽量使用局部变量

    # -*- coding:utf-8 -*-
    import timeit
    
    test_dict = {}
    
    class dome(object):
        def test_class(self):
            num = 100
            self.test_dict = {}        # 为了公平,每次执行都同样初始化新的 {}
            for i in range(num):
                self.test_dict[i] = i
    
        def test_local(self):
            num = 100
            test_dict = {}             # 为了公平,每次执行都同样初始化新的 {}
            for i in range(num):
                test_dict[i] = i
            self.test_dict = test_dict
    
        def test_global(self):
            num = 100
            global test_dict
            test_dict = {}              # 为了公平,每次执行都同样初始化新的 {}
            for i in range(num):
                test_dict[i] = i
    
    s = dome()
    
    print(timeit.timeit(stmt=s.test_class))    # 9.75976037823
    print(timeit.timeit(stmt=s.test_local))    # 7.17526431985
    print(timeit.timeit(stmt=s.test_global))   # 7.57540534177
    
    """
    1. 访问局部变量速度要快很多
    2. 循环之外能做的事不要放在循环内
    在一些会频繁操作 类/实例属性 的情况下,应该是先把 属性 取出来存到 局部变量,然后用 局部变量 来完成操作。最后视情况把变动更新到 属性 上。
    """
    

    拼接字符串列表时使用join

    a=list(str(range(1000)))
    
    In [126]: %%timeit
    s=""
    for x in a:
        s+=x
       .....: 
    1000 loops, best of 3: 304 µs per loop
    
    In [127]: %%timeit
       .....: s="".join(a)
       .....: 
    10000 loops, best of 3: 59.3 µs per loop
    
    参考博客 https://blog.csdn.net/xdhstc/article/details/51719892
    

    if is True 对比 if == True,列表推导。

    # -*- coding:utf-8 -*-
    import timeit
    
    def test_1():
        a = [True] * 100
        s = []
        for i in a:
            if i == True:
                s.append(i)
        return s
    
    
    def test_2():
        a = [True] * 100
        return [i for i in a if i is True]
    
    
    def test_3():
        a = [True] * 100
        return [i for i in a if i == True]
    
    
    def test_4():
        a = [True] * 100
        return [i for i in a if i]
    
    
    print(timeit.timeit(stmt=test_1))  # 11.5888194259
    print(timeit.timeit(stmt=test_2))  # 6.00562291202
    print(timeit.timeit(stmt=test_3))  # 7.15504198257
    print(timeit.timeit(stmt=test_4))  # 4.29275713242
    

    使用**而不是pow

    In [145]: %timeit -n100000 c = pow(2,20)
    100000 loops, best of 3: 89.3 ns per loop
    
    In [146]: %timeit -n100000 c = 2**20
    100000 loops, best of 3: 22.2 ns per loop
    

    带有条件判断的嵌套for循环时尽量分析条件减少循环次数

    # -*- coding:utf-8 -*-
    import timeit
    
    
    def test1():
        s = []
        for z in range(10):
            for y in range(100):
                for x in range(1000):
                    if x > 100 and y > 50 and z > 5:
                        return s
                    s.append((x, y, z))
    
    
    
    def test2():
        s = []
        for x in range(1000):
            for y in range(100):
                for z in range(10):
                    if x > 100 and y > 50 and z > 5:
                        return s
                    s.append((x, y, z))
    
    
    
    print(timeit.timeit(stmt=test1, number=100))    # 14.1777687741
    print(timeit.timeit(stmt=test2, number=100))    # 2.03417086749
    print(sorted(test1()) == sorted(test2()))       # False
    print(len(test1()))                             # 651101
    print(len(test2()))                             # 101516
    

    pip常用命令

    pip install keras==2.1.0    # 安装指定版本
    pip install –upgrade keras==2.1.0   #升级package到指定版本
    pip install --no-index -f=<目录>/ <包名>    # 安装本地安装包
    pip uninstall <包名> 或 pip uninstall -r requirements.txt  # 卸载包
    pip install -U <包名> #升级包 pip install <包名> --upgrade
    pip install -U pip  # 升级pip
    pip show -f <包名>    # 显示包所在的目录
    pip search <在线搜索关键字>  # 搜索包
    pip list -o # 查询可升级的包
    pip install <包名> -d <目录> 或 pip install -d <目录> -r requirements.txt  # 下载包而不安装
    pip wheel <包名>  # 打包
    pip install <包名> -i https://mirrors.aliyun.com/pypi/simple  # 指定单次安装源
    # 更换国内pypi镜像
        阿里:https://mirrors.aliyun.com/pypi/simple
        中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/
    
    # 指定全局安装源
        在unix和macos,配置文件为:$HOME/.pip/pip.conf
        在windows上,配置文件为:%HOME%pippip.ini
        [global]
        timeout = 6000
          index-url = https://mirrors.aliyun.com/pypi/simple
    

    还有这样强转类型的骚操作

    >>> type('a')(1)
    '1' 
    

    如何快速反转字符串?

    #Bad
    a = 'Python is a powerful languange.'
    
    list_a = list(a)
    list_a.reverse()
    re_a = ''.join(list_a) 
    
    #Good
    a = 'Python is a powerful languange.'
    re_a = a[::-1]
    

    把列表分割成同样大小的块?

    a = [1, 2, 3, 4, 5, 6]
    list(zip( *[iter(a)]*2 ))
    >>> [(1, 2), (3, 4), (5, 6)]
    
    
    #合并list相邻项
    a = [1, 2, 3, 4, 5, 6]
    
    list(zip( a[::2], a[1::2] ))
    >>> [(1, 2), (3, 4), (5, 6)]
    

    交换dict的键值

    # Bad
    a = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    
    def reverse_dict(a):
        new_dict = {}
        for k,v in m.items():
            new_dict[v] = k
        return new_dict
    
    # Good
    a = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    
    def reverse_dict(a):
        k = a.keys()
        v = a.values()
        new_dict = dict(zip(v, k))
        return new_dict
    

    使用 Counter 进行计数统计

    >>> from collections import Counter
    >>> Counter(s=3, c=2, e=1, u=1)
    Counter({'s': 3, 'c': 2, 'u': 1, 'e': 1})
    
    >>> some_data=('c', '2', 2, 3, 5, 'c', 'd', 4, 5, 'd', 'd')
    >>> Counter(some_data).most_common(2)
    [('d', 3), ('c', 2)]
    >>> some_data=['c', '2', 2, 3, 5, 'c', 'd', 4, 5, 'd', 'd']
    >>> Counter(some_data).most_common(2)
    [('d', 3), ('c', 2)]
    >>> some_data={'c', '2', 2, 3, 5, 'c', 'd', 4, 5, 'd', 'd'}
    >>> Counter(some_data).most_common(2)
    [('c', 1), (3, 1)]
    

    避免类初始化时大量重复的赋值语句

    class A(object):
        def __init__(self, a, b, c, d, e, f):
            self.__dict__.update({k: v for k, v in locals().items() if k != 'self'})
    

    解密PYC 文件很简单

    >>> import dis, marshal
    >>> with open('hello.pyc', 'rb') as f:
    ...     f.seek(8)
    ...     dis.dis(marshal.load(f))
    

    for else,不break的话就执行else

    for i in range(10):
        if i == 10:
            break
        print(i)
    else:
        print('10不在里面!')
        
    相当于:flag = False
    
    for i in range(10):
        if i == 10:
            flag = True
            break
        print(i)
    if not flag:
        print('10不在里面!')
    

    倒序

    >>> a = "live"
    >>> a[::-1]
    'evil'
    

    数制转换

    >>> int('1000', 2)
    8
    >>> int('A', 16)
    10
    

    闭包中的自由变量之坑

    >>> funcs = [lambda x: x*i for i in range(10)]
    >>> [f(1) for f in funcs]
    [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
    
    正确写法:
    >>> funcs = [lambda x, i=i: x*i for i in range(10)]
    >>> [f(1) for f in funcs]
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    finally return

    def some_func():
        try:
            return 'from_try'
        finally:
            return 'from_finally'
    Output:
    
    >>> some_func()
    'from_finally'
  • 相关阅读:
    进程-线程-消息队列
    用Ogre实现《天龙八部》场景中水面(TerrainLiquid)详解
    TCP协议三次握手过程分析【图解,简单清晰】
    excel批量删除sql语句
    批量删除指定盘指定格式文件
    Linux命令速查手册(第2版)学习
    List、Map、Set 三个接口,存取元素时,各有什么特点
    HashMap 什么时候进行扩容呢
    两个对象值相同 (x.equals(y) == true),但却可有不同的 hash code,这句话对不对?
    ArrayList,Vector, LinkedList 的存储性能和特性
  • 原文地址:https://www.cnblogs.com/lgjbky/p/9634773.html
Copyright © 2020-2023  润新知