Variations on python class implementation where instances interact
I've written three versions on my menu system class. They where:
class Menu(object)
The menu instances are stored in __dict__. I refer to menu data with self.data.
class Menu(dict)
The menu instances are stored in the dict subclassed by my class. I refer to menu data with self[data].
class Menu(object)
The menu data is stored in a cls.data dict that I establish in __init__(). The class is mostly a method container and I don't benefit from the instance member features.
Each has their positive and negative aspects but they all smell bad. I think what I have learned is that if you develop a class where one instance has to be able to interact with another instance, the schema falls apart since one method may need to transition between instances.
For example, if I have a front panel LCD with a Main Menu screen and four hotkeys to select other menus, some methods will need to be able to navigate across instance boundaries and this is totally kicking my butt. When something is this unpleasant, it usually means that there is something important to learn. So, can any of you help me out? How can you best write code where instances interact within a method?
Main Menu
Port Network Device
Setup Setup Setup Next>
When I push the button under Port Setup, the Menu class needs to switch its instance from the Main Menu instance to the Port Setup instance using a method that belongs to the class/instance. But how?
Port Setup Menu
Baud Stop Parity Protocol
Rate Bits Bit Address
Related
I am new to socket programing and SW architecture.
My system must be : a GUI in my laptop using python. There are many embedded systems with same sensors ( GPS, Temperature, pressure ...). Each time you select an embedded system, my program needs to establish a connection with it , I need to show its GPS position and the real time feed of its sensors in the GUI ( For now the GUI is not the problem, I can do with Kivy or Tkinter).
This is how it must function :
In the GUI, there is a field to enter the ID of embedded system and a button to try to connect with it.
When the button is clicked, the program establishes connection and shows GPS, Temperature and pressure in real time continuously until connection is lost.
I was thinking of doing it with this architecture :
A thread to deal with the GUI
Each time a button is clicked and an embedded system is found, an object of a class I created is instantiated.
The class has as attributes :
list GPS ( to store GPS feed)
list temperature ( to store Temperature feed)
list pressure
a thread_socket ( the socket is created in a thread to be a client to the embedded system. So each time an object is instantiated of the class, a separate socket is create )
The class has as methods :
Get_Gps() : Each time this method is called the GPS list attribute is updated
Get_Temperature() / Pressure()
Stop() : When this method is called the embedded system needs to shutdown.
In the socket thread, I have methods such as send_message() and receive_message() to send through TCP/IP the request for getting GPS and sensor data or stopping the system.
On each embedded system I will put a server using python that is set up everytime the system starts.
This way the ID of the system is the ip of the server, And my laptop would be a client, searching for the ip adress when I select a system.
My questions are :
Does this architecture seem alright to you ?
Is it correct to receive real time feed in a list ? for example for the gps.
Each time I find a system I instanciate an object to keep things clean, is this a good way to do it?
Do you see any issues or improvements ?
Thank you in advance,
I think your approach in general is fine.
However, you should keep a few things in mind:
When designing your software, you should first identify the different tasks involved and define separate functional units for each task. This is the concept of separation of concerns.
I also suggest to read a bit on the Model-View-Controller (MVC) pattern: In your case, the model would be your class containing the data structure for the measurements and the business logic (e.g. polling data from a source for example every second until the connection is stopped). The view and the controller might both be located in the GUI (which is absolutely fine).
The GUI is not necessarily an explicit thread, but many frameworks rather work with an event-based concept that lets you define the application's behavior for a given user interaction.
Why do you actually need lists for the measurements? Is there a requirement to keep the history of measurements over a certain period of time? Is this a list that will keep growing and growing or rather a rolling list (e.g. for showing the last n seconds/minutes of measurements in the GUI)? There seems a bit of a contradiction to starting a new class instance with every new connection, because you would obviously loose the contents when you stop the connection and terminate the instance.
Hope this gives you some ideas of how to proceed from there.
I have a program that contains two main classes:
A GUI class that inherits from QWidget, and has several user input and output fields (graphs, spin boxes etc.)
A Serial Monitor class that inherits from QObject and contains various loops for continuously polling serial attached devices in accordance with a set of parameters (sample period, polling commands, etc.)
An instance of the Serial Monitor class is created from within the GUI class and moved to a secondary thread like so:
# Create Serial monitor instance in this thread
self.serial_monitor = Serial_Monitor(
formatter=self.poll,
prompt="2 poll\n")
# Create a secondary QThread to run the serial monitor
self.serial_thread = QThread()
# Move the serial monitor to the secondary thread and start
self.serial_monitor.moveToThread(self.serial_thread)
self.serial_thread.start()
My question arises when trying to directly pass the output of user interface items (spin boxes, buttons etc.) to variables in the Serial Monitor. My main aims are:
I want to avoid creating several pyqtSlot functions in the Serial Monitor just to set each variable, as it makes adding further variables a faff and bloats the code.
I would also like to keep all setting of Serial Monitor variables in the correct thread, rather than setting them in the GUI command thread.
My initial solution to directly setting variables from the GUI was this:
self.set_box_period.valueChanged.connect(
lambda val: setattr(self.serial_monitor, "sample_period", val))
It avoids creating any new methods in the Serial Monitor, and appears to set the variables just fine, however I am not sure if it is "thread safe", and further more am not sure how to find out.
After some digging I found out that you can re-implement the __setattr__ method within a class like so:
#pyqtSlot()
def __setattr__(self, name, value):
"""
------------------------------------------------------------------------
Re-implementation of "getattr" method to correctly wire up to slots
------------------------------------------------------------------------
"""
self.__dict__[name] = value
self.logger.info(F"Set {name} to {value}")
The logging output indicates that every Serial Monitor variable is set within the Serial Monitor thread, so this solution does work, however I am not sure if it is necessary.
To sum up, do I need to worry about re-implementing __setattr__ in my Serial Monitor class, or is my initial lambda implementation perfectly safe to use?
Thanks in advance!
I am rookie to Python threading and am looking for guidance on how to implement mulithreading on an application with two classes, GUI and weblogic that need need to run in parallel.
The GUI class is all about user interaction and will have code like "if you click here run this weblogic method." The GUI must be in its own thread because the weblogic method can be slow and so waiting for it to complete will cause the GUI to seem unresponsive. The good news is that GUI code has no ability to modify any data inside the weblogic thread and so locking is not an issue. (The GUI just calls a weblogic method with the appropriate variables and then processes the resulting output.)
The web logic class includes multiple methods and constructors and some of the methods can be time consuming to run. The class also includes constructors that are vital to all the methods in the class. (Think userid, password, API access url and the like)
So what I am looking to implement is a way to instantiate the two threads in parallel. Hence, the GUI would run in its own thread and issue commands to the weblogic thread which would respond accordingly.
I started looking at the Threading module and while I have gotten it to work for simplistic functions, I have not been successful in running an entire class inside a thread. Since I am new to all of this, I am looking for guidance on the right strategy. Should I even be using Threading? Is there better approach?
Here is some pseudo code to illustrate what I am trying to accomplish:
GUI Code:
class GUI():
def createGUI(self):
# create GUI layout here
def button1(self):
# if clicked
outputtodisplay = weblogic.filelist()
# display outputtodisplay
def button2(self)
# if clicked assume that we have a file selector box which provides a filename
weblogic.uploadfile(filename)
# show an upload success indicator
Weblogic:
class weblogic():
def __init__(self, count, instance):
# run some stuff to setup
self.uid = xxx
self.pwd = yyy
self.url = zzz
def listfiles():
# get file list using uid, pwd, url
return output
def uploadfile(self,filename):
# upload file using uid, pwd, url
return success/failure
By designing a GUI for my python script which works with PySerial for implementing some serial interface functions I want to have shown up some parameters reading out a source.
So this GUI for example has to show the actual voltage which is represented by the parameter volt_act.
I thought that I can connect the QLCDNumber lcdVoltage with the following code:
self.connect(self, QtCore.SIGNAL("selfVoltage"), self.lcdVoltage, QtCore.SLOT("display(int)"))
And at the point I want to read the voltage I emit the parameter:
self.emit(QtCore.SIGNAL("selfVoltage"), volt_act)
But that doesn't work. How can I correctly implement a QLCDNumber where the parameter is updated in real-time when I emit it?
From docs:
Short-circuit signals do not have a list of arguments or the
surrounding parentheses.
Short-circuit signals may only be connected to slots that have been
implemented in Python. They cannot be connected to Qt slots or the
Python callables that wrap Qt slots.
You need to declare the variable type explicitly, if you intend to use Qt slots:
self.connect(self, QtCore.SIGNAL("selfVoltage(int)"), self.lcdVoltage, QtCore.SLOT("display(int)"))
and
self.emit(QtCore.SIGNAL("selfVoltage(int)"), volt_act)
But, I'd really suggest you to use the new style signals.
First, you'd define a signal as class variable:
voltage = QtCore.pyqtSignal(int)
then connect it:
self.voltage.connect(self.lcdVoltage.display)
and finally, you'd emit:
self.voltage.emit(volt_act)
I have two coupled classes DhcpServer and SessionManager. I got the following requirements in my specs that led to that coupling:
DhcpServer must not issue an IP address lease if SessionManager forbids that (e.g. an error occurred while creating a session)
SessionManager must start a session upon creation of a new lease by DhcpServer and destroy a session as soon as that lease expires or gets released explicitly by a client
On the other hand DhcpServer must destroy the lease if SessionManager stopped a corresponding session (e.g. by sysadmin's request)
At first it was tempting to put all the code into a single class. But the responsibilities were distinct, so I split them into two and created two interfaces:
class ISessionObserver(object):
def onSessionStart(**kwargs): pass
def onSessionStop(**kwargs): pass
class IDhcpObserver(object):
def onBeforeLeaseCreate(**kwargs):
"""
return False to cancel lease creation
"""
pass
def onLeaseCreate(**kwargs): pass
def onLeaseDestroy(**kwargs): pass
Then I implemented IDhcpObserver in SessionManager and ISessionObserver in DhcpServer. And that led to coupling. Even though the classes do not depend on each other directly they do depend on the interfaces declared in each other's packages.
Later I want to add another protocol for session initiation leaving SessionManager's logic intact. I don't want it to implement IAnotherProtocolObserver as well.
Also DHCP server as such has nothing to do with my notion of session. And since there's no DHCP protocol implementation for Twisted (which I'm using) I wanted to release it as a separate project that has no dependencies neither on SessionManager nor on its package.
How can I satisfy my spec requirements while keeping the code pieces loosely coupled?
A good way to decouple classes is to use events.
So what you need to do is to "fire" events when something happens. Example: Send an event "session created" when the SessionManager could create a session. Make the DhcpServer listen for that event and prepare a lease when it receives it.
Now all you need is a third class which creates the other two and configures the event listeners.
The beauty of this solution that it keeps everything simple. When you write unit tests, you will always only need one of the classes because all you need is to check whether the correct event has been fired.