python进阶小技巧

Python进阶小技巧

记录3个近日学习到的python进阶技巧,既不是初级技巧,也不是非常高级的奇技淫巧,所以姑且称为进阶技巧,分别是:with, singledispatch和Flattening。

1. 实现自定义方法的with

1.1 Magic Method

Magic Method直译成魔术方法,简单的说就是python中用双下划线包裹起来的方法,《流畅的Python》一书中也把这类方法叫做dunder(double underline) method,双下方法。Python中类的构造函数__init__就是一种最常见的魔术方法。要实现with,就需要2种魔术方法:__enter____exit__

__enter__方法用于管理执行with后返回的实例,并且可以赋值给as关键词之后的变量。
__exit__则顾名思义,定义了with退出时的操作,并对异常进行处理。

下面写一个非常简单的demo

from websocket import create_connection


class Demo:
    def __init__(self, uri):
        self.ws = create_connection(uri)

    def __enter__(self):
        return self.ws
    
    def __exit__(self):
        self.ws.close()

demo非常简单,创建一个websocket连接,并且可以使用with方法来调用。如果不使用with,那么每次建立连接之后,都需要手动显式的去close掉,否则就会有一些僵尸连接长期的挂在那里。用demo中的写法,那么在with执行完毕后,__exit__方法会自动的来替你关闭这个连接,省心省力。

1.2 contextlib

1.1中的魔术方法,固然是非常的清晰明了,但是我实现上面那么简单的功能,就要创建一个类,实现3种魔法方法,显得繁琐了些。为此,python提供了一个非常简便的装饰器——contextlib。使用contextlib重写一下上面那段代码:

from contextlib import contextmanager


@contextmanager
def demo(uri):
    ws = create_connection(uri)
    try:
        yield ws
    finally:
        ws.close()

可以把其中的try部分理解成刚才的__enter__方法,finally部分则对应__exit__方法。

两种写法各有千秋,完全可以根据喜好和具体场景来选择合适的实现方法。我还是更喜欢Magic Method实现的方法,__enter____exit__看起来更清晰和直白,使用装饰器的方法相比之下有种过于隐晦的感觉。

2. 单重派发singledispatch

作为一个python程序员,你完全可以在不知道functools存在的情况下写几万行业务代码而没有任何障碍,但若能熟练使用functools模块中的各种功能,你就可以写出妖艳风骚的多的pythonic代码。

singledispatch正是functools里的一种方法,single很好理解,就是单个的,dispatch词汇量达标的同学也都知道,是派遣派出的意思,合在一起就是单重派发了,它所做的事情,就是把不同数据类型的参数,派发到同名,但内容不同的函数模块去。

比如这一段代码:

def foo(arg):
    if isinstance(arg, str):
        print(f"{arg} is str")
    elif isinstance(arg, int):
        print(f"{arg} is int")
    else:
        print(f"{arg} is unknown")

foo的功能一目了然,就是根据参数arg的不同类型来输出不同的内容,现在用singledispatch来重写一下这段代码:

from functools import singledispatch


@singledispatch
def foo(arg):
    print(f"{arg} is unknown")


@foo.register
def _(arg: int):
    print(f"{arg} is int")


@foo.register
def _(arg: str):
    print(f"{arg} is str")

从python3.7开始,可以通过类型注解的方式实现单重派发,之前的版本,需要在register中指定类型。

上面两种写法孰优孰劣我也不做评判,我把这个记录下来仅仅是因为,我终于发现了类型注解的一个实际用处!!从3.5出现以来,我一直以为类型注解只是一种毫无卵用的另类注释而已!

3. 拉平(Flattening)

问:怎么用最简单的代码把[[1], [2, 3], [4, 5, 6]]变成[1, 2, 3, 4, 5, 6]?
我的第一反应是这样的:

a = [[1], [2, 3], [4, 5, 6]]
l = [each for element in a for each in element]

一个字,low,那怎么写逼格更高呢:

a = [[1], [2, 3], [4, 5, 6]]
l = sum(a, [])

没想到吧,sum还有这功能。当然,如果是列表嵌套列表再嵌套列表的复杂格式,要拉平就写个lamda函数吧。

发布了24 篇原创文章 · 获赞 39 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/shayuchaor/article/details/102916490