apply changes to running instance of a class from another class - python

Some weeks ago I had to simplify a program drastically, because I couldn't find a solution for this probably simple problem.
Now I'm stuck at the same issue again and hope somebody can help me to fix it.
I'm using PyQt5 and started a QWidget out of my main class Class_One, from which I opened a second class Class_Two with the following lines.
def on_create_search(self):
self.search_form = Class_Two()
self.search_form.show()
In Class_Two I save changes to a JSON file, which should also effect a dictionary and a visible QTreeWidget from Class_One.
So what I want to do is, to execute a method in Class_One, triggered by Class_Two, just as it was called from the running instance of Class_One.
The called method should read in the JSON file and apply the changes to the data and the GUI of the running instance of Class_One.
Calling such a method from another instance of Class_One didn't help me out, because the changes have to be applied to my running class instance of Class_One.
Perhaps there is an even better way, so I'm open for any suggestions.

Use callback.
class Class_One:
def callback(self, arg1, arg2):
# code you want
def on_create_search(self):
self.search_form = Class_Two()
self.search_form.show(self.callback)
class Class_two:
def show(self, callback):
# original code
callback(arg1, arg2)

Related

Python/Tkinter: role of init / super in writing tkinter widgets as classes

In writing a tkinter root window as a class, I'm using the following code:
class RootWin(Tk):
def __init__(self,...args go here...):
super().__init__()
Although the code is correct, and works, I am uncomfortable writing code that I don't fully understand, and despite the many explanations I have come across, none have clarified this for me.
I understand that the line class RootWin(Tk): indicates that I am creating a class called RootWin that inherits from Tk. In the next line, self refers to the instance of this class I will create later in my code, and the args specify the parameters I want to pass to this specific instance. That much is very clear.
Then, the explanations I've come across indicate that super().__init__() runs the init method of Tk (the parent class).
But why is it necessary to run the init method of the Tk class? If class RootWin(Tk) already indicates that my new RootWin class inherits from Tk, then why would anything more be required?
Perhaps the best way to pose this question is to ask it in three explicit parts, and request three answers, with apologies, if that's asking a lot. I really want to understand this!
Question 1: What is accomplished by the line
class RootWin(Tk):
Question 2: What is accomplished by the line
def __init__(self,...args go here...):
Question 3: what is accomplished by the following line that has not already been accomplished by the two previous lines?
super().__init__()
Any advice appreciated.
But why is it necessary to run the init method of the Tk class?
Your own class has some initialization it performs, correct? There is code in your __init__ that must run for your class to be useful. This is where, for example, you would create other widgets for your app, variables, etc.
The tkinter base classes are the same way. They have code in their own __init__ method that must be run for the class to be useful. This code doesn't run automatically if you create your own __init__. Therefore, you must call it so that the widget is properly initialized.
Question 1: What is accomplished by the line class RootWin(Tk):
Answer: it begins the definition of a new class name RootWin that inherits from the class Tk
Question 2: What is accomplished by the line def __init__(self,...args go here...)
Answer: it defines a method that is automatically called by python when you create an instance of your custom class. It also defines the arguments that your function may require.
When you do foo = RootWin(), python will automatically call RootWin.__init__ and pass in the instance (self) as the first argument. The rest are to be supplied by the caller.
Question 3: what is accomplished by the following line that has not already been accomplished by the two previous lines? super().__init__()
Answer: First, it has not been accomplished by the two previous lines. Because of the two previous lines, python will not automatically call the __init__ method of the base class. That responsibility becomes yours when you define a custom __init__. When you call super().__init__() you are explicitly requesting that the __init__ method of the base class be called.
The advantage to requiring you to explicitly call it is that you now have a choice of when or if to call it. While you almost always should, you might choose to do some custom initialization either before or after the base class has been initialized.
Note that none of this is unique to tkinter. This is how all python objects work.

Python when to use instance vs static methods

I am struggling to understand when it makes sense to use an instance method versus a static method. Also, I don't know if my functions are static since there is not a #staticmethod decorator. Would I be able to access the class functions when I make a call to one of the methods?
I am working on a webscraper that sends information to a database. It’s setup to run once a week. The structure of my code looks like this
import libraries...
class Get:
def build_url(url_paramater1, url_parameter2, request_date):
return url_with_parameters
def web_data(request_date, url_parameter1, url_parameter2): #no use of self
# using parameters pull the variables to look up in the database
for a in db_info:
url = build_url(a, url_parameter2, request_date)
x = requests.Session().get(url, proxies).json()
#save data to the database
return None
#same type of function for pulling the web data from the database and parsing it
if __name__ == ‘__main__’:
Get.web_data(request_date, url_parameter1, url_parameter2)
Parse.web_data(get_date, parameter) #to illustrate the second part of the scrapper
That is the basic structure. The code is functional but I don’t know if I am using the methods (functions?) correctly and potentially missing out on ways to use my code in the future. I may even be writing bad code that will cause errors down the line that are impossibly hard to debug only because I didn’t follow best practices.
After reading about when class and instance methods are used. I cannot see why I would use them. If I want the url built or the data pulled from the website I call the build_url or get_web_data function. I don’t need an instance of the function to keep track of anything separate. I cannot imagine when I would need to keep something separate either which I think is part of the problem.
The reason I think my question is different than the previous questions is: the conceptual examples to explain the differences don't seem to help me when I am sitting down and writing code. I have not run into real world problems that are solved with the different methods that show when I should even use an instance method, yet instance methods seem to be mandatory when looking at conceptual examples of code.
Thank you!
Classes can be used to represent objects, and also to group functions under a common namespace.
When a class represents an object, like a cat, anything that this object 'can do', logically, should be an instance method, such as meowing.
But when you have a group of static functions that are all related to each other or are usually used together to achieve a common goal, like build_url and web_data, you can make your code clearer and more organized by putting them under a static class, which provides a common namespace, like you did.
Therefore in my opinion the structure you chose is legitimate. It is worth considering though, that you'd find static classes more in more definitively OOP languages, like Java, while in python it is more common to use modules for namespace separation.
This code doesn't need to be a class at all. It should just be a pair of functions. You can't see why you would need an instance method because you don't have a reason to instantiate the object in the first place.
The functions you have wrote in your code are instance methods but they were written incorrectly.
An instance method must have self as first parameter
i.e def build_url(self, url_paramater1, url_parameter2, request_date):
Then you call it like that
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
This self parameter is provided by python and it allow you to access all properties and functions - static or not - of your Get class.
If you don't need to access other functions or properties in your class then you add #staticmethod decorator and remove self parameter
#staticmethod
def build_url(url_paramater1, url_parameter2, request_date):
And then you can call it directly
Get.build_url(url_paramater1, url_parameter2, request_date)
or call from from class instance
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
But what is the problem with your current code you might ask?
Try calling it from an instance like this and u will see the problem
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
Example where creating an instance is useful:
Let's say you want to make a chat client.
You could write code like this
class Chat:
def send(server_url, message):
connection = connect(server_url)
connection.write(message)
connection.close()
def read(server_url):
connection = connect(server_url)
message = connection.read()
connection.close()
return message
But a much cleaner and better way to do it:
class Chat:
def __init__(server_url):
# Initialize connection only once when instance is created
self.connection = connect(server_url)
def __del__()
# Close connection only once when instance is deleted
self.connection.close()
def send(self, message):
self.connection.write(message)
def read(self):
return self.connection.read()
To use that last class you do
# Create new instance and pass server_url as argument
chat = Chat("http://example.com/chat")
chat.send("Hello")
chat.read()
# deleting chat causes __del__ function to be called and connection be closed
delete chat
From given example, there is no need to have Get class after all, since you are using it just like a additional namespace. You do not have any 'state' that you want to preserve, in either class or class instance.
What seems like a good thing is to have separate module and define these functions in it. This way, when importing this module, you get to have this namespace that you want.

Keeping classes loosely coupled and sharing data

I've been working in python on a project where I have a GUI which I split up a bunch of the work between classes. I don't know a lot of the best practices for passing data around between classes, and I've frequently run into the issue, where I have to implement something, or change something for work, and I've resorted to making a lot of the classes objects of another class in order to give it the data I need.
Any ideas or suggests would be greatly appreciated on how to keep my classes independent for later modification and still pass the relevant data around without affecting interfaces too much?
As an example
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork(Window):
def __init__(self, parent=None):
self.parent=parent
I often find myself doing stuff like the above giving objects to class Window
or simply inheriting everything from them as in ParseMyWork
There must be better and cleaner ways of passing data around without making my classes utterly dependent on eachother, where one little change creates a cascade effect that forces me to make changes in a bunch of other classes.
Any answers to the question don't necessarily have to be in python, but it will be helpful if they are
If I'm understanding your question correctly, I would say that inheritance is not necessary in your case. Why not give ParseMyWork a function for dealing with a specific Window task?
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork():
def __init__(self, parent=None):
self.parent=parent`
def doWindowActivity(self, window):
window.doStuff
Then you can use the function like this
work_parser = ParseMyWork()
window = Window()
work_parser.doWindowActivity(window);
That way you can use your work_parse instance with any window instance.
Apologies in advance for my Python, it's been a while so if you see any rookie mistakes, do point them out.
Keep it simple.py:
def doStuff(window):
#do work here
return window
def parseStuff(stuff):
pass
really.py:
from simple import doStuff, parseStuff
def really_simple(window):
okay = doStuff(window)
return parseStuff(okay)
don't complicate the class:
from really import really_simple
really_simple(window)
imo: classes are overly complicated objects, and in a lot of cases more confusing than they need to be, plus they hold references and modify stuff, and can be difficult to decouple once they have been tied to other classes. if there isn't a clear reason why a class needs to be used, then it probably doesn't need to be used.
Classes are super powerful, so it's good you're getting started with em.
Discalimer: Haven't worked in python for a while now, so things might not be exact. The general idea still applies though.
Getting into your question now:
I would say the best way to achieve what you want is to create an instance of the first object where you will extract information from.
Now when creating a class, it's vital that you have attributes within them that you will want to be stored within it that you would like to retrieve once the class is instantiated.
For example, using your Window class example above, let's say that you have an attribute called resolution. It would look something like this:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
Now the resolution information associated with your Window class is forever part of any Window class instance. Now, the next step would be to create a get method for resolution. This should be done as follow:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
def getResoultion():
return self.resolution
Now, the reason we created this get method is because we can now set a variable to the information that is returned with it.
So let's say that you have everything associated with your Window class in its own file (let's say the file name is called Window.py). In a separate file (let's call it main.py), you can do the following:
import Window
windowInstance = Window()
windowResolution = windowInstance.getResolution()
If you print out the variable windowResolution, you should get that 40x80 printed out.
Now, as a side note, I do believe it is possible to get the information associated with an attribute with an instance of a class by simply doing something like
windowResolution = windowInstance.resolution
but that is bad practice in general. The reason, in a nutshell, is because you are now exposing attribute names of your class which you do not want to do because it makes it easy for a person outside of your code to learn the name where that information is held and change it. This can then lead to a myriad of other problems when it comes to making an overall program work. That is why it is best practice to use getters and setters. I already showed what getters are. Simply a get method for attributes. Setters, as you can probably assume, allow for one to set the information of an attribute to something else. Now you might say "Gabe, if we can create setter methods, what's the point of it if they just change it". My answer to that is to not give a setter method to all attributes. For attributes you don't mind for a person to change, give it a setter method, but for attributes you do not want any outside users to touch, simply don't create a setter method for it. Same goes with getter methods too. Users don't need to see all of the information of all attributes that makes your program work. Here's a better explanation: https://en.wikipedia.org/wiki/Mutator_method
Now, back to your example. Now let's say you have your ParseMyWork class in its own file like we did with your Window class, and let's say that ParseMyWork needs the resolution info from Window class. You can do the following :
import Window
import ParseMyWork
windowInstance = Window()
windowResolution = windowInstance.getResolution()
parseInstance = ParseMyWork(windowResolution)
This will only pass the window resolution information associated with your Window class. Hope this helps.

python subprocess Process target function won't instantiate classes

I am trying to launch several operations in parallel using subprocess.Process. The problem I am having is that if I try to instantiate an instance of my class in the target function nothing happens. But, if I instantiate the classes first and pass the instances to the target function then everything works. Here is an abstraction of what I am doing
Instantiate before launching Process: everything works
def spawn(my_class_instance):
my_class_instance.launch()
for params in my_list_of_parameters:
an_instance = MyClass(params)
Process(target=spawn, args=(an_instance)).start()
Instantiate inside target function: doesn't work
def spawn(params):
an_instance = MyClass(params)
an_instance.launch()
for params in my_list_of_parameters:
Process(target=spawn, args=(params)).start()
I'd really like to understand more about why it doesn't work to try to instantiate classes inside the target function. Is it related to immediately calling Process.start()? What is happening under the hood that is preventing this?
One thing that might be causing this is that each MyClass.launch() itself calls subprocess.Popen(..., shell=False), in case this might be the reason. If so, why? It still gets called in the first case.
Thanks!
This works. Still, I may be something in your question.
from multiprocessing import Process
class MyClass:
def __init__(self, params):
pass
def launch(self):
print "method launch is called"
def spawn(params):
an_instance = MyClass(params)
an_instance.launch()
my_list_of_parameters = ['1', '2']
for params in my_list_of_parameters:
Process(target=spawn, args=(params)).start()

wxPython cannot call function in main class from subclass

I am having difficulties in trying to get a function in a separate class. I have a main class with a few functions, one of which is reset:
class GUI(wx.Frame):
[GUI STUFF HERE]
def reset(self):
self.data = [0]
Within that class i also have before the subroutines to initiate another class:
self.controlPanel = controlPanel(self.panel)
Which initiates another class which is a staticbox with buttons. Within that class I have a function bound to a button event:
def reset(self, event):
GUI.reset()
where the function "reset" is in the main GUI class. I get an error when i try to call reset in the main class, yet I can do it the other way round. Why is this and how can I fix it? I want button events in child classes to call a function in the parent class.
Thanks in advance.
"GUI" is not defined in "controlPanel", you want to call the method of the instance of "GUI".
One way would be to do the following in your button handler:
self.GetParent().reset()
Depending how complex your application this might get out of hand as it will no longer work if you insert another layer in between GUI and controlPanel.
You might want to look into using 'wx.lib.pubsub' and in your controlPanel use 'pub.sendMessage' and in your GUI use 'pub.subscribe'.
wxPython Phoenix pubsub doc
pubsub's doc

Categories