Question: I am creating a python CLI, where user can provide an operation they want to perform, for eg:

```
sum 10 15

```

In my code, I have defined my classes as follows:

```
class Operation:
    # common stuff
    pass

class Sum(Operation):
    identifier = "sum"
    def perform(a, b):
        return a + b

class Difference(Operation):
    identifier = "diff"
    def perform(a, b):
        return a - b

```

Now, in my CLI, if I type `sum 10 15` I want to return the result of `Sum.perform(10, 15)` and similarly if I type `diff 10 15`, I return the result of `Difference.perform(10, 15)`, as `sum` is the identifier of class `Sum` and `diff` is the identifier of class `Difference`.

How do I dynamically access the class and its `perform` method, when I get the input directly from user input?

Answer: 
Classes in Python are [first-class citizens](https://en.wikipedia.org/wiki/First-class_citizen), meaning they can be used as standard objects. In particular we can simply store them in a dictionary:

```
my_dict = {
    'sum': Sum,
    'diff': Difference,
}

```

and so on. Then when you get the operation name as string from command line you simply do

```
my_dict[op_name].perform(a, b)

```

Note that this is a very basic (and you will soon see problematic, e.g. not all operators accept two arguments) approach to what is known as [parsing](https://en.wikipedia.org/wiki/Parsing) and [abstract syntax trees](https://en.wikipedia.org/wiki/Abstract_syntax_tree). This is a huge topic, a bit hard but also very interesting. I encourage you to read about it.

**// EDIT:** If you want to keep identifier on the class, then you can apply a simple class decorator:

```py
my_dict = {}

def autoregister(cls):
    # It would be good idea to check whether we
    # overwrite an entry here, to avoid errors.
    my_dict[cls.identifier] = cls
    return cls

@autoregister
class Sum(Operation):
    identifier = "sum"
    def perform(a, b):
        return a + b

print(my_dict)

```

You have to remember though to import all classes before you use `my_dict`. In my opinion an explicit dict is easier to maintain.
Reading your comment, I think you need to interpret the input. The way I would go about this is splitting the input by spaces (based on your example), and then checking that list. For example:

```py
# This is the place you called the input:
input_unsplit = input("Enter your command and args")
input_list = input_unsplit.split(" ")

# Check the first word to see what function we're calling
if("sum") in input_list[0].lower():
    result = Sum.perform(input_list[1], input_list[2])
    print(result)
# this logic can be applied to other functions as well.

```

This is a simple solution that could be hard to scale.

=== EDITED ===

I have more to add.

If used correctly, dir() can make a list of defined classes up to a certain point in the code. I wrote a calculator for my precal class, and in it I chose to use dir after defining all the math classes, and then if the name met certain conditions (i.e not **main**), it would be appended to a list of valid args to pass. You can modify your classes to include some kind of operator name property:

```
def class Addition:
    self.op_name = "sum"

```

and then perform to take in an array:

```
    def perform(numbers):
        return numbers[0] + numbers [1]

```

To solve many of your scalability issues. Then, after declaring your classes, use dir() in a for loop to append to that valid array, like so:

```
valid_names = []
defined_names = dir()
for name in defined_names:
    if '_' not in name:
        if name not in ("sys","argparse","<any other imported module/defined var>"):
            valid_names.append(name)

```

Note that making this step work for you is all in the placement in the script. it's a bit tedious, but works flawlessly if handled correctly (in my experience).

Then, you can use eval (safe in this context) to call the method you want:

```
# get input here

for name in defined_names:
    if eval(name).op_name == input_list[0].lower():
        eval(name).perform(input_list)

```

This should be a fairly easy-to-scale solution. Just watch that you keep the dir check up to date, and everything else just... works.