在Python3.0中将方法动态添加到类中

2024-05-15 02:57:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图用Python编写一个数据库抽象层,它允许您使用链式函数调用构造SQL语句,例如:

results = db.search("book")
          .author("J. K. Rowling")
          .price("<40.00")
          .title("Harry")
          .execute()

但是当我试图动态地向db类添加所需的方法时,我遇到了一些问题。在

以下是我代码的重要部分:

^{pr2}$

但是,当我运行示例时,例如:

print(db.search("book").price(">4.00").execute())

输出:

{'__Set__': 'harry'}

我是不是走错了路?有没有更好的方法来获取被调用函数的名称或者以某种方式制作函数的“硬拷贝”?在


Tags: 方法数据库executedbsqlsearch语句price
3条回答

创建类后,您只需添加搜索函数(方法)

class Search:  # The class does not include the search methods, at first
    def __init__(self):
        self.conditions = {}

def make_set_condition(option):  # Factory function that generates a "condition setter" for "option"
    def set_cond(self, value):
        self.conditions[option] = value
        return self
    return set_cond

for option in ('price', 'name'):  # The class is extended with additional condition setters
    setattr(Search, option, make_set_condition(option))

Search().name("Nice name").price('$3').conditions  # Example
{'price': '$3', 'name': 'Nice name'}

PS:此类有一个__init__()方法,该方法没有family参数(条件设置器在运行时动态添加,但添加到类中,而不是单独添加到每个实例中)。如果需要创建具有不同条件设置器的Search对象,则上述方法的以下变体起作用(__init__()方法有一个family参数):

^{pr2}$

参考号:http://docs.python.org/howto/descriptor.html#functions-and-methods


如果您确实需要知道存储在其中的属性名称的搜索方法,只需使用

       set_cond.__name__ = option  # Sets the function name

(就在return set_cond之前)。在此之前,方法Search.name具有以下名称:

>>> Search.price
<function set_cond at 0x107f832f8>

设置其__name__属性后,将获得一个不同的名称:

>>> Search.price
<function price at 0x107f83490>

以这种方式设置方法名可以使涉及该方法的错误消息更容易理解。在

首先,您没有向类添加任何内容,而是将其添加到实例中。在

其次,您不需要访问dict。使用self.__dict__[opt] = self.__Set__可以更好地完成setattr(self, opt, self.__Set__)。在

第三,不要使用__xxx__作为属性名。这些保留给Python内部使用。在

第四,正如您所注意到的,Python不容易被愚弄。您调用的方法的内部名称仍然是__Set__,即使您使用不同的名称访问它。:—)当您将方法定义为def语句的一部分时,将设置该名称。在

您可能想用元类创建和设置options方法。您还可能希望实际创建这些方法,而不是尝试对所有方法使用一个方法。如果你真的只想使用一个__getattr__是一种方法,但它可能有点麻烦,我一般建议不要使用它。Lambdas或其他动态生成的方法可能更好。在

下面是一些可以帮助您开始的工作代码(不是您试图编写的整个程序,而是一些说明如何将各个部分组合在一起的代码):

class Assign:

    def __init__(self, searchobj, key):
        self.searchobj = searchobj
        self.key = key

    def __call__(self, value):
        self.searchobj.conditions[self.key] = value
        return self.searchobj

class Book():

    def __init__(self, family):
        self.family = family
        self.options = ['price', 'name', 'author', 'genre']
        self.conditions = {}

    def __getattr__(self, key):
        if key in self.options:
            return Assign(self, key)
        raise RuntimeError('There is no option for: %s' % key)

    def execute(self):
        # XXX do something with the conditions.
        return self.conditions

b = Book('book')
print(b.price(">4.00").author('J. K. Rowling').execute())

相关问题 更多 >

    热门问题