Search code examples
pythonoopstring-formatting

Dynamic Object Naming and Class Calling in Python


I'm developing a programming language in Python where you can program a simulation of simple machines. I have written a function that takes some input, parses it, and finds out what the first word is.

Now, for the first word insert, I need to take the next words obj, name, x, and y.

obj: what type of simple machine it is
name: what you want to call the object
x: X coordinate on the graph
y: Y coordinate on the graph

I have already made a function nextword that iterates through the rest of the code and defines each variable as those words, so with the following code:

insert pulley JohnThePulley 3 4

It sees first word is insert, and calls my insert function.
Then, it sets obj to pulley, name to JohnThePulley, and so on.

However, now I need to make an object in the daughter class pulley, under the mother class simple_machines, that has the name JohnThePulley, etc.

The situation I'm in is that for the first word insert, for example, I don't know at all what the next word will be, from all the choices of daughter classes that they can call. I need to create the specified object along with the provided name, the provided X coordinate and the provided Y coordinate.

I have tried doing simple formatting in python using '{}'.format(name) or .format(obj), but those don't work.

# Insert function
def insert(code):
    c = 4
    syntax = np.array([obj, name, x, y])
    nextword(parser.code_array, syntax, c)
    objc += 1
    return


# Nextword function, code_array[0] is insert, syntax is an array that
# contains all the variables that need to be defined for any function
def nextword(code_array, syntax, c):
    assert len(code_array) == c + 1, "Too Many Words!"
    for m in range(0, c):
        syntax[m] = code_array[m + 1]
    return


# Mother Class simple_machines with properties
class simple_machines:
    def __init__(self, obj, name, x, y, coords):
        self.obj = (
            obj
        )  # what type of obj, in this case, pulley
        self.name = name  # name, JohnThePulley
        self.x = x  # 3 in this case
        self.y = y  # 4 in this case
        self.coords = (x, y)  # (3,4) in this case
        return


# Pulley Class, here so I can later define special properties for a pulley
class pulley(simple_machines):
    def __init__(self, name, x, y):
        super(simple_machines, self).__init__()
        return


# Code that I tried
def insert(code):
    c = 4
    syntax = np.array([obj, name, x, y])
    nextword(parser.code_array, syntax, c)
    "{}".format(name) = "{}".format(obj)(
        name, x, y
    )  # this is what my
    # instantiation would look like, formatting an object with name, then
    # calling a class formatted with obj, and inserting their input of
    # name,x,y as the properties
    return

I expect an object in pulley to be created with the name JohnThePulley, and the coordinates X = 3 and Y = 4. What I'd like to result in, in simpler terms, is an object called name in a class called obj with the attributes name.x, name.y, etc

However, I get errors like:

NameError: name 'obj' is not defined

or:

SyntaxError: can't assign to function call

The first one apparently means that the word obj isn't being assigned, but the second one apparently means that I can't format a function name or format a variable name and define it as a function (even though I'm instantiating it as a class).

What am I doing wrong? How can I fix this?


Solution

  • name 'obj' is not defined is because obj is defined in another function. You have to use MYOBJECT.obj, not obj alone, and also keep a reference to MYOBJECT.

    '{}'.format(obj)(name,x,y) doesn't mean anything, '{}'.format(obj) is a string and isn't callable.

    SyntaxError: can't assign to function call is the actual problem you seem to be interested in. You could do globals()['{}'.format(name)] = stuff but it doesn't work for local variables and objects (and your linter is not going to like it).

    If you want to do the same for objects you can use setattr(MYOBJECT, '{}'.format(name), '{}'.format(obj))

    All of the solutions above are in technical terms considered "ugly" and what you're probably looking for is a dictionary, while it isn't OOP, dictionaries are used behind the scenes to handle exactly what you want to do with objects. An object without methods is essentially a just dictionary.

    mydico = dict()
    mydico[name] = obj
    

    Also, if name is a string, then '{}'.format(name) is equivalent to name.