Python 装饰器在类中获取或设置字典值

     2023-02-23     67

关键词:

【中文标题】Python 装饰器在类中获取或设置字典值【英文标题】:Python decorator get or set dictionary value in class 【发布时间】:2017-12-08 07:36:21 【问题描述】:

我正在研究一个代表具有大量关联数据的对象的类。我将这些数据存储在一个名为metadata 的字典类属性中。表示可以是:

'key1':slowToComputeValue, 'key2':evenSlowerToComputeValue

值的计算在某些情况下非常很慢,所以我想做的是,使用“getter”函数,首先尝试从 元数据中获取值 em>字典。只有在 KeyError 上(即当 getter 尝试获取一个尚不存在的键的值时)才应该计算该值(并添加到字典中以便在下次调用 getter 时快速访问)。

我从一个简单的开始:

try:
    return self.metadata[requested_key]
except KeyError:
    #Implementation of function

由于类中有很多 getter,我开始认为前 3 行代码可以由装饰器处理。但是,我在完成这项工作时遇到了问题。问题是我需要将元数据字典从类实例传递给装饰器。我发现了几个教程和帖子,如this 一个,它们表明可以将参数发送到封闭函数,但我遇到的困难是将类实例化属性元数据发送给它(如果我发送一个字符串值它有效)。

我尝试的一些示例代码在这里:

def get_existing_value_from_metadata_if_exists(metadata):
    def decorator(function):
        @wraps(function)
        def decorated(*args, **kwargs):
            function_name = function.__name__
            if function_name in metadata.keys():
                return metadata[function_name]
            else:
                function(*args, **kwargs)
        return decorated
    return decorator

class my_class():
    @get_existing_value_from_metadata_if_exists(metadata)
    def get_key1(self):
        #Costly value calculation and add to metadata

    @get_existing_value_from_metadata_if_exists(metadata)
    def get_key2(self):
        #Costly value calculation and add to metadata

    def __init__(self):
        self.metadata = 

我得到的错误通常是自我定义的,但我尝试了参数放置、装饰器放置等的各种组合,但没有成功。

所以我的问题是:

    我怎样才能完成这项工作? 装饰器是实现我想要做的事情的合适方式吗?

【问题讨论】:

您是否希望数据即使在 my_class 的不同实例之间也能保持不变? 否 - 每个实例都与一个音频文件相关。所以每个实例都有自己的一组属性。 【参考方案1】:

是的,装饰器是一个很好的用例。例如,Django 已经包含了类似的东西,它叫做cached_property

基本上,它所做的只是当第一次访问该属性时,它将以与函数相同的名称将数据存储在实例的 dict(__dict__) 中。当我们稍后获取相同的属性时,它会简单地从实例字典中获取值。

cached_property 是 non-data descriptor。因此,一旦在实例的字典中设置了键,对属性的访问将始终从那里获取值。

class cached_property(object):
    """
    Decorator that converts a method with a single self argument into a
    property cached on the instance.

    Optional ``name`` argument allows you to make cached properties of other
    methods. (e.g.  url = cached_property(get_absolute_url, name='url') )
    """
    def __init__(self, func, name=None):
        self.func = func
        self.__doc__ = getattr(func, '__doc__')
        self.name = name or func.__name__

    def __get__(self, instance, cls=None):
        if instance is None:
            return self
        res = instance.__dict__[self.name] = self.func(instance)
        return res

在你的情况下:

class MyClass:
    @cached_property
    def key1(self):
        #Costly value calculation and add to metadata

    @cached_property
    def key2(self):
        #Costly value calculation and add to metadata

    def __init__(self):
        # self.metadata not required

使用name 参数将现有方法转换为缓存属性。

class MyClass:
    def __init__(self, data):
        self.data = data

    def get_total(self):
        print('Processing...')
        return sum(self.data)

    total = cached_property(get_total, 'total')

演示:

>>> m = MyClass(list(range(10**5)))

>>> m.get_total()
Processing...
4999950000

>>> m.total
Processing...
4999950000

>>> m.total
4999950000

>>> m.data.append(1000)

>>> m.total  # This is now invalid
4999950000

>>> m.get_total()  # This still works
Processing...
4999951000

>>> m.total
4999950000

根据上面的例子我们可以看到,只要我们知道内部数据还没有更新,我们就可以使用total,从而节省处理时间。但它不会使get_total() 变得多余,因为它可以根据数据得到正确的总数。

另一个例子可能是,我们面向公众的客户目前正在使用某些东西(比如get_full_name())作为方法,但我们意识到在这种情况下使用它作为属性(只是full_name)更合适保持方法不变但将其标记为已弃用并开始建议用户从现在开始使用新属性是有意义的。

【讨论】:

哇,这是什么魔法......它有效,但我仍在努力解决它。您能否添加一个使用名称 kwarg 的示例? @user3535074 “name kwarg”是什么意思? 'name=None' 部分 -> def __init__(self, func, name=None)【参考方案2】:

解决这个问题的另一种方法是像这样使用类“属性”:

class MyClass():
    def __init__():
        self._slowToComputeValue = None
    @property
    def slowToComputeValue(self):
        if self._slowToComputeValue is None:
            self._slowToComputeValue = self.ComputeValue()
        return self._slowToComputeValue
    def ComputeValue(self):
        pass

现在您可以像访问类属性一样访问它:

myclass = MyClass()
print(myclass.slowToComputeValue)

【讨论】:

Python:装饰器能否确定一个函数是不是在类中定义?

】Python:装饰器能否确定一个函数是不是在类中定义?【英文标题】:Python:canadecoratordetermineifafunctionisbeingdefinedinsideaclass?Python:装饰器能否确定一个函数是否在类中定义?【发布时间】:2012-02-0606:31:36【问题描述】:我正在编... 查看详情

在类中声明装饰器

...发布时间】:2016-11-2605:35:01【问题描述】:我正在尝试在Python中使用自定义包装器/装饰器,并且我想在一个类中声明一个inside,以便例如打印属性的快照。我已经尝试了thisquestion的东西,但没有成功。这是我想做的(注意:这... 查看详情

python中的property类和@property装饰器

Python中的property类和@property装饰器在Python的类中,为了避免使用者直接在类的外部操作属性和方法,我们可以将属性和方法设置成私有属性和私有方法。如果我们需要访问私有属性和私有方法,可以用包含get/set的方法来间接访问... 查看详情

如何在类中定义装饰器?

】如何在类中定义装饰器?【英文标题】:Howtodefinedecoratorwithintheclass?【发布时间】:2021-11-1005:47:18【问题描述】:我想在类中使用装饰器,但出现位置错误。1.我不想使用functools和importwraps。2.我们可以在类内声明而不是在类外... 查看详情

可以在 Python 的类中调用有状态函数吗?

】可以在Python的类中调用有状态函数吗?【英文标题】:PossibletocallstatefulfunctioninaclassinPython?【发布时间】:2020-09-1708:28:02【问题描述】:是否可以在Python中直接设置某个值并通过任何方式(继承、元类、类装饰器)在类中获取... 查看详情

如何在类中声明装饰器,以装饰已经装饰的继承方法?

】如何在类中声明装饰器,以装饰已经装饰的继承方法?【英文标题】:Howtodeclaredecoratorinsideaclass,todecorateanalreadydecorated,inheritedmethod?【发布时间】:2019-10-0206:23:25【问题描述】:我想创建一个装饰器,它是一个类成员,它将装... 查看详情

如何在类中使用 Pyomo 装饰器

】如何在类中使用Pyomo装饰器【英文标题】:HowtousePyomodecoratorwithinaclass【发布时间】:2020-03-2300:44:14【问题描述】:下面是一个使用装饰器语法的简单Pyomo脚本-我想了解如何在类中使用这种语法-在本例中是Model。非类版本frompyomo... 查看详情

如何在类中嵌套多处理管理器字典

】如何在类中嵌套多处理管理器字典【英文标题】:howtohavenestedmultiprocessingmanagerdictionariesinaclass【发布时间】:2020-12-0318:48:19【问题描述】:我创建了一个简单的类来存储多处理值。init函数如下所示:def__init__(self):Manager=multiproc... 查看详情

如何在类中移动这个方法装饰器模式?

】如何在类中移动这个方法装饰器模式?【英文标题】:HowdoImovethismethod-decoratorpatterninsideaclass?【发布时间】:2015-05-1401:15:47【问题描述】:目前,我正在使用装饰器将类中的方法动态添加到列表中;这样我可以在需要时同时遍... 查看详情

装饰器

 1.这是ts编译为js后,装饰器的应用函数。装饰器在类声明时为它添加额外功能2.装饰器应用顺序:实例成员->静态成员->构造器->类2.1小顺序:对于实例成员和静态成员,可以直接看出,从下到上先执行的参数装饰器,... 查看详情

TypeError:在类中使用装饰器时,“staticmethod”对象不可调用

】TypeError:在类中使用装饰器时,“staticmethod”对象不可调用【英文标题】:TypeError:\'staticmethod\'objectisnotcallablewhileusingdecoratorsinsideclasses【发布时间】:2021-09-2906:48:38【问题描述】:下面有一些代码classExample:def__init__(self,height,we... 查看详情

使用 staticmethod 或 classmethod 装饰器装饰时,类中的 Python LRU 缓存忽略最大大小限制

】使用staticmethod或classmethod装饰器装饰时,类中的PythonLRU缓存忽略最大大小限制【英文标题】:PythonLRUcacheinaclassdisregardsmaxsizelimitwhendecoratedwithastaticmethodorclassmethoddecorator【发布时间】:2022-01-2108:29:00【问题描述】:我正在查看Pyth... 查看详情

在类中的所有实例方法自动调用之后调用方法:元类还是装饰器?

...在类中的所有实例方法自动调用之后调用方法:元类还是装饰器?【英文标题】:Callamethodafterallinstancemethodcallsinaclassautomatically:ametaclassoradecorator?【发布时间】:2012-08-2702:37:21【问题描述】:假设我有一堂课classFoo:def__init__(self):p... 查看详情

在类中使用托管bean设置变量,并从另一个托管bean中的此类获取变量(代码片段)

我发布了类似的问题。看看here。我解决了在托管bean之间共享值的问题。我的新问题是分享我在一个类中的一个mangedbean中设置的值。并希望在antohermangedbean中获得此值。这是解释我的问题的代码示例。@ManagedBean@SessionScopedpublicclass... 查看详情

在 Python 3 中获取未绑定方法对象的定义类

】在Python3中获取未绑定方法对象的定义类【英文标题】:GetdefiningclassofunboundmethodobjectinPython3【发布时间】:2011-04-0502:18:14【问题描述】:假设我想为类中定义的方法制作一个装饰器。我希望该装饰器在被调用时能够在定义该方... 查看详情

python装饰器在flask中验证发布请求(代码片段)

查看详情

python获取类属性

参考技术A通常情况下,我们在类对象中定义的属性都会设置访问权限,外部程序无法直接获取,防止恶意的修改,当属性被设置为私有属性后,外部程序该如何访问呢?例:使用普通方法访问私有属性例:使用property方法访问私... 查看详情

在类中装饰 @property.setter 装饰器 [重复]

...【发布时间】:2019-09-0122:27:22【问题描述】:我找不到在Python类中装饰@property.setter装饰器的正确方法。为了避免复制粘贴代码,我决定在我的项目的“设置”模块中装饰@property.setter函数。所以“设置”模 查看详情