美文网首页IT课程分享
能让你代码更 Pythonic 的小技巧

能让你代码更 Pythonic 的小技巧

作者: 蓝桥云课 | 来源:发表于2018-06-19 15:31 被阅读71次

下面例举几个在工作中用到过,个人认为比较 Pythonic 的一些实现个技巧:

cached_property

它的作用是将一个方法的计算结果缓存到对象的 __dict__ 当中,熟悉 Flask 的人对这个应该不陌生,Django 应该也有类似的实现。这是 werkzeug 中的源码实现:

class cached_property(property):

  def __init__(self, func, name=None, doc=None):
        self.__name__ = name or func.__name__
        self.__module__ = func.__module__
        self.__doc__ = doc or func.__doc__
        self.func = func

    def __set__(self, obj, value):
        obj.__dict__[self.__name__] = value

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        value = obj.__dict__.get(self.__name__, _missing)
        if value is _missing:
            value = self.func(obj)
            obj.__dict__[self.__name__] = value
        return value

曾经主要运用这个将公司网站的一个页面性能提升了 3~4 倍。

Flask 自己实现了一个线程安全的版本,locked_cached_property

class locked_cached_property(object):
      def __init__(self, func, name=None, doc=None):
            self.__name__ = name or func.__name__
            self.__module__ = func.__module__
            self.__doc__ = doc or func.__doc__
            self.func = func
            self.lock = RLock()

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        with self.lock:
            value = obj.__dict__.get(self.__name__, _missing)
            if value is _missing:
                value = self.func(obj)
                obj.__dict__[self.__name__] = value
            return value

类方法装饰器

学习 Python 一段时间应该都知道装饰器是什么了,也应该知道怎么写一个简单的装饰器了。但是如果想装饰一个类方法,怎么去访问到当前的对象或者类?在普通装饰器中是不太好做到的,这时候就需要借助描述器了。上面的 cached_property 的实现就是一个示范。用 cached_property 装饰一个类方法后,当该方法被以属性的方式调用后,对象和类会被分别传递到 objtype 参数中。

基于这个特性可以实现一个和 @property 对应的类属性装饰器 @classproperty

class classproperty(object):

     def __init__(self, func):
         self.func = classmethod(func)

     def __get__(self, obj=None, type=None):
         return self.func.__get__(obj, type)()

使用它可以将一个 classmethod 以属性的方式访问。

Python 单列模式

在网上搜索 Python 单例模式,能找到很多中实现,比如这样的:

class Singleton(object):

    def __init__(self):
        pass

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance

或者这样的:

def Singleton(cls):
    _instance = {}

    def _singleton(*args, **kargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kargs)
        return _instance[cls]

    return _singleton


@Singleton
class A(object):
    a = 1

    def __init__(self, x=0):
        self.x = x

私以为如果真正理解 Python 的话,下面的才是 Pythonic 的做法:

class Singleton(object):
    def foo(self):
        pass
singleton = Singleton()

将上面的代码在 a.py 中,那么在中用的地方导入的 singleton 就是单例的。

from a import singleton

将一个对象转化成字典

如果一个类定义了 __getitem__keys 那么它的对象就能用 dict 函数转化成字典:

>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...     def __getitem__(self, key):
...         return getattr(self, key)
...     def keys(self):
...         return ('name', 'age')
...

>>> p = Person('Jike', 20)
>>> dict(p)
{'age': 20, 'name': 'Jike'}

这个特性有什么用处呢?举个例子,在些 Flask WEB 应用时,接口需要返回 jSON 序列化的分页数据,我们可以改造 flask-sqlalchemyPagination 对象:

from flask_sqlalchemy import Pagination as _Pagination

class Pagination(_Pagination):
    def __getitem__(self, key):
        return getattr(self, key)

      def items(self):
        def keys(self):
            return (
                'page', 'pages', 'total', 'items',
                'has_prev', 'next_num', 'has_next'
            )

这样分页对象就能很方便的转换成字典了。

作者:实验楼工程师 @protream

更多趣味实验可以直接访问实验楼,在线实验环境操作方便,为大家定期更新最佳实验!(●'◡'●)

实验楼

课程咨询,欢迎添加班主任微信:

班主任微信

相关文章

网友评论

    本文标题:能让你代码更 Pythonic 的小技巧

    本文链接:https://www.haomeiwen.com/subject/bpwaeftx.html