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_精選專案課程