1

I'm trying to assign class methods to class attribute, so I can call the methods from string. When using the class I want to call it from string like:

A.MAP['add'](x, y)
A.MAP['subtract'](x, y)

This is my current code:

class A:
    MAP = {
        'add' : A.add(x, y),
        'subtract' : A.subtract(x, y),
    }

    @classmethod
    def add(cls, x, y)
        return x + y

    @classmethod
    def subtract(cls, x, y)
        return x - y

However the result shown error that A is not defined at the line of assigning A.add to MAP['add']. For short functions I can use lambda. However, in case of a longer function, how can I achieve this design?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Chetchaiyan
  • 261
  • 2
  • 11
  • 2
    Why on earth do you want to do that? The desired api you've presented is just as unintuitive as it can be, and that takes something. Why do you need, what seems to be a stand-alone methods, as class methods anyway? – Tymoteusz Paul May 05 '15 at 12:30
  • `'add' : lambda x,y: A.add(x, y),`...? – Cthulhu May 05 '15 at 12:34
  • @TymoteuszPaul About the main goal, I would like to process a few methods which can be done from text file instruction. About class methods ,actually it doesn't need to be a classmethod. I just want that to have namespace in front of it so I can easily remember them, but it isn't necessary. – Chetchaiyan May 05 '15 at 12:34
  • If you need dynamic access to the class's methods, you can just use `method_name = 'add'; getattr(A, method_name)(3, 7)`. There's no need for you to keep an explicit dictionary. – chepner May 05 '15 at 12:34
  • 1
    http://stackoverflow.com/questions/3061/calling-a-function-of-a-module-from-a-string-with-the-functions-name-in-python – Cthulhu May 05 '15 at 12:35
  • @Cthulhu each function have many line of code. so I can't use lambda – Chetchaiyan May 05 '15 at 12:36
  • If you want namespace in front of it then spread the functions across multiple python files, then you have pretty fomrat lile `math.subtract(x,y)` – Tymoteusz Paul May 05 '15 at 12:37
  • @chepner the problem seem to be answer by getattr as shown in previous questions you state. However, the main problem here is the design which I would like to make it appear in dict so I can be easily to understand and read code. I think this question isn't similar as you said. – Chetchaiyan May 05 '15 at 12:47
  • @TymoteuszPaul you are right there are predefined methods to do this, however I assume this is a learning exercise in OOP programming. Please enforce standardized Python approach as this helps uniformity and readability. – Warosaurus May 05 '15 at 12:47
  • @Warosaurus just because there are classes doesn't mean that it's oop, and this "excercise" doesn't teach anything good. – Tymoteusz Paul May 05 '15 at 13:01

2 Answers2

2

Note that when you try:

class A:
    MAP = {
        'add' : A.add(x, y),
        'subtract' : A.subtract(x, y),
    }

you are trying to access e.g. A.add before the name A exists (the class isn't bound to the name until definition completes) and before the name add exists (you haven't defined that method yet). Everything at the top level of the class definition is done in order.


You need to put the class methods into the dictionary after the class has been defined (they don't become callable until definition is complete):

class A:

    MAP = {}

    @classmethod
    def add(cls, x, y):  # note colon
        return x + y

    @classmethod
    def subtract(cls, x, y):  # also here
        return x - y

A.MAP['add'] = A.add
A.MAP['subtract'] = A.subtract

Note that, as neither class method uses cls, you could make them @staticmethods instead. Or just use functions - Python isn't Java, you don't need to put everything into a class.


Alternatively, you can use getattr to access attributes (including class methods) by name:

>>> class A:

        @classmethod
        def add(cls, x, y):
            return x + y

        @classmethod
        def subtract(cls, x, y):
            return x - y


>>> getattr(A, 'add')(1, 2)
3
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Thank you for your explanation and multiple solution. This help me a lot to understand why A is not define error shown. getattr isn't solve my problem since one operation require more than one function to handle it. so i need same keyword 'add' to operate multiple function depend on the cases. I can use @staticmethod by declaring 'add' : add.__func__ however, I think your suggestion to put it after the class is quite easier for me to read. Thank you again for your help. – Chetchaiyan May 05 '15 at 12:52
0

Please do not program in python like that, instead use a more standard oop approach like this:

#!/usr/bin/env python

class A:

    def __init__(self):
        pass

    @classmethod
    def add(self, x, y):
        return x + y

    @classmethod
    def subtract(self, x, y):
        return x - y

if __name__ == "__main__":
    a = A()
    print a.add(1,2)  # ans: 3
    print a.subtract(2,1) # ans: 1
Warosaurus
  • 520
  • 1
  • 5
  • 14
  • This doesn't help the OP access the functionality *"from text file instruction"*... – jonrsharpe May 05 '15 at 12:44
  • @jonrsharpe you might be right, honestly I didn't read the question all to much as this is simple exercise. However I suggest you instead stick to a "better" approach and teach others the "right" way to do things rather than crawl for points on SO. – Warosaurus May 05 '15 at 12:51
  • 1
    Note that my answer includes an explanation of the actual problem and various options to help the user resolve it without making too many assumptions about why they're trying to achieve it; there are plenty of legitimate reasons to want to call things by name. If you have a problem with it, downvote it, but it's not like I've told the OP to use `exec`/`eval`. Hop off your high horse and [be nice](http://stackoverflow.com/help/be-nice). – jonrsharpe May 05 '15 at 12:54