• Pythonic---------详细讲解


    作者:半载流殇
    链接:https://zhuanlan.zhihu.com/p/35219750
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
    Pythonic,简言之就是以Python这门语言独特的方式写出既简洁又优美的代码!笔者精心整理了许多实用的Python tricks,想要提高效率、写出高质量的Python代码的话此文必看。 注:请将Python更新到3.6版,方能完美运行本文的所有代码。字符串格式化字符串在字符串前加f,就可以在里面用大括号嵌入变量了(可以代替format函数)>>> a = 5
    >>> b = 10
    >>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
    'Five plus ten is 15 and not 30.'
    字符串拼接>>> text = ['I', ' Love ', 'Python!']
    >>> print(''.join(text))
    I Love Python!
    字符串的contains>>> 'ov' in 'love'
    True
    反转元素>>> 'Love'[::-1]
    'evoL'
    >>> for e in reversed([1,3,5]): print(e)
    5 3 1
    去除非法字符串保存文件时,我们必须去除一些非法字符串,此处利用any函数实现def rectify(name):
        if any(symbol in name for symbol in ['?', '<', '>', '|', '*', '"', ":"]):
            name = ''.join([c for c in name if c not in ['?', '<', '>', '|', '*', '"', ":"]])
        return name
    HTML转义>>> import html
    >>> html.unescape('&lt')
    '<'
    >>> html.escape('<')
    '&lt;'
    函数可变参数*args:任意数量的位置参数,可被打包成元组。**kwargs:任意数量的关键词参数,可被打包成字典。打包def foo(*args, **kwargs):
         print(f"args: {args}")
         print(f"kwargs: {kwargs}")
    
    >>> foo(1,2,3,4, a=1,b=2,c=3)
    args: (1, 2, 3, 4)
    kwargs: {'a': 1, 'b': 2, 'c': 3}
    解包def foo(x, y):
        print(x, y)
    
    alist = [1, 2]
    adict = {'x': 1, 'y': 2}
    
    >>> foo(*alist)
    1, 2
    >>> foo(**adict)
    1, 2
    装饰器装饰器的主要用途:打印日志、检测性能、数据库事务、URL路由它本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。想理解装饰器,就得知道以下两点:1. 函数皆对象2. 闭包特性(内函数能捕捉到外函数的环境变量)简单的日志函数from datetime import datetime
    import functools
    def log(f):
        @functools.wraps(f)
        def wr(*args, **kwargs):
                print(f'call {f.__name__}() at {datetime.now()}')
                return f(*args, **kwargs)
        return wr
    
    @log
    def square(x):
        return x ** 2
    
    >>> square(2)
    call square() at 2018-01-24 11:01:19.547516
    4
    注意到为了让@deco自适应任何参数定义的函数,我们将可变参数args, *kwargs作为了wr的参数@functools.wraps(f)为了防止wr的函数属性覆盖掉原函数的属性,我们必须利用@functools.wraps(f)来把原函数的所有属性复制到新函数里# 不加@functools.wraps(f)的情况下
    >>> square.__name__
    'wr'
    # 加了@functools.wraps(f)的情况下
    >>> square.__name__
    'square'
    如果想给装饰器传递参数,那么你必须利用闭包特性再嵌套一层函数,不过这并不常用。函数性能检测def perf(f):
        @functools.wraps(f)
        def wr(*args, **kwargs):
                start = time.time()
                r = f(*args, **kwargs)
                end = time.time()
                print(f'call {f.__name__}() in {end - start}')
                return r
        return wr
    
    @perf
    def test(x):
        time.sleep(2)
        return x
    
    >>> test(5)
    call test() in 2.0007083415985107
    5
    数据库的cursordef link_mysql(fun):
        def wr(*args, **kwargs):
            with pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=dbname, charset=charset) as cur:
                fun(cur, *args, **kwargs)
        return wr
    
    @link_mysql
    def insert_data(cur, ...):
        # execute your sql here.
    上下文管理器应用文件操作(超常用)、进程互斥锁和支持上下文的其他对象目的是为了代替try语句和简化语法以文件操作为例:利用它,文件会自动打开和关闭with open('/path/to/file', 'r') as f:
        handle_f
    上下文语句支持嵌套(nested)例如将a文件的源数据写入b文件里:with open('a.txt') as i, open('b.txt') as o:
        o.write(i.read())
    实质通过上下文管理协议__enter__和__exit__来实现Python有个库contextlib利用生成器简化了这种实现,以下是大体框架from contextlib import contextmanager
    
    @contextmanager
    def make_context() :
        # enter
        try:
            yield <value>
        except Exception as e:
            # handle_err
        finally:
            # exit
    
    with make_context() as <value>:
        # handle_value
    以下是with语句操作文件的实质由于自定义,函数名用my_open,但功能和open几乎一样@contextmanager
    def my_open(filename, mode):
        f = open(filename, mode)
        try:
            yield f
        except Exception as e:
            raise e
        finally:
            f.close()
    
    with my_open('/path/to/file', 'r') as f:
        handle_f
    偏函数partial()用于把一个函数的某些参数给固定住(也就是设置默认值),并返回一个新的函数。def int2(x, base=2):
        return int(x, base)
    相当于:import functools
    int2 = functools.partial(int, base=2)
    数据结构元组元组是一个immutable对象,有以下重要性:- 性能优化- 线程安全- 可以作为dict的key(hashable)- 拆包特性元组拆包a, b = b, a两个数字交换的原理就是它。以下是利用它来获取文件名及其扩展名>>> import os
    >>> filename, ext = os.path.splitext('patch.exe')
    >>> filename
    'patch'
    >>> ext
    'exe'
    更多的解包方式(_代表舍弃,*代表可变长元组)>>> t = (1, 2, 3, 4)
    >>> first, *middle, last = t
    >>> middle
    [2, 3]
    >>> _, *rest = t
    >>> rest
    [2, 3, 4]
    列表切片如果想要获取列表的多个元素,就得用到切片list[start:stop:step]
    你甚至可以给切片命名,增强复用性和可读性:s = slice(start,stop,step)
    list[s]
    切片的原理是序列协议class Seq:
        def __getitem__(self, index):
                return index
    
    >>> s = Seq()
    >>> s[1:5:2]
    slice(1, 5, 2)
    以上实现的是不可变序列协议,如果可变的话还要添加__setitem__()如果在运行时添加协议的话也行,这叫猴子补丁>>> def set_item(self, key, value):
            self[key] = value
    >>> classname.__setitem__ = set_item
    列表推导式这是Python最强大的几个特征之一。格式也很简单,其中if条件可以省略,for循环可以有多个[i for i in iterable if condition]
    10-20所有偶数的平方:[i*i for i in range(10, 21) if i % 2 == 0 ]
    一行实现快排def qsort(arr):
        return arr if len(arr) <= 1 else qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])
    索引迭代enumerate()可以把一个list变成索引-元素对。for i, value in enumerate(['A', 'B', 'C']):
        print(i, value) 
    0 A 1 B 2 C
    zipzip()可以将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,并返回一个迭代器,常用于同时遍历两个可迭代对象。>>> li1 = ['Python' ,'JavaScript', 'Java']
    >>> li2 = [1, 2, 3]
    >>> nl = zip(li1, li2)
    <zip object at memory>
    >>> list(nl)
    [('Python', 1), ('JavaScript', 2), ('Java', 3)]
    配合dict可以生成字典>>> l1 = ['A', 'B', 'C']
    >>> l2 = [1, 2, 3]
    >>> dict(zip(l1, l2))
    {'A': 1, 'B': 2, 'C': 3}
    append和extend>>> x = [1, 2, 3]
    >>> x.extend([4, 5])
    >>> x
    [1, 2, 3, 4, 5]
    >>> x.append([6, 7])
    >>> x
    [1, 2, 3, 4, 5, [6, 7]]
    集合运算首先将要比较的两个list转换为set,再转回list就行了>>> l1 = [1, 2, 3, 4]
    >>> l2 = [2, 3, 5, 7]
    >>> list(set(l1) & set(l2))
    [2, 3]
    >>> list(set(l1) | set(l2))
    [1, 2, 3, 4, 5, 7]
    >>> list(set(l1) ^ set(l2))
    [1, 4, 5, 7]
    字典本质是键值对哈希表get用来获取某个键的值,不存在的话就用设置的default(默认为None)>>> d = dict(a=1, b=2)
    >>> d.get('a')
    1
    >>> d.get('c')
    >>> d.get('d', 2)
    2
    合并>>> d1 = {'a':1, 'b':2}
    >>> d2 = {'c':3, 'd':4}
    >>> nd = {**d1, **d2}
    >>> nd
    {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    类似的,列表也可以这样合并>>> l1 = [1, 2]
    >>> l2 = [3, 4]
    >>> l3 = [*l1, *l2]
    >>> l3
    [1, 2, 3, 4]
    键值对反转>>> kv = {'a': 1, 'b':2 , 'c': 3}
    >>> vk = zip(kv.values(), kv.keys())
    >>> dict(vk)
    {1: 'a', 2: 'b', 3: 'c'}
    >>> min(vk)
    (1, 'a')
    >>> sorted(vk)
    [(1, 'a'), (2, 'b'), (3, 'c')]
    键值排序>>> rows = [{k1: v1, k2: v2 ...}, ...]
    >>> from operator import itemgetter
    # 根据k1排序
    >>> sorted(rows, key=itemgetter(k1))
    # 类似的,对于class的对象可以用attrgetter进行排序
    集合运算>>> a = {'a': 1, 'b': 2, 'c': 3}
    >>> b = {'x': 1, 'b': 2, 'c': 4}
    >>> a.keys() & b.keys()
    {'b', 'c'}
    >>> a.keys() - b.keys()
    {'a'}
    >>> a.items() & b.items()
    {('b', 2)}
    其他数据结构具名元组常用于构建简单的类>>> from collections import namedtuple
    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> p = Point(x=11, y=22)
    >>> p
    Point(x=11, y=22)
    >>> p.x + p.y
    33
    >>> coord = (33, 44)
    >>> q = Point(*coord)
    >>> q
    Point(x=33, y=44)
    默认值字典常用于统计数目>>> from collections import defaultdict
    >>> words = ('python', 'java', 'ruby', 'python', 'C', 'java', 'C++', 'C')
    >>> counts = defaultdict(int)
    >>> for word in words:
    ...    counts[word] += 1
    >>> counts
    defaultdict(<class 'int'>, {'python': 2, 'java': 2, 'ruby': 1, 'C': 2, 'C++': 1})
    双向队列>>> from collections import deque
    >>> q = deque(["Eric", "John", "Michael"])
    >>> q.append("Terry")
    >>> q
    deque(['Eric', 'John', 'Michael', 'Terry'])
    >>> q.popleft()
    Eric'
    >>> q.pop()
    'Terry'
    >>> q
    deque(['John', 'Michael'])
    计数器>>> from collections import Counter
    >>> c = Counter('hello world')
    >>> c
    Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1})
    >>> c.most_common(2)
    [('l', 3), ('o', 2)]
    堆>>> import heapq
    >>> a = [1, 2, 3]
    >>> b = [4, 5, 6]
    >>> c = list(heapq.merge(a, b))
    >>> c
    [1, 2, 3, 4, 5, 6]
    >>> heapq.nlargest(3, c)
    [6, 5, 4]
    >>> heapq.nsmallest(3, c)
    [1, 2, 3]
    OOP只读属性可以通过在变量名前加__来使其变成私有变量,外部无法直接访问,但可以通过类定义的方法来访问。class Person(object):
        def __init__(self, name):
                self.__name = name
    
        def get_name(self):
                return self.__name
    
        def set_name(self, name):
                self.__name = name
    
    >>> p = Person('alphardex')
    >>> p.name
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Person' object has no attribute 'name'
    >>> p.get_name()
    'alphardex'
    >>> p.set_name('wang')
    >>> p.get_name()
    'wang'
    @property肯定有的人不习惯通过方法来访问私有变量,那么如何用属性来访问私有变量呢?这时就要用到@property了,它可以把一个方法变成属性调用class Person(object):
        def __init__(self, name):
                self.__name = name
    
        @property
        def name(self):
                return self.__name
    
        @name.setter
        def name(self, value):
                self.__name = value
    
    >>> p = Person('alphardex')
    >>> p.name
    'alphardex'
    >>> p.name = 'wang'
    >>> p.name
    'wang'
    slots当我们定义了一个class并用其创建了一个实例后,可以动态地给其绑定属性,如果要限制这一点,可以利用__slots__class Person(object):
        __slots__ = ('name', 'age')
    
    >>> p = Person('wang')
    >>> p.name = 'wang'
    >>> p.age = 21
    >>> p.skill = 'Python'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Person' object has no attribute 'skill'
    魔术方法魔术方法可以用来定制类的功能。比如__repr__用来调试时打印类的字符串class Person(object):
        def __init__(self, name, age):
                self.name = name
                self.age = age
        def __repr__(self):
                return f'<Person {self.name} age: {self.age}>'
    
    >>> p = Person('alphardex', 21)
    >>> p
    <Person alphardex age: 21>
    想了解更多魔术方法请参见官方文档元类type俗话说道生一,一生二,二生三,三生万物。在Python里可以这么说:type生元类,元类生类,类生实例。用一个数字变量的创建来说明这一点吧>>> age = 21
    >>> age.__class__
    <class 'int'>
    >>> age.__class__.__class__
    <class 'type'>
    age可以看作为int类的实例,而int类又可以看做type类的实例。也就是说,type创建了int类,实际上诸如str和bool等类也是由type创建的。>>> help(type)
    Help on class type in module builtins:
    
    class type(object)
     |  type(object_or_name, bases, dict)
     |  type(object) -> the object's type
     |  type(name, bases, dict) -> a new type
    
    def say_hello(self, name='world'):
        print(f'Hello, {name}')
    
    >>> Hello = type('Hello', (object,), dict(hello=say_hello))
    >>> h = Hello()
    >>> type(Hello)
    <class 'type'>
    >>> type(h)
    <class '__main__.Hello'>
    通过用help查看type,可以发现它确实能动态地创建类:第一个参数是类名name,第二个参数是基类bases,第三个参数是dict,里面包含着类的所有方法。实际上,type是Python的一个内置元类。自定义元类当然,你也可以利用type来定义自己的元类。class JSArrayMeta(type):
        def __new__(cls, name, bases, attrs):
                attrs['push'] = lambda self, value: self.append(value)
                attrs['shift'] = lambda self: self.pop(0)
                attrs['includes'] = lambda self, value: value in self
                return type.__new__(cls, name, bases, attrs)
    
    class JSList(list, metaclass=JSArrayMeta):
        def __init__(self, value):
                self.extend(value)
    
    >>> l = JSList([1, 2, 3])
    >>> l
    [1, 2, 3]
    >>> l.push('a')
    >>> l
    [1, 2, 3, 'a']
    >>> l.shift()
    1
    >>> l
    [2, 3, 'a']
    >>> l.includes(3)
    True
    我们首先定制了一个元类,叫JSArrayMetaclass(没错就是JS里的数组XD)注意元类的命名规则:结尾一定要有Meta作为识别__new__方法用来创建JSList类,它接受4个参数JSList继承了list类,同时获得了元类的所有方法其他加载内置模块利用-m参数,我们可以直接加载Python的模块# 搭建http服务器
    $ python -m http.server
    # 创建虚拟环境
    $ python -m venv <name>
    # 性能测试
    $ python -m cProfile <file.py>
    # 查看JSON
    $ cat <file.json> | python -m json.tool
    数据序列化import pickle
    data = ... # Some Python object
    # 存储
    with open(f'{file}.pickle', 'wb') as f:
        pickle.dump(data, f)
    # 读取
    with open(f'{file}.pickle', 'rb') as f:
        data = pickle.load(f)
    数据分析利用pandas模块可以对数据进行分析$ pip install pandas
    >>> import pandas as pd
    >>> data = pd.read_csv(...)
    # 数据查看
    >>> data.columns              # 查看数据结构
    >>> data.describe()           # 简要数据分析
    >>> data.sort_values(by=...)  # 对数据排序
    # 数据选取
    >>> data.head()               # 查看前五条数据
    >>> data.iloc[n]              # 选择位置为n的数据,支持切片
    >>> data[data.A > 0]          # 选择A栏大于0的数据
    >>> data[data.B.isin([...])]  # 利用in过滤数据
    >>> data[~data.B.isin([...])] # 上一句的取反,相当于not in
    # 缺失值处理
    >>> pd.isna(data)             # 获取缺失值的布尔标记
    >>> data.dropna(how='any')    # 去除所有含有缺失值的栏
    >>> data.fillna(value=5)      # 填充所有含有缺失值的栏
    # 数据保存(可以相互转换格式,支持excel、csv和json)
    >>> data.to_json(...)
    作者:半载流殇
    链接:https://zhuanlan.zhihu.com/p/35219750
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    Pythonic,简言之就是以Python这门语言独特的方式写出既简洁又优美的代码!笔者精心整理了许多实用的Python tricks,想要提高效率、写出高质量的Python代码的话此文必看。

    注:请将Python更新到3.6版,方能完美运行本文的所有代码。

    字符串

    格式化字符串

    在字符串前加f,就可以在里面用大括号嵌入变量了(可以代替format函数)

    >>> a = 5
    >>> b = 10
    >>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
    'Five plus ten is 15 and not 30.'
    

    字符串拼接

    >>> text = ['I', ' Love ', 'Python!']
    >>> print(''.join(text))
    I Love Python!
    

    字符串的contains

    >>> 'ov' in 'love'
    True
    

    反转元素

    >>> 'Love'[::-1]
    'evoL'
    >>> for e in reversed([1,3,5]): print(e)
    5 3 1
    

    去除非法字符串

    保存文件时,我们必须去除一些非法字符串,此处利用any函数实现

    def rectify(name):
        if any(symbol in name for symbol in ['?', '<', '>', '|', '*', '"', ":"]):
            name = ''.join([c for c in name if c not in ['?', '<', '>', '|', '*', '"', ":"]])
        return name
    

    HTML转义

    >>> import html
    >>> html.unescape('&lt')
    '<'
    >>> html.escape('<')
    '&lt;'
    

    函数

    可变参数

    *args:任意数量的位置参数,可被打包成元组。
    **kwargs:任意数量的关键词参数,可被打包成字典。

    打包

    def foo(*args, **kwargs):
         print(f"args: {args}")
         print(f"kwargs: {kwargs}")
    
    >>> foo(1,2,3,4, a=1,b=2,c=3)
    args: (1, 2, 3, 4)
    kwargs: {'a': 1, 'b': 2, 'c': 3}
    

    解包

    def foo(x, y):
        print(x, y)
    
    alist = [1, 2]
    adict = {'x': 1, 'y': 2}
    
    >>> foo(*alist)
    1, 2
    >>> foo(**adict)
    1, 2
    

    装饰器

    装饰器的主要用途:打印日志、检测性能、数据库事务、URL路由
    它本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。
    想理解装饰器,就得知道以下两点:
    1. 函数皆对象
    2. 闭包特性(内函数能捕捉到外函数的环境变量)

    简单的日志函数

    from datetime import datetime
    import functools
    def log(f):
        @functools.wraps(f)
        def wr(*args, **kwargs):
                print(f'call {f.__name__}() at {datetime.now()}')
                return f(*args, **kwargs)
        return wr
    
    @log
    def square(x):
        return x ** 2
    
    >>> square(2)
    call square() at 2018-01-24 11:01:19.547516
    4
    

    注意到为了让@deco自适应任何参数定义的函数,我们将可变参数args, *kwargs作为了wr的参数

    @functools.wraps(f)

    为了防止wr的函数属性覆盖掉原函数的属性,我们必须利用@functools.wraps(f)来把原函数的所有属性复制到新函数里

    # 不加@functools.wraps(f)的情况下
    >>> square.__name__
    'wr'
    # 加了@functools.wraps(f)的情况下
    >>> square.__name__
    'square'
    

    如果想给装饰器传递参数,那么你必须利用闭包特性再嵌套一层函数,不过这并不常用。

    函数性能检测

    def perf(f):
        @functools.wraps(f)
        def wr(*args, **kwargs):
                start = time.time()
                r = f(*args, **kwargs)
                end = time.time()
                print(f'call {f.__name__}() in {end - start}')
                return r
        return wr
    
    @perf
    def test(x):
        time.sleep(2)
        return x
    
    >>> test(5)
    call test() in 2.0007083415985107
    5
    

    数据库的cursor

    def link_mysql(fun):
        def wr(*args, **kwargs):
            with pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=dbname, charset=charset) as cur:
                fun(cur, *args, **kwargs)
        return wr
    
    @link_mysql
    def insert_data(cur, ...):
        # execute your sql here.
    

    上下文管理器

    应用

    文件操作(超常用)、进程互斥锁和支持上下文的其他对象
    目的是为了代替try语句和简化语法
    以文件操作为例:利用它,文件会自动打开和关闭

    with open('/path/to/file', 'r') as f:
        handle_f
    

    上下文语句支持嵌套(nested)
    例如将a文件的源数据写入b文件里:

    with open('a.txt') as i, open('b.txt') as o:
        o.write(i.read())
    

    实质

    通过上下文管理协议__enter__和__exit__来实现
    Python有个库contextlib利用生成器简化了这种实现,以下是大体框架

    from contextlib import contextmanager
    
    @contextmanager
    def make_context() :
        # enter
        try:
            yield <value>
        except Exception as e:
            # handle_err
        finally:
            # exit
    
    with make_context() as <value>:
        # handle_value
    

    以下是with语句操作文件的实质
    由于自定义,函数名用my_open,但功能和open几乎一样

    @contextmanager
    def my_open(filename, mode):
        f = open(filename, mode)
        try:
            yield f
        except Exception as e:
            raise e
        finally:
            f.close()
    
    with my_open('/path/to/file', 'r') as f:
        handle_f
    

    偏函数

    partial()用于把一个函数的某些参数给固定住(也就是设置默认值),并返回一个新的函数。

    def int2(x, base=2):
        return int(x, base)
    

    相当于:

    import functools
    int2 = functools.partial(int, base=2)
    

    数据结构

    元组

    元组是一个immutable对象,有以下重要性:
    - 性能优化
    - 线程安全
    - 可以作为dict的key(hashable)
    - 拆包特性

    元组拆包

    a, b = b, a
    两个数字交换的原理就是它。
    以下是利用它来获取文件名及其扩展名

    >>> import os
    >>> filename, ext = os.path.splitext('patch.exe')
    >>> filename
    'patch'
    >>> ext
    'exe'
    

    更多的解包方式(_代表舍弃,*代表可变长元组)

    >>> t = (1, 2, 3, 4)
    >>> first, *middle, last = t
    >>> middle
    [2, 3]
    >>> _, *rest = t
    >>> rest
    [2, 3, 4]
    

    列表

    切片

    如果想要获取列表的多个元素,就得用到切片

    list[start:stop:step]
    

    你甚至可以给切片命名,增强复用性和可读性:

    s = slice(start,stop,step)
    list[s]
    

    切片的原理是序列协议

    class Seq:
        def __getitem__(self, index):
                return index
    
    >>> s = Seq()
    >>> s[1:5:2]
    slice(1, 5, 2)
    

    以上实现的是不可变序列协议,如果可变的话还要添加__setitem__()
    如果在运行时添加协议的话也行,这叫猴子补丁

    >>> def set_item(self, key, value):
            self[key] = value
    >>> classname.__setitem__ = set_item
    

    列表推导式

    这是Python最强大的几个特征之一。
    格式也很简单,其中if条件可以省略,for循环可以有多个

    [i for i in iterable if condition]
    

    10-20所有偶数的平方:

    [i*i for i in range(10, 21) if i % 2 == 0 ]
    

    一行实现快排

    def qsort(arr):
        return arr if len(arr) <= 1 else qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])
    

    索引迭代

    enumerate()可以把一个list变成索引-元素对。

    for i, value in enumerate(['A', 'B', 'C']):
        print(i, value) 
    0 A 1 B 2 C
    

    zip

    zip()可以将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,并返回一个迭代器,常用于同时遍历两个可迭代对象。

    >>> li1 = ['Python' ,'JavaScript', 'Java']
    >>> li2 = [1, 2, 3]
    >>> nl = zip(li1, li2)
    <zip object at memory>
    >>> list(nl)
    [('Python', 1), ('JavaScript', 2), ('Java', 3)]
    

    配合dict可以生成字典

    >>> l1 = ['A', 'B', 'C']
    >>> l2 = [1, 2, 3]
    >>> dict(zip(l1, l2))
    {'A': 1, 'B': 2, 'C': 3}
    

    append和extend

    >>> x = [1, 2, 3]
    >>> x.extend([4, 5])
    >>> x
    [1, 2, 3, 4, 5]
    >>> x.append([6, 7])
    >>> x
    [1, 2, 3, 4, 5, [6, 7]]
    

    集合运算

    首先将要比较的两个list转换为set,再转回list就行了

    >>> l1 = [1, 2, 3, 4]
    >>> l2 = [2, 3, 5, 7]
    >>> list(set(l1) & set(l2))
    [2, 3]
    >>> list(set(l1) | set(l2))
    [1, 2, 3, 4, 5, 7]
    >>> list(set(l1) ^ set(l2))
    [1, 4, 5, 7]
    

    字典

    本质是键值对哈希表

    get

    用来获取某个键的值,不存在的话就用设置的default(默认为None)

    >>> d = dict(a=1, b=2)
    >>> d.get('a')
    1
    >>> d.get('c')
    >>> d.get('d', 2)
    2
    

    合并

    >>> d1 = {'a':1, 'b':2}
    >>> d2 = {'c':3, 'd':4}
    >>> nd = {**d1, **d2}
    >>> nd
    {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    

    类似的,列表也可以这样合并

    >>> l1 = [1, 2]
    >>> l2 = [3, 4]
    >>> l3 = [*l1, *l2]
    >>> l3
    [1, 2, 3, 4]
    

    键值对反转

    >>> kv = {'a': 1, 'b':2 , 'c': 3}
    >>> vk = zip(kv.values(), kv.keys())
    >>> dict(vk)
    {1: 'a', 2: 'b', 3: 'c'}
    >>> min(vk)
    (1, 'a')
    >>> sorted(vk)
    [(1, 'a'), (2, 'b'), (3, 'c')]
    

    键值排序

    >>> rows = [{k1: v1, k2: v2 ...}, ...]
    >>> from operator import itemgetter
    # 根据k1排序
    >>> sorted(rows, key=itemgetter(k1))
    # 类似的,对于class的对象可以用attrgetter进行排序
    

    集合运算

    >>> a = {'a': 1, 'b': 2, 'c': 3}
    >>> b = {'x': 1, 'b': 2, 'c': 4}
    >>> a.keys() & b.keys()
    {'b', 'c'}
    >>> a.keys() - b.keys()
    {'a'}
    >>> a.items() & b.items()
    {('b', 2)}
    

    其他数据结构

    具名元组

    常用于构建简单的类

    >>> from collections import namedtuple
    >>> Point = namedtuple('Point', ['x', 'y'])
    >>> p = Point(x=11, y=22)
    >>> p
    Point(x=11, y=22)
    >>> p.x + p.y
    33
    >>> coord = (33, 44)
    >>> q = Point(*coord)
    >>> q
    Point(x=33, y=44)
    

    默认值字典

    常用于统计数目

    >>> from collections import defaultdict
    >>> words = ('python', 'java', 'ruby', 'python', 'C', 'java', 'C++', 'C')
    >>> counts = defaultdict(int)
    >>> for word in words:
    ...    counts[word] += 1
    >>> counts
    defaultdict(<class 'int'>, {'python': 2, 'java': 2, 'ruby': 1, 'C': 2, 'C++': 1})
    

    双向队列

    >>> from collections import deque
    >>> q = deque(["Eric", "John", "Michael"])
    >>> q.append("Terry")
    >>> q
    deque(['Eric', 'John', 'Michael', 'Terry'])
    >>> q.popleft()
    Eric'
    >>> q.pop()
    'Terry'
    >>> q
    deque(['John', 'Michael'])
    

    计数器

    >>> from collections import Counter
    >>> c = Counter('hello world')
    >>> c
    Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1})
    >>> c.most_common(2)
    [('l', 3), ('o', 2)]
    

    >>> import heapq
    >>> a = [1, 2, 3]
    >>> b = [4, 5, 6]
    >>> c = list(heapq.merge(a, b))
    >>> c
    [1, 2, 3, 4, 5, 6]
    >>> heapq.nlargest(3, c)
    [6, 5, 4]
    >>> heapq.nsmallest(3, c)
    [1, 2, 3]
    

    OOP

    只读属性

    可以通过在变量名前加__来使其变成私有变量,外部无法直接访问,但可以通过类定义的方法来访问。

    class Person(object):
        def __init__(self, name):
                self.__name = name
    
        def get_name(self):
                return self.__name
    
        def set_name(self, name):
                self.__name = name
    
    >>> p = Person('alphardex')
    >>> p.name
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Person' object has no attribute 'name'
    >>> p.get_name()
    'alphardex'
    >>> p.set_name('wang')
    >>> p.get_name()
    'wang'
    

    @property

    肯定有的人不习惯通过方法来访问私有变量,那么如何用属性来访问私有变量呢?这时就要用到@property了,它可以把一个方法变成属性调用

    class Person(object):
        def __init__(self, name):
                self.__name = name
    
        @property
        def name(self):
                return self.__name
    
        @name.setter
        def name(self, value):
                self.__name = value
    
    >>> p = Person('alphardex')
    >>> p.name
    'alphardex'
    >>> p.name = 'wang'
    >>> p.name
    'wang'
    

    slots

    当我们定义了一个class并用其创建了一个实例后,可以动态地给其绑定属性,如果要限制这一点,可以利用__slots__

    class Person(object):
        __slots__ = ('name', 'age')
    
    >>> p = Person('wang')
    >>> p.name = 'wang'
    >>> p.age = 21
    >>> p.skill = 'Python'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Person' object has no attribute 'skill'
    

    魔术方法

    魔术方法可以用来定制类的功能。
    比如__repr__用来调试时打印类的字符串

    class Person(object):
        def __init__(self, name, age):
                self.name = name
                self.age = age
        def __repr__(self):
                return f'<Person {self.name} age: {self.age}>'
    
    >>> p = Person('alphardex', 21)
    >>> p
    <Person alphardex age: 21>
    

    想了解更多魔术方法请参见官方文档

    元类

    type

    俗话说道生一,一生二,二生三,三生万物。
    在Python里可以这么说:type生元类,元类生类,类生实例。
    用一个数字变量的创建来说明这一点吧

    >>> age = 21
    >>> age.__class__
    <class 'int'>
    >>> age.__class__.__class__
    <class 'type'>
    

    age可以看作为int类的实例,而int类又可以看做type类的实例。
    也就是说,type创建了int类,实际上诸如str和bool等类也是由type创建的。

    >>> help(type)
    Help on class type in module builtins:
    
    class type(object)
     |  type(object_or_name, bases, dict)
     |  type(object) -> the object's type
     |  type(name, bases, dict) -> a new type
    
    def say_hello(self, name='world'):
        print(f'Hello, {name}')
    
    >>> Hello = type('Hello', (object,), dict(hello=say_hello))
    >>> h = Hello()
    >>> type(Hello)
    <class 'type'>
    >>> type(h)
    <class '__main__.Hello'>
    

    通过用help查看type,可以发现它确实能动态地创建类:第一个参数是类名name,第二个参数是基类bases,第三个参数是dict,里面包含着类的所有方法。
    实际上,type是Python的一个内置元类。

    自定义元类

    当然,你也可以利用type来定义自己的元类。

    class JSArrayMeta(type):
        def __new__(cls, name, bases, attrs):
                attrs['push'] = lambda self, value: self.append(value)
                attrs['shift'] = lambda self: self.pop(0)
                attrs['includes'] = lambda self, value: value in self
                return type.__new__(cls, name, bases, attrs)
    
    class JSList(list, metaclass=JSArrayMeta):
        def __init__(self, value):
                self.extend(value)
    
    >>> l = JSList([1, 2, 3])
    >>> l
    [1, 2, 3]
    >>> l.push('a')
    >>> l
    [1, 2, 3, 'a']
    >>> l.shift()
    1
    >>> l
    [2, 3, 'a']
    >>> l.includes(3)
    True
    
    • 我们首先定制了一个元类,叫JSArrayMetaclass(没错就是JS里的数组XD)
    • 注意元类的命名规则:结尾一定要有Meta作为识别
    • __new__方法用来创建JSList类,它接受4个参数
    • JSList继承了list类,同时获得了元类的所有方法

    其他

    加载内置模块

    利用-m参数,我们可以直接加载Python的模块

    # 搭建http服务器
    $ python -m http.server
    # 创建虚拟环境
    $ python -m venv <name>
    # 性能测试
    $ python -m cProfile <file.py>
    # 查看JSON
    $ cat <file.json> | python -m json.tool
    

    数据序列化

    import pickle
    data = ... # Some Python object
    # 存储
    with open(f'{file}.pickle', 'wb') as f:
        pickle.dump(data, f)
    # 读取
    with open(f'{file}.pickle', 'rb') as f:
        data = pickle.load(f)
    

    数据分析

    利用pandas模块可以对数据进行分析

    $ pip install pandas
    >>> import pandas as pd
    >>> data = pd.read_csv(...)
    # 数据查看
    >>> data.columns              # 查看数据结构
    >>> data.describe()           # 简要数据分析
    >>> data.sort_values(by=...)  # 对数据排序
    # 数据选取
    >>> data.head()               # 查看前五条数据
    >>> data.iloc[n]              # 选择位置为n的数据,支持切片
    >>> data[data.A > 0]          # 选择A栏大于0的数据
    >>> data[data.B.isin([...])]  # 利用in过滤数据
    >>> data[~data.B.isin([...])] # 上一句的取反,相当于not in
    # 缺失值处理
    >>> pd.isna(data)             # 获取缺失值的布尔标记
    >>> data.dropna(how='any')    # 去除所有含有缺失值的栏
    >>> data.fillna(value=5)      # 填充所有含有缺失值的栏
    # 数据保存(可以相互转换格式,支持excel、csv和json)
    >>> data.to_json(...)
  • 相关阅读:
    第 02 组 每周小结 (2/3)
    第02组 每周小结(1/3)
    第02组 beta冲刺总结
    第02组 beta冲刺(5/5)
    第02组 beta冲刺(4/5)
    第02组 beta冲刺(3/5)
    第02组 beta冲刺(2/5)
    第02组beta冲刺(1)
    将博客搬至CSDN
    制作鼠标放在图片上,一闪而过水波的效果
  • 原文地址:https://www.cnblogs.com/yezefei/p/8709039.html
Copyright © 2020-2023  润新知