Returning an class instance from a function

Hello,

I am working on a little “plugin” for a software, I am trying to put in application all the python I learnt here.
I have some issues with the “programmatically generation” of an instance of my class:

index = 0
naming = ["node_plugin_"+ str(index) for i in range(100)]
start_call = False


def start():

    #This function is launch when the user select the name of the plugin in the pull down menu.
    #A popup will appears and ask to the user some variables

    global start_call
    start_call = True

    #user input with popup
    var01 = "/my/path/my/file"
    var02 = "Cycle"
    var03 = "Additive"


    class Plugin:
        def __init__(self, var01, var02, var03, index):
            self.var01 = var01
            self.var02 = var02
            self.var03 = var03
            self.index = index

        def my_function(self):
            print(self.var01)


    instance_Plugin = Plugin(var01, var02, var03, index)

    return instance_Plugin, start_call


#To check if the user call the plugin
if start_call == True:
    naming[index], start_call = start()


print(start_call)
>>>False
start()
print(start_call)
>>>>True
a = naming[index].var02
print(a)
>>> AttributeError: 'str' object has no attribute 'var02'
print(naming[index].my_function())
>>>AttributeError: 'str' object has no attribute 'my_function'

naming[index] should be associated with the return value of start(), in this case instance_Plugin, no?
To summarise, I don’t know how to associate a variable in the global scope to an instance class generated in a function.

no. look:

if start_call == True:
    naming[index], start_call = start()


print(start_call)

as you can see, start_call is false, so this:

naming[index], start_call = start()

never happens, given if the condition evaluates to False. So you never update the string in the list with the class instance/object

If you would print naming:

print(naming)

you will see the list still consists of "node_plugin_0" only

2 Likes

Thank you, indeed, I fixed the list comprehension to have an incrementation:

naming = ["node_plugin_"+ str(i) for i in range(3)]
print(naming)
>>> ['node_plugin_0', 'node_plugin_1', 'node_plugin_2']

But, for the condition, when the user call the function Start(), the global variable start_call become True:

print(start_call) #Function start is not called yet
>>>False
start() #call of the function start() by the user
print(start_call)
>>>>True

What I don’t understand is, the instance created in the function Start():

instance_Plugin = Plugin(var01, var02, var03, index)

when I return it with:

return instance_Plugin, start_call

It looks like I have no acces to it at a global scope:

naming[index], start_call = start()

I don’t know how to associate my instance to a name from my list (instance_Plugin become node_0)

Take a look at the order which you do things, first you attempt to update a list element while the call hasn’t started:

if start_call == True:
    naming[index], start_call = start()

so the if condition evaluates to false, so naming array does not get updated/code in the body of the if clause doesn’t get executed.

then you start the call. But now you do no update the naming list anymore.

2 Likes

So, I added one line for the return values of my function start()

index = 0
naming = ["node_plugin_"+ str(i) for i in range(3)]
start_call = False

def start():

    global start_call
    start_call = True

    #user input avec popup
    var01 = "/my/path/my/file"
    var02 = "Cycle"
    var03 = "Additive"


    class Plugin:
        def __init__(self, var01, var02, var03, index):
            self.var01 = var01
            self.var02 = var02
            self.var03 = var03
            self.index = index

        def my_function(self):
            return self.var01


    instance_Plugin = Plugin(var01, var02, var03, index)

    return instance_Plugin, start_call

naming[index], start_call = start()

if start_call == True:
    naming[index], start_call = start()



print(start_call)
start()
print(start_call)
a = naming[index].var02
print(a)
print(naming[index].my_function())
print(hasattr(naming[index],"var03"))
print(getattr(naming[index], "var03"))

or this way:

index = 0
naming = ["node_plugin_"+ str(i) for i in range(3)]
start_call = False

#for node in nuke.allNodes():
    #if "AUTO_BEAUTY_" in node["name"].value():
        #if int(node["name"].value()[12]) >= index:
            #index = int(node["name"].value()[12]) + 1


def start(start_Call):

    start_call = True
    var01 = "/my/path/my/file"
    var02 = "Cycle"
    var03 = "Additive"

    return start_call, var01, var02, var03

start_call, var01, var02, var03 = start(start_call)


class Plugin:
    def __init__(self, var01, var02, var03, index):
        self.var01 = var01
        self.var02 = var02
        self.var03 = var03
        self.index = index

    def my_function(self):
        print(self.var01)

if start_call == True:
    naming[index] = Plugin(var01, var02, var03, index)

print(start_call)
print(naming[index].var01)

Is one better than the other? I know using global variable is not recommanded.

For the value of index, there will be a code block to check if there s no other node of this plugin already in the file:

for node in nuke.allNodes():
    if "AUTO_BEAUTY_" in node["name"].value():
        if int(node["name"].value()[12]) >= index:
            index = int(node["name"].value()[12]) + 1

avoid using the global keyword when-ever possible, functions that modify global variable become a mess to track

1 Like