1

I'm writing a script in Maya and trying to assign a variable inside another method instead of inside __init__ like we normally do. I put my window commands inside the __init__ so when a new instance is initialized, if we assign variables inside __init__ it will run all the way through without assigning the variables the value I want.

For example:

    def __init__(self, windowID = 'selectsomething', title = 'select something'):
        self.windowID = windowID
        self.title = title

        if cmds.window(self.windowID, exists = True):
            cmds.deleteUI(self.windowID)
                    
        myWindow = cmds.window(self.windowID, title = self.title)
        cmds.rowColumnLayout(numberOfColumns = 2, columnWidth = [(1, 300), (2, 100)],
                             columnAttach = [1, 'left', 10], columnSpacing = [1, 10],
                             rowSpacing = [1, 5])
        cmds.button(label = "Apply", command = self.applyButton) #it should print out selected object
        cmds.button(label = "Cancel", command = self.cancelButton)
        cmds.showWindow(myWindow)

        #now for example if I have a sel variable to store selected objects, it would actually return nothing cuz the code ran all the way through and didnt wait for me to select what I needed
        sel = cmds.ls(selection = True) #this will return nothing

My solution is to assign variables inside the applyButton method, which will store what I selected. I found it's a bit weird to call a method which uses a variable from another method from that method itself.

For example:

class Abc:
    def func(*arg):
        print(self.var)
    
    def var(self):
        self.var = 1
        self.func()
        
abc = Abc()
abc.var()

For now the code runs, but doesn't it sound a bit weird to call the func method which uses the variable from var method from var method itself?

I haven't seen anyone do it. I mean without class, a variable assigned inside a function stays inside that function and we can only use it with return. But it looks like in class we can make any inside-method-variable global by adding self. before it?

My friend also said we can use @property in this case but I don't think I figured it out yet.

Community
  • 1
  • 1
slovik
  • 67
  • 7
  • 1
    No, this isn't strange at all. This is the *whole point* of using a class, to encapsulate shared state. Note, it *isn't* global. – juanpa.arrivillaga Jan 07 '20 at 05:06
  • Hmm that does make me feel better, thank you @juanpa.arrivillaga. Can you explain a bit more on 'encapsulate shared state'? And btw, when you said 'it isn't global.' did you mean the variable actually belongs to the instance not the global? Thank you!!! – slovik Jan 07 '20 at 06:36
  • 1
    You are using a class method mixed with an instance variable what could be strange. e.g. if you do Abc().func() it will fail. But indeed, you can simply set an self.variable anywhere. In most cases I initialize it with None in the init and check if they are valid before I use them. – haggi krey Jan 07 '20 at 08:55
  • Didnt I use instance method? And thank you @haggikrey for your advices (y) – slovik Jan 07 '20 at 09:10
  • 1
    If you define a method like this func(args) in a class it will become a class method, an instance method is defined func(self, args) what you have done correctly in your var method. – haggi krey Jan 07 '20 at 11:37
  • 1
    @haggikrey No, a class method is defined if you decorate it with the `@classmethod` decorator. `func(*arg)` is still an instance method; the invoking instance is just accessed via `arg[0]` rather than the name `self`. – chepner Jan 07 '20 at 17:10
  • Oh, yes, thanks for clarifying. – haggi krey Jan 07 '20 at 17:39
  • Thank you @chepner for pointing it out :D – slovik Jan 08 '20 at 02:38

1 Answers1

1

You need to be aware that data attributes are implicitly a member of the class and can therefore be used by any method in the same class after they have been assigned somewhere.

From the Python documentation:

Data attributes need not be declared; like local variables, they spring into existence when they are first assigned to.

While your example will work (if you call Abc.var() before Abc.func()), it would IMHO be better style to initialize the variable at class level like this (note that I call it val to avoid confusion with the method name):

class Abc:
    val = 0

    def func(self, *arg):
        print(self.val)

    def var(self):
        self.val = 1
        self.func()

The purpose of the self keyword is nicely explained here and here.

Also note that initializing an attribute inside the __init__ method will bind this attribute to a class instance, whereas initializing it outside of the __init__ method will bind it to the class itself, which is a different thing (see this discussion).

Gerd
  • 2,568
  • 1
  • 7
  • 20
  • Oh thank you so much @Gerd, I didn't notice that initializing an attribute inside and outside ```__init__``` can make a whole difference like that. And thank you for the info, helped me a lot!!! – slovik Jan 08 '20 at 03:42