博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python黑魔法—学习笔记
阅读量:225 次
发布时间:2019-02-28

本文共 16843 字,大约阅读时间需要 56 分钟。

王炳明的的学习笔记。

小整数池

在这里插入图片描述

在同一行里,同时给两个变量赋同一值时,解释器知道这个对象已经生成,那么它就会引用大同一个对象。如果分成两行的话,解释器并不直达这个对象已经存在了,就会重新申请内存存放这个对象。

intern机制

在这里插入图片描述

site-packages和dist-packages

dist-packages是debian系的Linux系统(如Ubuntu)才有的目录,当使用apt去安装的Python包会使用dist-packages,而使用pip或者easy_install安装的包才会安装在site-packages下。

argument和parameter

  • parameter:形参(formal parameter),体现在函数内部,作用域是这个函数体。
  • argument:实参(actual parameter),调用函数实际传递的参数。

/usr/bin/python 和 /usr/bin/env python

  • 脚本或者项目的入口文件里的第一行 # ! / u s r / b i n / p y t h o n \#!/usr/bin/python #!/usr/bin/python,是执行Python进入console模式里的Python。

    在这里插入图片描述

  • 执行 e n v p y t h o n env python envpython时,会去 e n v ∣ g r e p P A T H env | grep PATH envgrepPATH的路径里依次查找名为Python的可执行文件。找到一个就执行。

    在这里插入图片描述

空字典生成{}方法比dict()方法运行速度快

return和try…finally

在这里插入图片描述

IDE环境和CMD环境下运行结果不相同

时有时无的切片异常

在这里插入图片描述

查看包搜索路径的方法

在这里插入图片描述

安装包方法

python3.6 -m pip install xxx

连接列表的方法

  • 直接相加

    在这里插入图片描述

  • itertools方法

    itertools内置模块专门用于操作可迭代对象。使用itertools.chain()函数先将可迭代对象串联起来,组成一个更大的可迭代对象,然后再利用list将其转化为列表。
    在这里插入图片描述

  • 使用 ∗ * 解包

    ∗ * 可以解包列表,解包后再合并。
    在这里插入图片描述

  • 使用extend

    在这里插入图片描述

  • 使用列表推导式

    在这里插入图片描述

  • 使用heapq

    heapq是Python的标准模块,提供了堆排序算法的实现,该模块里面的merge方法,可以用于合并多个列表。
    在这里插入图片描述

heapq.merge得到的是一个始终有序的列表,因为它采用堆排序,效率非常高。

  • 魔法方法

    直接相加实际是作用在KaTeX parse error: Expected group after '_' at position 1: _̲_add__魔法上。
    在这里插入图片描述
    在这里插入图片描述

  • yield from方法

    在这里插入图片描述

合并字典的方法

  • 原地更新

    字典对象内置方法update,用于把另一个字典更新到自己身上。
    在这里插入图片描述
    在这里插入图片描述

  • 先解包再合并

    在这里插入图片描述

  • 借助itertools

    在这里插入图片描述

  • 借助ChainMap

    在这里插入图片描述

使用ChainMap时,当字典间有重复的键值时,只会取第一个值,排在后面的键值并不会更新掉前面的。

  • 使用dict.items()合并

    在这里插入图片描述
    在这里插入图片描述

  • 字典解析式

    在这里插入图片描述

判断是否包含子串的方法

  • 使用in和not in

  • 使用find方法

    使用 字符串对象的find方法,如果有找到子串,就可以返回指定子串在字符串中的出现位置。如果没有找到,就返回-1。

在这里插入图片描述

  • 使用index方法

    字符串对象哟一个index方法,可以返回指定子串在该字符串中第一次出现的索引,如果没有找到会抛出异常,因此使用时需要注意捕获。
    在这里插入图片描述

  • 使用count方法

    只要判断结果大于0就说明子串存在于字符串中。
    在这里插入图片描述

  • 通过魔法方法

    在这里插入图片描述

  • 借助operator

    operator模块是Python内置的操作符函数接口,它定义了一些算术和比较内置操作的函数。operator模块是用c实现的,所以执行速度比Python代码快。在operator中有一个方法contains,可以很方便的判断子串是否在字符串中。
    在这里插入图片描述

  • 使用正则匹配

    在这里插入图片描述

装饰器

装饰器的使用方法很固定:

  • 定义一个装饰器
  • 定义一个函数或者类
  • 把装饰器放在该函数上

装饰器并不是编码必须的,它的出现,使代码:

  • 更加优雅,代码结构更加清晰
  • 将实现特定的功能代码封装成装饰器,提高代码复用率,增强代码可读性。
def decorator(func):    def wrapper(*args, **kw):        return func()    return wrapper@decoratordef function():    print('hello, decorator')
  • 入门:日志打印器
#这是装饰器函数,参数function是被装饰的函数def logger(func):    def wrapper(*args, **kw):        print('开始执行:{}函数:'.format(func.__name__))        #真正执行的函数        func(*args, **kw)        print('函数执行完了。')    return wrapper@loggerdef add(x, y):    print('{} + {} = {}'.format(x, y, x + y))add(20, 30)

在这里插入图片描述

  • 入门:时间计时器
import time#装饰函数def timer(func):    def wrapper(*args, **kw):        t1 = time.time()        #执行函数        func(*args, **kw)        t2 = time.time()        #计算时长        cost_time = t2 - t1        print('花费时间:{}'.format(cost_time))    return wrapper@timerdef want_sleep(sleep_time):    time.sleep(sleep_time)want_sleep(10)

在这里插入图片描述

  • 进阶:带参数的函数装饰器
def say_hello(country):    def wrapper(func):        def deco(*args, **kwargs):            if country == 'china':                print('你好!')            elif country == 'america':                print('hello.')            else:                return            #真正习性函数的地方            func(*args, **kwargs)        return deco    return wrapper#小明,中国人@say_hello('china')def xiaoming():    pass#jack, 美国人@say_hello('america')def jack():    passxiaoming()print('-------')jack()

在这里插入图片描述

  • 高阶:不带参数的类装饰器
    基于类实现的装饰器的实现,必须实现__call__和__init__两个内置函数。
    • _init_:接受被装饰函数
    • _call_:实现装饰逻辑
class logger(object):    def __init__(self, func):        self.func = func    def __call__(self, *args, **kwargs):        print('[INFO]: the function {func}() is running...'.format(func=self.func.__name__))        return self.func(*args, **kwargs)@loggerdef say(something):    print('say {}!'.format(something))say('hello')

在这里插入图片描述

  • 高阶:带参数的类装饰器
    • _init_:接收传入参数
    • _call_:接收被装饰函数,实现装饰逻辑
class logger(object):    def __init__(self, level='INFO'):        self.level = level           def __call__(self, func):        def wrapper(*args, **kwargs):            print('[{level}]: the function {func}() is running...'.format(level=self.level, func=func.__name__))            func(*args, **kwargs)        return wrapper@logger(level='WARNING')def say(something):    print('say {}!'.format(something))say('hello')

在这里插入图片描述

  • 使用偏函数与类实现装饰器
    Python 对某个对象是否能通过装饰器(@decorator)形式使用只有一个要求:decorator必须是一个可被调用(callable)的对象。
    • 函数
    • 实现了__call__函数的类
    • 偏函数
import timeimport functoolsclass DelayFunc:    def __init__(self, duration, func):        self.duration = duration        self.func = func            def __call__(self, *args, **kwargs):        print('Wait for {duration} seconds...'.format(duration=self.duration))        time.sleep(self.duration)        return self.func(*args, **kwargs)            def eager_call(self, *args, **kwargs):        print('Call without delay')        return self.func(*args, **kwargs)def delay(duration):    """    装饰器:推迟某个函数的执行    同时提供eager_call方法立即执行    """    #此处是为了避免定义额外函数    #直接使用functools.partial帮助构造DelayFunction实例    return functools.partial(DelayFunc, duration)@delay(duration=2)def add(a, b):    return a + b

在这里插入图片描述

描述符

一个实现了描述符协议的类就是一个描述符。在类里实现了__get__()、set()、delete()其中至少一个方法。实现保护属性不受修改、属性类型检查的功能,提高代码的复用率。

  • get():用于访问属性。返回属性的值,若属性不存在、不合法等都可以抛出对应的异常。
  • set():在属性分配操作中个调用。不会返回任何内容。
  • delete():控制删除操作,不会返回内容。
class Student:    def __init__(self, name, math, chinese, english):        self.name = name        self.math = math        self.chinese = chinese        self.english = english    @property    def math(self):        return self._math           @math.setter    def math(self, value):        if 0 <= value <= 100:            self._math = value        else:            raise ValueError('Valid value must be in [0, 100]')    @property    def chinese(self):        return self._chinese    @chinese.setter    def chinese(self, value):        if 0 <= value <= 100:            self._chinese = value        else:            raise ValueError('Valid value must be in [0, 100]')    @property    def english(self):        return self._english    @english.setter    def english(self, value):        if 0 <= value <= 100:            self._english = value        else:             raise ValueError('Valid value must be in [0, 100]')    def __repr__(self):        return '
'.format(self.name, self.math, self.chinese, self.english)

在这里插入图片描述

  • 描述符分类
    • 数据描述符:实现了__get__()和__set__()两种方法的描述符。
    • 非数据描述符:只实现了__get__()一种方法的描述符。

数据描述符和非数据描述符的区别在于:他们相对实例的字典的优先级不同。

#数据描述符class DataDes:    def __init__(self, default=0):        self._score = default    def __set__(self, instance, value):        self._score = value    def __get__(self, instance, owner):        print('访问数据描述符里的__get__')        return self._score        #非数据描述符class NoDataDes:    def __init__(self, default=0):        self._score = default    def __get__(self, instance, owner):        print('访问非数据描述符里的__get__')        return self._score        class Student:    math = DataDes(0)    chinese = NoDataDes(0)    def __init__(self, name, math, chinese):        self.name = name         self.math = math        self.chinese = chinese    def __getattribute__(self, item):        print('调用__getattribute__')        return super(Student, self).__getattribute__(item)    def __repr__(self):        return '
'.format(self.name, self.math, self.chinese)

在这里插入图片描述

  • 基于描述符实现property
    通过property装饰的函数,例如示例中的math会变成类Student实例的属性。对math的属性进行复制就会进入使用math.setter装饰函数的逻辑代码块。
class Student:    def __init__(self, name):        self.name = name    @property    def math(self):        return self._math    @math.setter    def math(self, value):        if 0 <= value <= 100:            self._math = value        else:            raise ValueError('Valid value must be in [0, 100]')
class TestProperty(object):    def __init__(self, fget=None, fset=None, fdel=None, doc=None):        self.fget = fget        self.fset = fset        self.fdel = fdel        self.__doc__ = doc           def __get__(self, obj, objtype=None):        print('in __get__')        if obj is None:            return self        if self.fget is None:            raise AttributeError        return self.fget(obj)    def __set__(self, obj, value):        print('in __set__')        if self.fset is None:            raise AttributeError        self.fset(obj, value)    def __delete__(self, obj):        print('in __delete__')        if self.fdel is None:            raise AttributeError        self.fdel(obj)    def getter(self, fget):        print('in getter')        return type(self)(fget, self.fset, self.fdel, self.__doc__)    def setter(self, fset):        print('in setter')        return type(self)(self.fget, fset, self.fdel, self.__doc__)    def deleter(self, fdel):        print('in deleter')        return type(self)(self.fget, self.fset, fdel, self.__doc__)class Student:    def __init__(self, name):        self.name = name    #这里改变    @TestProperty    def math(self):        return self._math    @math.setter    def math(self, value):        if 0 <= value <= 100:            self._math = value        else:            raise ValueError('Valid value must be in [0, 100]')

等价的两种写法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 静态方法–@staticmethod
    staticmethod相当于一个描述符类,而myfunc此刻变成了一个描述符。
class staticmethod:    def __init__(self, f):        self.f = f    def __get__(self, obj, objtype=None):        print('in staticmethod __get__')        return self.fclass Test:    def myfunc():        print('hello method2')    #描述符的体现    myfunc = staticmethod(myfunc) #等价写法    class Test:    @staticmethod    def myfunc():        print('hello method1')

在这里插入图片描述

在这里插入图片描述

  • 静态方法–@classmethod
class classmethod(object):    def __init__(self, f):        self.f = f            def __get__(self, instance, owner=None):        print('in classmethod __get__')        def newfunc(*args):            return self.f(owner, *args)        return newfuncclass Test:    def myfunc(cls):        print('hello classmethod')    myfunc = classmethod(myfunc)

在这里插入图片描述

  • 所有实例共享描述符
    Student类里没写构造函数:从下面的实例结果可以看出,std2共享了std1的属性值,只要其中一个实例的变量发生改变,另一个实例的变量也会跟着改变。因为此时的math,Chinese,English三个全部是类变量,导致std1和std2在访问这三个变量时,其实都是访问类变量。
class Score:    def __init__(self, default=0):        self._value = default    def __get__(self, instance, owner):        return self._value    def __set__(self, instance, value):        if 0 <= value <= 100:            self._value = value        else:            raise ValueErrorclass Student:    math = Score(0)    chinese = Score(0)    english = Score(0)    def __repr__(self):        return '
'.format(self.math, self.chinese, self.english)

在这里插入图片描述

把math,chinese,English变成实例之间相互隔离的属性,这样写:

class Score:    def __init__(self, object):        self.name = object    def __get__(self, instance, owner):        return instance.__dict__[self.name]    def __set__(self, instance, value):        if 0 <= value <= 100:            instance.__dict__[self.name] = value        else:            raise ValueErrorclass Student:    math = Score('math')    chinese = Score('chinese')    english = Score('english')    def __init__(self, math, chinese, english):        self.math = math        self.chinese = chinese        self.english = english    def __repr__(self):        return '
'.format(self.math, self.chinese, self.english)

在这里插入图片描述

上下文管理器

上下文管理器的优点:

  • 提高代码的复用率;
  • 提高代码的优雅度;
  • 提高代码的可读性;
with open('test.txt') as f:    print(f.readlines())

基本语法:

with EXPR as VAR:    BLOCK

上下文表达式:with open(‘test.txt’) as f

上下文管理器:open(‘test.txt’)
f不是上下文管理器,应该是资源对象。

在一个类里,实现了__enter__和__exit__的方法,这个类的实例就是一个上下文管理器。在编写代码的时候,可以将资源的连接或者资源获取放在__enter__中,将资源的关闭写在__exit__中。

class Resource():    def __enter__(self):        print('===connect to resource===')        return self    def __exit__(self, exc_type, exc_val, exc_tb):        print('===close resource connection===')    def operate(self):        print('===in operation===')with Resource() as res:    res.operate()

在这里插入图片描述

  • 上下文管理器隐藏处理异常
    异常可以在__exit__中捕获并决定如何处理异常,返回True表示异常已经捕获,不需要Python解释器再往外抛异常了。没有return就默认为return False。
    __exit__函数的三个参数:
    • exc_type:异常类型
    • exc_val:异常值
    • exc_tb:异常的错误栈信息
      当主逻辑代码没有报异常时,这三个参数都将为None。
class Resource():    def __enter__(self):        print('===connect to resource===')        return self    def __exit__(self, exc_type, exc_val, exc_tb):        print('===close resource connection===')        return True    def operate(self):        1/0with Resource() as res:    res.operate()

在这里插入图片描述

  • 装饰器将函数对象编程一个上下文管理器
    按照contextlib的协议来实现一个打开文件(with open)的上下文管理器。

在被装饰函数里,必须是一个生成器(带有yield),而yield之前的代码,就相当于__enter__里面的内容。yield之后的代码,就相当于__exit__里的内容。

import contextlib@contextlib.contextmanagerdef open_func(file_name):    #__enter__ method    print('open file:', file_name, 'in __enter__')    file_handler = open(file_name, 'r')    #important yield    yield file_handler    #__exit__ method    print('close file:', file_name, 'in __exit__')    file_handler.close()    returnwith open_func('test.txt') as file_in:    for line in file_in:        print(line)

在这里插入图片描述

上面的示例只能实现上下文资源管理器的一个目的(资源管理),并不能实现另一个目的(处理异常)。要处理异常可以改成下面的示例:

import contextlib@contextlib.contextmanagerdef open_func(file_name):    #__enter__ method    print('open file:', file_name, 'in __enter__')    file_handler = open(file_name, 'r')    #important yield    try:        yield file_handler    except Exception as exc:        #deal with exception        print('the exception was thrown')    finally:        print('close file:', file_name, 'in __exit__')        file_handler.close()        returnwith open_func('test.txt') as file_in:    for line in file_in:        1/0        print(line)

在这里插入图片描述

“创建临时目录,使用完后再删除临时目录”功能在一个项目中很多地方都需要用到,如果可以将这段逻辑处理成一个工具函数作为一个上下文管理器,那代码的复用率也大大提高。

import contextlibimport shutil@contextlib.contextmanagerdef tempdir(**kwargs):    argdict = kwargs.copy()    if 'dir' not in argdict:        argdict['dir'] = CONF.tempdir    tmpdir = tempfile.makdtemp(**argdict)    try:        yield tmpdir    finally:        try:            shuil.rmtree(tmpdir)        except OSError as e:            LOG.error(_LE('could not remove tempdir: %s'), e)

嵌套上下文管理器的另类写法

  • method1
import contextlib@contextlib.contextmanagerdef test_context(name):    print('enter, my name is {}'.format(name))    yield    print('exit, my name is {}'.format(name))with test_context('aa'):    with test_context('bb'):        print('=== in main ===')
  • method2
with test_context('aaa'), test_context('bbb'):    print('=== in main ===')

在这里插入图片描述

嵌套for循环写成单行

用itertools库实现for循环嵌套

list1 = range(1, 3)list2 = range(4, 6)list3 = range(7, 9)for item1 in list1:    for item2 in list2:        for item3 in list3:            print(item1 + item2 + item3)
from itertools import productlist1 = range(1, 3)list2 = range(4, 6)list3 = range(7, 9)for item1, item2, item3 in product(list1, list2, list3):    print(item1 + item2 + item3)

在这里插入图片描述

关闭异常自动关联上下文

处理异常时,处理不当或者其他问题,再次抛出另一个异常,抛出的异常会携带元素的异常信息。

异常处理程序或finally块中引发异常,默认情况下,异常机制会隐式将先前的异常附加为新异常的__context__属性。这就是Python默认开启的自动关联异常上下文。

try:    print(1/0)except Exception as exc:    raise RuntimeError('something bad happend')

在这里插入图片描述

控制这个上下文,可以加个from关键字(from语法有个限制,就是第二个表达式必须是另一个异常类或实例),来表明新的异常时直接由哪个异常引起的。

try:    print(1/0)except Exception as exc:    raise RuntimeError('something bad happend') from exc

在这里插入图片描述

通过with_traceback()方法为异常设置上下文__context__属性,也能在traceback更好的显示异常信息。

try:    print(1/0)except Exception as exc:    raise RuntimeError('bad thing').with_traceback(exc)

在这里插入图片描述

彻底关闭这个自动关联异常上下文的机制,可以使用raise…from None。

try:    print(1/0)except Exception as exc:    raise RuntimeError('something bad happend') from None

在这里插入图片描述

自带的缓存机制

缓存是一种将定量数据加以保存,以备迎合后续获取需求的处理方式,加快数据获取的速度。

数据的生成过程可能需要经过计算、规整、远程获取等操作,如果是同一份数据需要多次使用,每次都重新生成会大大浪费时间。所以,如果将计算或者远程请求等操作获得的数据缓存下来,会加快后续的数据获取需求。

Python自带的缓存机制实现于functool模块中的lru_cache装饰器。

@functools.lru_cache(maxsize=None, typed=False)- maxsize:最多可以缓存多少个此函数的调用结果,如果为None,则无限制,设置为2的幂时,性能最佳。- typed:若为True,则不同参数类型的调用将分别缓存。
from functools import lru_cache@lru_cache(None)def add(x, y):    print('calculating: %s + %s' % (x, y))    return x + yprint(add(1, 2))print(add(1, 2))print(add(2, 3))

在这里插入图片描述

流式读取超大文件

使用with…open…可以从一个文件中读取数据,但是当使用read函数,Python会将文件的内容一次性的全部载入内存中,如果文件有10个G甚至更多,那么电脑就要消耗巨大的内存。如果用readline做一个生成器来逐行返回,但是如果文件内容就一行,还是会一次性读入全部内容到内存。最优雅的解决方法是,在使用read方法时,指定每次只读取固定大小的内容。

def read_from_file(filename, block_size=1024*8):    with open(filename, 'r') as fp:        with True:            chunk = fp.read(block_size)            if not chunk:                break            yield chunk

优化后:

from functools import partialdef read_from_file(filename, block_size=1024*8):    with open(filename, 'r') as fp:        for chunk in iter(partial(fp.read, block_size), ''):            yield chunk

延迟调用

Python使用上下文管理器实现延时调用。

import contextlibdef callback():    print('B')with contextlib.ExitStack() as stack:    stack.callback(callback)    print('A')

在这里插入图片描述

快速计算函数运行时间

  • method1
import timestart = time.time()#run the functionend = time.time()print(end - start)
  • method2
import timeimport timeitdef run_sleep(second):    print(second)    time.sleep(second)print(timeit.timeit(lambda: run_sleep(2), number=5))

在这里插入图片描述

标准错误输出到日志文件中

import sysimport contextliblog_file = 'test.log'def task():    pass@contextlib.contextmanagerdef close_stdout():    raw_stdout = sys.stdout    file = open(log_file, 'a+')    sys.stdout = file    yield    sys.stdout = raw_stdout    file.close()with close_stdout():    task()

反转字符串/列表

mstr = 'abcd'ml = [1, 2, 3, 4]mstr[::-1]ml[::-1]

在这里插入图片描述

函数参数

def func(item, item_list=[]):    item_list.append(item)    print(item_list)func('iphone')func('xiaomi', item_list=['oppo','vivo'])func('huawei')

在这里插入图片描述

在这里插入图片描述

转载地址:http://mpqs.baihongyu.com/

你可能感兴趣的文章