1

I have found myself using a lot of global variables in order to access user input (e.g. a file path) but I know this is bad practice and will likely lead to spaghetti code in the end.

How can I better organise this application without global variables so that I can make use of variables that are set within the GUI through button presses etc?

I've tried global variables, which do work, but will probably lead to bad habits forming, without these I get errors regarding variables being out of scope and undefined.

The application works so far when everything is within one .py file but now that it is growing and I want to split it up into a proper structure I am struggling.

I want to be able to use variables from within a method tied to my GUI so that I can split the application up into multiple files rather than having it all within one file which doesn't seem practical or good practice. I'm not sure if it would be better to use classes instead or if there is a better approach for what I am trying to achieve.

spaghetticode
  • 485
  • 1
  • 4
  • 8
  • 1
    You can use classes, that is one way to avoid global mutable state. The other is to simply always pass data as arguments to your function and return data from functions. Without more details, I don't think one can give more concrete advice – juanpa.arrivillaga Feb 11 '19 at 19:23
  • 1
    Possible duplicate of [How to make a cross-module variable?](https://stackoverflow.com/questions/142545/how-to-make-a-cross-module-variable) - I went looking for this after I wrote my answer - if this question gets closed as a dupe, I'll delete my answer or mark as *community wiki*. – wwii Feb 11 '19 at 19:58
  • for consideration: https://stackoverflow.com/q/3338283/2823755 – wwii Feb 11 '19 at 20:04

3 Answers3

1

If you have names/variables that you know about in advance, put them all in a single module then import that module's contents into all your other modules. Maybe one of the variables in that module can be a dictionary that holds some stuff or can be added to as the program executes.


tmp.py:

foo = 'bar'

b.py:

import tmp

def f():
    return tmp.foo

a.py:

import tmp, b

print(b.f())
tmp.foo = 'ICHANGED!!'
print(b.f())

>>>
bar
ICHANGED!!

This works. the name/variable foo is defined/assigned in tmp.py; then it is imported into a.py and b.py. a changes foo and the function in b sees the change.

wwii
  • 23,232
  • 7
  • 37
  • 77
1

What you need to do here is look into OOP or object oriented programming.

With OOP, you can define self.whatever = something and that variable will be accessable the way you want it.

A good place to look into OOP is here.

Legorooj
  • 2,646
  • 2
  • 15
  • 35
  • I have done OOP in C++ and Java, I had thought there were other ways to do things in Python since a lot of threads I had read on here talked about avoiding OOP in Python but I may have to reconsider. – spaghetticode Feb 11 '19 at 18:58
  • 1
    @MLBeginner it is essentially impossible to "avoid" OOP in Python, python is purely object-oriented language: *everything* is an object. What you may have heard is that you don't always have to write a class definition for everything. – juanpa.arrivillaga Feb 11 '19 at 19:24
1

Yes, creating a class seems best.

class CSVProccessor(object):
    def __init__(self, csv_file_path=None):
        self.csv_file_path = csv_file_path
        self.df = None

    def csv_open(self):
        self.csv_file_path = filedialog.askopenfilename()

    def csv_display(self):
        window2 = Toplevel() 
        csv_frame = Frame(window2)
        csv_frame.pack(fill=BOTH, expand=1)
        self.df = pd.read_csv(self.csv_file_path)
        window2.table = csv_view = Table(csv_frame,
                                         dataframe=df,
                                         showtoolbar=False,
                                         showstatusbar=False)
        csv_view.show()

    def pre_processing_split(self):
        np.random.seed(11)
        self.df = pd.read_csv(self.csv_file_path)

csv_processor = CSVProcessor()
csv_processor.csv_open()
# ...etc...
mVChr
  • 49,587
  • 11
  • 107
  • 104
  • In this case, if I use a button to allow a user to choose a file location in the directory, will this not only update the file path within csv_open()? How will I then get that to be accessed within pre_processing_split() without needing the user to select the path again? – spaghetticode Feb 11 '19 at 19:00
  • Attach as an attribute of `self` as shown. – mVChr Feb 11 '19 at 19:01
  • 1
    I hadn't seen the further edit or missed it the first time, thank you. I will work on this, I think (hope) it will have solved my problem – spaghetticode Feb 11 '19 at 19:03