Python 有哪些让你相见恨晚的技巧?

关注「实验楼」,每天分享一个项目教程   

实验楼高级工程师protream老师,为大家带来这些Python黑魔法:有的能网页速度提高3倍,有的可以把数十行代码浓缩成几行,了解一下。

正文共:2889 字 

预计阅读时间:8 分钟

实验楼python高级工程师@protream总结了一些他在工作中用到过,个人认为比较 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 装饰一个类方法后,当该方法被以属性的方式调用后,对象和类会被分别传递到 obj  type 参数中。

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

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-sqlalchemy  Pagination 对象:

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'
)

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

作者:实验楼工程师 郑楠GitHub: protream (Zheng Nan)Python学习:Python_精选项目课程


Python 有哪些让你相见恨晚的技巧?

推荐阅读:


Python 有哪些让你相见恨晚的技巧?