0

In the example below, I have to explicitly define all of the 'resolve' methods in the ReturnValue class.

It would be more concise if I could auto define these methods within a loop, seeing as they all pretty much do the same thing, with the only difference being the name of the method which matches the name of the class member variable being returned.

Is this possible with 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()
0

2 Answers 2

2

An alternative is to intercept the method call using the builtin __getattribute__ and return the specific attribute when a "resolve" method is received.

This code should do the job:

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)

A difference with @Philip Tzou answer is that here we are not adding every method in the class, as setattr does. Instead we directly return the attribute in demand. Depending on your case of use this could be good or not.

Also, what Philip mentions at the end of his answer is important to consider and could be implemented in the code above if you replace this line:

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

For this:

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

This code was written in Python 3, so maybe you have to change the super() syntax in order to work in Python 2.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you @martin, I was able to get your solution working in Python2. I appreciate having everything encapsulated inside the affected class. Trying to follow the execution via a debugger leaves me more confused... but it works!
Btw, the resolve_xxx can be also implemented in the subclass of Interface. Maybe in your case you don't need have them in the ReturnValue.
1

I think this should work:

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)

But you see, it didn't save too much lines. And I think just defining every method explicitly is actually a better and pythonic way. If you are trying to reuse some complicating code, just isolating the common part out of each method and put them into a separated function like this:

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)

    ...

1 Comment

Thank you @philip. In my real-world implementation, I will use this when querying an API endpoint, which returns a large dictionary. Each of the 'resolve_' methods simply returns the value of that key, so I am saving many lines of code... which I'm sure I'll end up adding back to with comments required to describe the magical method

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.