Is there a way to assign variables in __init__ without having them run immediately?

So I was trying to write a program that converts various metric units to other units. (i.e. Cm to Mm) My Professor was adamant about not using globals and having all of our code be in either a function or a class. With the code as shown below, it gives me a:

ValueError  (*line 18, in __init__ self.intNtry = int(self.ntryAnswer) ValueError: invalid literal for int() with base 10: ''*)

Is there any way to have the variables not activate as soon as the program starts? I'm new to programming, please don't bully me

class Converter(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.txt = tk.Text(self, height=1, width=45)
        self.txt1 = tk.Text(self, height=1, width=45)
        self.txt2 = tk.Text(self, height=1, width=45)
        self.txt3 = tk.Text(self, height=3, width=45)

        self.unit1 = tk.Entry(self)
        self.unit2 = tk.Entry(self)
        self.num1 = tk.Entry(self)

        self.btn = tk.Button(self, text="Calculate", padx=15, pady=15, command=self.buttonClick)

        **self.ntryAnswer = self.num1.get()
        self.intNtry = int(self.ntryAnswer)**

        self.initWindow()

    def buttonClick(self):
        if self.unit1 == "cm" and self.unit2 == "m":
            ans1 = float(self.intNtry) / 100
            print(ans1)

Upvotes: 1

Views: 57

Answers (3)

chepner
chepner

Reputation: 531918

Your class doesn't need an intNTry attribute. The value returned by self.num1.get() isn't interesting until you are ready for it, namely when you actually click the button.

class Converter(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.txt = tk.Text(self, height=1, width=45)
        self.txt1 = tk.Text(self, height=1, width=45)
        self.txt2 = tk.Text(self, height=1, width=45)
        self.txt3 = tk.Text(self, height=3, width=45)

        self.unit1 = tk.Entry(self)
        self.unit2 = tk.Entry(self)
        self.num1 = tk.Entry(self)

        self.btn = tk.Button(self, text="Calculate", padx=15, pady=15, command=self.buttonClick)

        self.initWindow()

    def buttonClick(self):
        if self.unit1 == "cm" and self.unit2 == "m":
            answer = self.num1.get()
            entry = int(answer)
            ans1 = entry / 100
            print(ans1)

If there are multiple places where it would be interesting to retrieve the value (or if you just want to use more encapsulation), a property as suggested by @modesitt would be appropriate.

class Converter(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)

        self.txt = tk.Text(self, height=1, width=45)
        self.txt1 = tk.Text(self, height=1, width=45)
        self.txt2 = tk.Text(self, height=1, width=45)
        self.txt3 = tk.Text(self, height=3, width=45)

        self.unit1 = tk.Entry(self)
        self.unit2 = tk.Entry(self)
        self.num1 = tk.Entry(self)

        self.btn = tk.Button(self, text="Calculate", padx=15, pady=15, command=self.buttonClick)

        self.initWindow()

    @property
    def field1(self):
        return int(self.num.get()) / 100

    def buttonClick(self):
        if self.unit1 == "cm" and self.unit2 == "m":
            print(self.field1)

Upvotes: 2

Harry Jones
Harry Jones

Reputation: 342

You could always assign that variable to None and then create an additional method which sets it:

def __init__(self, parent):
   self.intNtry = None

def foo(self):
   self.intNtry = int(self.ntryAnswer)

Upvotes: 0

modesitt
modesitt

Reputation: 7210

Use property

class Converter(Frame):
    ...
    @property
    def intNtry(self):
        ntryAnswer = self.num1.get()
        return int(self.ntryAnswer)

which will dynamically evaluate when .intNtry is called. There is no reason to store this variable though - .self.num.get() can be called when you need the value during buttonClick. In general though, computed properties should use @property.

Upvotes: 1

Related Questions