社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

使用decorator将字典插入python类

cyberbeast • 5 年前 • 1597 次点击  

我试图设计一个包装器,它可以接受类(不是对象)的名称,并在类的每个实例中插入一个字典。下面是我在包装现有函数时如何实现这一点的片段。

def insert_fn_into_class(cls):
    """Decorator function that consumes a function and inserts it into the cls class."""
    def decorator(func):
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            return func(*args, **kwargs)
        setattr(cls, f'prefix_{func.__name__}', wrapper)

    return decorator

如何使用类似的模板来修饰字典并将其插入cls类。既然字典是不可调用的,那么如何设计这样的包装器呢?

更新

感谢您对此的建设性反馈。 一位堆栈溢出用户正确地指出,我未能解释为什么要这样做。所以说:

  1. 我正在尝试构建一个框架,它实际上可以使用一堆用户定义的函数并扩展现有的类。所以我有一节课 A ,以及用户定义的函数 f_1 , f_2 f_n 我想把它注入课堂 这样类的一个实例 obj_a = A() 可以调用以下函数 obj_a.f_1() . 我使用了一个类似于上面代码片段的decorator函数来实现这一点。
  2. 现在,每个用户定义的函数都有一些重复的代码,如果基类的所有实例 可以访问用户定义的词典。我实现这一点的思路是尝试修改现有的包装函数,将其添加到类中。然而,我知道字典是不可调用的,因此,这个问题。

我希望这足够详细。

更新2

看来还有进一步细化的余地。下面是一个例子,说明我前面描述的各种组件是什么样子的。

module_a.py

class BaseClass():
    def __init__(self):
        ...

    def base_class_method(self):
        ...

    def run(self):
        getattr(self, 'prefix_user_fn_1')()

def extend(cls=BaseClass):
    def decorator(func):
        def wrapper(self, *args, **kwargs):
            return func(*args, **kwargs)
        setattr(cls, f'prefix_{func.__name__}', wrapper)
    return decorator

user_defined_functions.py

from module_a import BaseClass, extend

@extend()
def user_fn_1():
    dict_ = {'a':'b', 'c':'d'}
    ...

@extend()
def user_fn_2():
    dict_ = {'my':'dict', 'c':'d'}
    ...

main.py

from module_a import BaseClass

b = BaseClass()
b.run()

每个用户函数都包含一个常用字典的子集。为了利用这一点,我认为如果这可以作为动态注入的基类属性的一部分来访问,那将是很方便的。

modified_user_defined_functions.py

# THIS WILL NOT WORK FOR OBVIOUS REASONS
from module_a import BaseClass, extend, common_config, insert_config_into_class

# @common_config ?? Is this even a good idea?
dict_ = {'my':'dict', 'a':'b', 'c':'d'}
insert_config_into_class(BaseClass, dict_)

@extend()
def user_fn_1(self):
    print(self.dict_)
    # do something with self.dict_
    ...

若要合并此项,我可能必须将run方法更改为 BaseClass 像这样:

modified_module_a.py

...
class BaseClass():
    ...

    def run(self):
        getattr(self, 'prefix_user_fn_1')(self)

更新3-潜在解决方案

def shared_config(data, cls=BaseClass):
    setattr(cls, 'SHARED_DICT', data)

这个解决方案是可行的,但也在一定程度上回答了我的问题,我想我可以说,当一个简单的函数可能实现这一点时,我可能通过为此编写一个decorator来过度设计我的解决方案。

然而,最初问题的一个方面仍然存在——这是一个好办法吗?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/40014
 
1597 次点击  
文章 [ 2 ]  |  最新文章 5 年前
bruno desthuilliers
Reply   •   1 楼
bruno desthuilliers    6 年前

我想我可以说也许我对我的解决方案设计得太过了

嗯,确实有点…FWW the whole thing looks quite overcomplicated .

首先:如果将dict定义为全局(模块)名称,则该模块中的所有函数都可以直接访问它:

# simple.py

SHARED_DATA = {"foo": "bar", "answer": 42}

def func1():
    print SHARED_DATA["foo"]

def func2():
    print SHARED_DATA["bar"]

所以我不认为在一个从另一个模块导入的类中“注入”它只是为了从这些函数访问它。

现在和你的装饰师:

def extend(cls=BaseClass):
    def decorator(func):
        def wrapper(self, *args, **kwargs):
            return func(*args, **kwargs)
        setattr(cls, f'prefix_{func.__name__}', wrapper)
    return decorator

如果目标是使函数成为类的属性,但不将其转换为实例方法,则可以使用 staticmethod

def extend(cls=BaseClass):
    def decorator(func):
        setattr(cls, f'prefix_{func.__name__}', staticmethod(func))
        return func
    return decorator

如果你有其他(无法解释的)理由 SHARED_DICT 类属性 BaseClass 或者另一个类),您确实可以提供一个配置函数:

# module_a
def configure(cls, data):
    cls.SHARED_DATA = data


# less_simple.py

from module_a import BaseClass, configure

SHARED_DATA = {"foo": "bar", "answer": 42}
configure(BaseClass, SHARED_DATA)

def func1():
    print SHARED_DATA["foo"]

def func2():
    print SHARED_DATA["bar"]

但请注意,你仍然不需要通过 基类 也不 self 从模块的函数访问此dict。

能够 当然,可以将类或实例传递给您使用过的已定义函数,但是在这里,不需要使用奇怪的装置-要么使它们成为classmethod,要么直接将它们设置为类的属性,python将负责将类或实例作为第一个参数(这里是example使它们成为实例方法):

# module_a
def configure(cls, data):
    cls.SHARED_DATA = data

def extend(cls=BaseClass):
    def decorator(func):
        setattr(cls, f'prefix_{func.__name__}', func)
        return func
    return decorator

# rube_goldberg.py

from module_a import BaseClass, configure, extend

SHARED_DATA = {"foo": "bar", "answer": 42}
configure(BaseClass, SHARED_DATA)

@extend
def func1(self):
    print SHARED_DATA["foo"]

@extend
def func2(self):
    print SHARED_DATA["bar"]

注意,这仍然是完全无用的装饰功能pov -他们不需要 自己 完全可以进入 SHARED_DATA ,但现在如果没有 基类 实例作为第一个参数,因此用户无法直接测试它们。

现在,也许你在问题中没有提到其他的事情,但到目前为止,你似乎正在努力使简单的事情变得复杂;-)

Slam
Reply   •   2 楼
Slam    6 年前

您提问的方式给了我一个提示,说明您不太了解python如何使用对象引用。

decorators不是用来处理不可调用的对象的,所以这是一个澄清

接受类的名称(不是对象)

不太清楚。而且您想附加到类dict或函数的内容没有区别,您无论如何只能操作抽象引用。

除此之外,看看这个片段:

def patcher(cls):
    def wrapper(*args, **kwargs):
        instance = cls(*args, **kwargs)
        instance.payload = {'my': 'dict'}
         return instance
    return wrapper

@patcher
class A:
    pass

它能满足你的需要吗?