【问题标题】:Specifically named dynamic class methods in pythonpython中专门命名的动态类方法
【发布时间】:2017-07-02 03:13:53
【问题描述】:

在下面的示例中,我必须在 ReturnValue 类中显式定义所有 'resolve' 方法。

如果我可以在循环中自动定义这些方法会更简洁,因为它们几乎都做同样的事情,唯一的区别是方法的名称与类成员变量的名称匹配返回。

这可以在 Python 2.7 中实现吗?

import graphene


class ApiObj(object):
    @staticmethod
    def get_values_as_dictionary():
        return {'dog': 'pound', 'cat': 'nip', 'horse': 'fly', 'bear': 'down'}


class ReturnKeys(graphene.Interface):
    dog = graphene.String()
    cat = graphene.String()
    horse = graphene.String()
    bear = graphene.String()


class ReturnValue(graphene.ObjectType):
    class Meta:
        interfaces = (ReturnKeys,)

    def resolve_dog(self):
        return self.dog

    def resolve_cat(self):
        return self.cat

    def resolve_horse(self):
        return self.horse

    def resolve_bear(self):
        return self.bear


api = ApiObj()
value_dict = api.get_values_as_dictionary()
rv = ReturnValue(**value_dict)

print rv.resolve_cat()
print rv.resolve_dog()
print rv.resolve_horse()
print rv.resolve_bear()

【问题讨论】:

    标签: python python-2.7 class oop dynamic


    【解决方案1】:

    我认为这应该可行:

    class ReturnValue(graphene.ObjectType):
        class Meta:
            interfaces = (ReturnKeys,)
    
    
    def set_resolve_method(animal):
        setattr(
            ReturnValue,
            'resolve_' + animal,
            lambda self: getattr(self, animal)
        )
    
    for animal in ('dog', 'cat', 'horse', 'bear'):
        # this function scoped the variable `animal`
        set_resolve_method(animal)
    

    但是你看,它并没有节省太多的行。而且我认为明确定义每个方法实际上是一种更好的pythonic方式。如果您想重用一些复杂的代码,只需将每个方法的公共部分隔离出来,并将它们放入一个单独的函数中,如下所示:

    def common_function(animal):
        pass  # do something here
    
    
    class ReturnValue(graphene.ObjectType):
        class Meta:
            interfaces = (ReturnKeys,)
    
        def resolve_dog(self):
            return common_function(self.dog)
    
        def resolve_cat(self):
            return common_function(self.cat)
    
        ...
    

    【讨论】:

    • 谢谢@philip。在我的实际实现中,我将在查询返回一个大字典的 API 端点时使用它。每个'resolve_' 方法都只返回该键的值,所以我节省了很多代码行......我相信我最终会用描述神奇方法所需的 cmets 添加回来
    【解决方案2】:

    另一种方法是使用内置的__getattribute__ 拦截方法调用,并在收到“resolve”方法时返回特定属性。

    这段代码应该可以完成这项工作:

    class ReturnValue(graphene.ObjectType):
        class Meta:
            interfaces = (ReturnKeys,)
    
        def __getattribute__(self, attr):
            if attr.startswith("resolve_"):
                return lambda: getattr(self, attr[8:])
            return super().__getattribute__(attr)
    

    与@Philip Tzou 答案的不同之处在于,我们不会像setattr 那样在类中添加所有方法。相反,我们直接返回需要的属性。根据您的使用情况,这可能好也可能不好。

    此外,Philip 在他的回答末尾提到的内容很重要,如果您替换此行,则可以在上面的代码中实现:

    return lambda: getattr(self, attr[8:])
    

    为此:

    return lambda: self.common_function(attr[8:])
    

    此代码是用 Python 3 编写的,因此您可能必须更改 super() 语法才能在 Python 2 中工作。

    【讨论】:

    • 谢谢@martin,我能够让您的解决方案在 Python2 中运行。我很欣赏将所有内容封装在受影响的类中。试图通过调试器跟踪执行让我更加困惑......但它有效!
    • 顺便说一句,resolve_xxx 也可以在Interface 的子类中实现。也许在您的情况下,您不需要将它们放在ReturnValue 中。
    猜你喜欢
    • 1970-01-01
    • 2016-12-03
    • 2013-04-09
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多