懒惰的类属性装饰器 [英] Lazy class property decorator
问题描述
我有一个django模型,需要参考自定义用户模型进行一些处理.
I have one django model which needs to do some processing referring the custom user model.
在类加载时,我无法使用该模型的类,因为类的加载顺序是未知的.
I can't work with the class of this model at class loading time because the loading order of the classes is unknown.
因此,我需要在运行时添加一些类属性,此刻,我需要将它们添加到__init__
或__new__
中,例如:
So I need to add some class attributes at runtime, at the moment I'm adding them in the __init__
or __new__
like:
def __new__(cls, *args, **kwargs):
# hack to avoid INSTALLED_APPS initialization conflicts.
# get_user_model() can't be called from this module at class loading time,
# so some class attributes must be added later.
# Metaclasses could me more appropiate but I don't want to override
# dango's metaclasses.
if not hasattr(cls, '_reverse_field_name_to_user'):
cls._find_reverse_field_name_to_user()
return Group.__new__(cls, *args, **kwargs)
它可以工作,但是看起来很可怕,所以我考虑过对这些属性使用类似@lazyclassproperty
的东西.
It works but looks horrible so I've thought about using something like @lazyclassproperty
for these attributes.
我找到了几个@classproperty
和@lazyproperty
装饰器,但没有两个装饰器,我也不知道该如何写一个.
I've found several @classproperty
and @lazyproperty
decorators but not one for both and I have no idea how to write one myself.
问题:我该如何编码这样的装饰器?或建议我目前愚蠢的实施方案的另一种更清洁的替代方案.
Question: How could I code such decorator? or suggest another cleaner alternative to my current silly implementation.
推荐答案
Pyramid framework has a very nice decorator called reify
, but it only works at instance level, and you want class level, so let's modify it a bit
class class_reify(object):
def __init__(self, wrapped):
self.wrapped = wrapped
try:
self.__doc__ = wrapped.__doc__
except: # pragma: no cover
pass
# original sets the attributes on the instance
# def __get__(self, inst, objtype=None):
# if inst is None:
# return self
# val = self.wrapped(inst)
# setattr(inst, self.wrapped.__name__, val)
# return val
# ignore the instance, and just set them on the class
# if called on a class, inst is None and objtype is the class
# if called on an instance, inst is the instance, and objtype
# the class
def __get__(self, inst, objtype=None):
# ask the value from the wrapped object, giving it
# our class
val = self.wrapped(objtype)
# and set the attribute directly to the class, thereby
# avoiding the descriptor to be called multiple times
setattr(objtype, self.wrapped.__name__, val)
# and return the calculated value
return val
class Test(object):
@class_reify
def foo(cls):
print("foo called for class", cls)
return 42
print(Test.foo)
print(Test.foo)
运行程序,它会打印
foo called for class <class '__main__.Test'>
42
42
这篇关于懒惰的类属性装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!