0

I want to proxy an API over a network. I have the API in a dictionary. I'd like to create a class with the API methods from the dictionary so I can use the API as if I was local. The trouble is finding the name of my dynamically created method. (My approach is based on Adding a Method to an Existing Object and Python dynamic class methods.)

class MainClass(object):
    def build_API(self):
        methods = dict(meth1='arg1', meth2='arg2')
        for key in methods.iterkeys():
            setattr(self, key, MethodType(self.default_API, self))
    def default_API(self, *args, **kwargs)
        called_as_name = ????
        self.send_message(called_as_name, args, kwargs)
    def send_message(self, called_as_name, *args, **kwargs)
        ...
        # Send API command over network
        ....

To use this:

api = MainClass()
api.build_API()
api.meth1()

However, everything I try for "called_as_name" always returns "default_API" and never "meth1". How can I get "called_as_name = meth1" when I type "api.meth1()" and "called_as_name = meth2" when I type "api.meth2()"?

I have tried:

curframe = inspect.currentframe()
calframe = inspect.getouterframes(curframe, 2)
called_as_name = calframe[1][3]

from Python: How to get the caller's method name in the called method?

called_as_name = inspect.stack()[1][5]

from Getting the caller function name inside another function in Python?

called_as_name = sys._getframe(1).f_code.co_name

from Getting the caller function name inside another function in Python?

1
  • You'd be better off making meth1 and meth2 be some sort of fake callable object that stores its own name. Also, I don't really think what you're doing is a good idea. All you're doing is making a bunch of aliases to a single method (default_API). Commented Apr 15, 2015 at 6:23

1 Answer 1

2

Trying to do this with actual methods and grabbing the names from the stack frame with that sort of introspection trickery is a recipe for disaster. Instead, make the "methods" be custom callable objects that know their names. Here's a sketch:

class FakeMethod(object):
    def __init__(self, name, parent):
        self.name = name
        self.parent = parent

    def __call__(self, *args, **kwargs):
        self.parent.send_message(self.name, args, kwargs)

class MainClass(object):
    def build_API(self):
        methods = dict(meth1='arg1', meth2='arg2')
        for key in methods.iterkeys():
            setattr(self, key, FakeMethod(key, self))
    def send_message(self, called_as_name, *args, **kwargs):
        print("Sending message:", called_as_name, args, kwargs)

Then:

>>> api = MainClass()
>>> api.build_API()
>>> api.meth1()
Sending message: meth1 ((), {}) {}
>>> api.meth2()
Sending message: meth2 ((), {}) {}

In theory you could even use __getattr__ on the MainClass to dynamically generate a FakeMethod every time an attribute name is accessed that is not defined but is listed in some list of API method names.

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

1 Comment

Perfect! I thought I needed to somehow store the name with the function, but did not make the leap to use a class object. "getattr" is also a great idea I'll have to try.

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.