Python Slots

Posted : admin On 4/7/2022
Slots

This example was ported from the PyQt4 version by Guðjón Guðjónsson.

  • Slot Machine in Python. GitHub Gist: instantly share code, notes, and snippets.
  • The receivers of signals are called Slots in Qt terminology. A number of standard slots are provided on Qt classes to allow you to wire together different parts of your application. However, you can also use any Python function as a slot, and therefore receive the message yourself.
  • More about sots ¶. Unfortunately there is a side effect to slots. They change the behavior of the objects that have slots in a way that can be abused by control freaks and static typing weenies.

Introduction

In the Python programs, every function is a slot. It is possible to connect one signal to multiple slots, and to connect slots consecutively. For instance, one event activates its slot and related subsequent events trigger another signal and the code in its slot to be executed. General understanding of the python programming.

In some applications it is often necessary to perform long-running tasks, such as computations or network operations, that cannot be broken up into smaller pieces and processed alongside normal application events. In such cases, we would like to be able to perform these tasks in a way that does not interfere with the normal running of the application, and ensure that the user interface continues to be updated. One way of achieving this is to perform these tasks in a separate thread to the main user interface thread, and only interact with it when we have results we need to display.

This example shows how to create a separate thread to perform a task - in this case, drawing stars for a picture - while continuing to run the main user interface thread. The worker thread draws each star onto its own individual image, and it passes each image back to the example's window which resides in the main application thread.

The User Interface

We begin by importing the modules we require. We need the math and random modules to help us draw stars.

The main window in this example is just a QWidget. We create a single Worker instance that we can reuse as required.

The user interface consists of a label, spin box and a push button that the user interacts with to configure the number of stars that the thread wil draw. The output from the thread is presented in a QLabel instance, viewer.

We connect the standard finished() and terminated() signals from the thread to the same slot in the widget. This will reset the user interface when the thread stops running. The custom output(QRect, QImage) signal is connected to the addImage() slot so that we can update the viewer label every time a new star is drawn.

The start button's clicked() signal is connected to the makePicture() slot, which is responsible for starting the worker thread.

We place each of the widgets into a grid layout and set the window's title:

The makePicture() slot needs to do three things: disable the user interface widgets that are used to start a thread, clear the viewer label with a new pixmap, and start the thread with the appropriate parameters.

Since the start button is the only widget that can cause this slot to be invoked, we simply disable it before starting the thread, avoiding problems with re-entrancy.

We call a custom method in the Worker thread instance with the size of the viewer label and the number of stars, obtained from the spin box.

Whenever is star is drawn by the worker thread, it will emit a signal that is connected to the addImage() slot. This slot is called with a QRect value, indicating where the star should be placed in the pixmap held by the viewer label, and an image of the star itself:

We use a QPainter to draw the image at the appropriate place on the label's pixmap.

The updateUi() slot is called when a thread stops running. Since we usually want to let the user run the thread again, we reset the user interface to enable the start button to be pressed:

Now that we have seen how an instance of the Window class uses the worker thread, let us take a look at the thread's implementation.

The Worker Thread

The worker thread is implemented as a PyQt thread rather than a Python thread since we want to take advantage of the signals and slots mechanism to communicate with the main application.

We define size and stars attributes that store information about the work the thread is required to do, and we assign default values to them. The exiting attribute is used to tell the thread to stop processing.

Each star is drawn using a QPainterPath that we define in advance:

Before a Worker object is destroyed, we need to ensure that it stops processing. For this reason, we implement the following method in a way that indicates to the part of the object that performs the processing that it must stop, and waits until it does so.

For convenience, we define a method to set up the attributes required by the thread before starting it.

The start() method is a special method that sets up the thread and calls our implementation of the run() method. We provide the render() method instead of letting our own run() method take extra arguments because the run() method is called by PyQt itself with no arguments.

The run() method is where we perform the processing that occurs in the thread provided by the Worker instance:

Information stored as attributes in the instance determines the number of stars to be drawn and the area over which they will be distributed.

We draw the number of stars requested as long as the exiting attribute remains False. This additional check allows us to terminate the thread on demand by setting the exiting attribute to True at any time.

The drawing code is not particularly relevant to this example. We simply draw on an appropriately-sized transparent image.

For each star drawn, we send the main thread information about where it should be placed along with the star's image by emitting our custom output() signal:

Since QRect and QImage objects can be serialized for transmission via the signals and slots mechanism, they can be sent between threads in this way, making it convenient to use threads in a wide range of situations where built-in types are used.

Running the Example

We only need one more piece of code to complete the example:

slots provide a special mechanism to reduce the size of objects. It is especially useful if you need to allocate thousands of objects that would otherwise take lots of memory space. It is not very common but you may find it useful someday. Note, however, that it has some side effects (e.g. pickle may not work) and that Python 3 introduced memory optimisation on objects (sse http://www.python.org/dev/peps/pep-0412/) so slots may not be needed anymore ?

The main idea is as follows. As you may know every object in Python contains a dynamic dictionary that allows adding attributes. You can see the slots as the static version that does not allow additional attributes.

Contents

  • slots
    • Quick Example

Here is the slots syntax uing the __slot__ keyword:

The traditional version would be as follows:

This means that for every instance you’ll have an instance of a dict. Now, for some people this might seem way too much space for just a couple of attributes.

Unfortunately there is a side effect to slots. They change the behavior of the objects that have slots in a way that can be abused by control freaks and static typing weenies. This is bad, because the control freaks should be abusing the metaclasses and the static typing weenies should be abusing decorators, since in Python, there should be only one obvious way of doing something.

Making CPython smart enough to handle saving space without __slots__ is a major undertaking, which is probably why it is not on the list of changes for P3k (yet).

I’d like to see some elaboration on the “static typing”/decorator point, sans pejoratives. Quoting absent third parties is unhelpful. __slots__ doesn’t address the same issues as static typing. For example, in C++, it is not the declaration of a member variable is being restricted, it is the assignment of an unintended type (and compiler enforced) to that variable. I’m not condoning the use of __slots__, just interested in the conversation. Thanks! – hiwaylon Nov 28 ‘11 at 17:541

Each python object has a __dict__ atttribute which is a dictionary containing all other attributes. e.g. when you type self.attr python is actually doing self.__dict__[‘attr’]. As you can imagine using a dictionary to store attribute takes some extra space & time for accessing it.

However, when you use __slots__, any object created for that class won’t have a __dict__ attribute. Instead, all attribute access is done directly via pointers.

So if want a C style structure rather than a full fledged class you can use __slots__ for compacting size of the objects & reducing attribute access time. A good example is a Point class containing attributes x & y. If you are going to have a lot of points, you can try using __slots__ in order to conserve some memory.

No, an instance of a class with __slots__ defined is not like a C-style structure. There is a class-level dictionary mapping attribute names to indexes, otherwise the following would not be possible: class A(object): __slots__= “value”,nna=A(); setattr(a, ‘value’, 1) I really think this answer should be clarified (I can do that if you want). Also, I’m not certain that instance.__hidden_attributes[instance.__class__[attrname]] is faster than instance.__dict__[attrname]. – tzot Oct 15 ‘11 at 13:56up vote 4 down vote

Slots are very useful for library calls to eliminate the “named method dispatch” when making function calls. This is mentioned in the SWIG documentation. For high performance libraries that want to reduce function overhead for commonly called functions using slots is much faster.

Slot machine in python

Now this may not be directly related to the OPs question. It is related more to building extensions than it does to using the slots syntax on an object. But it does help complete the picture for the usage of slots and some of the reasoning behind them.

By default, instances of both old and new-style classes have a dictionary for attribute storage. This wastes space for objects having very few instance variables. The space consumption can become acute when creating large numbers of instances.

The default can be overridden by defining __slots__ in a new-style class definition. The __slots__ declaration takes a sequence of instance variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because __dict__ is not created for each instance.

This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. If defined in a new-style class, __slots__ reserves space for the declared variables and prevents the automatic creation of __dict__ and __weakref__ for each instance. New in version 2.2.

Notes on using __slots__

Without a __dict__ variable, instances cannot be assigned new variables not listed in the __slots__ definition. Attempts to assign to an unlisted variable name raises AttributeError. If dynamic assignment of new variables is desired, then add ‘__dict__’ to the sequence of strings in the __slots__ declaration. Changed in version 2.3: Previously, adding ‘__dict__’ to the __slots__ declaration would not enable the assignment of new attributes not specifically listed in the sequence of instance variable names.

Without a __weakref__ variable for each instance, classes defining __slots__ do not support weak references to its instances. If weak reference support is needed, then add ‘__weakref__’ to the sequence of strings in the __slots__ declaration. Changed in version 2.3: Previously, adding ‘__weakref__’ to the __slots__ declaration would not enable support for weak references.

__slots__ are implemented at the class level by creating descriptors (3.4.2) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.

If a class defines a slot also defined in a base class, the instance variable defined by the base class slot is inaccessible (except by retrieving its descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this.

Warning

effects of a __slots__ declaration is limited to the class where it is defined. In other words, subclasses will have a __dict__ (unless they also define __slots__).

__slots__ do not work for classes derived from ``variable-length’’ built-in types such as long, str and tuple.

Pyside2 Signal Slot

Any non-string iterable may be assigned to __slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.

For every instance of any class, attributes are stored in a dictionary.

This means that for every instance you’ll have an instance of a dict. Now, for some people this might seem way too much space for just a couple of attributes.

If you have lots and lots and looooots of instances, and you want to save some memory, you can use __slots__. The basic idea is that when you define the __slots__ class attribute, those attributes will get just the enough space, without wasting space.

Slot Machine In Python

Here is the previous example using __slots__:

Now, one side effect of these __slots__ thing is that, whenever you define the __slots__ class attribute, your __dict__ attribute for every instance will be gone!. It’s not a surprise because that’s why you should use __slots__ in the first place… to get rid off the __dict__ in every instance, to save some memory remember?Can’t bind attributes to the instance any more…

Another side effect is that, as there is no __dict__, there is no way to add, at runtime, any attributes to your instance:

# This should should work if there is no __slots__ defined...>>> instance.new_attr = 10Traceback (most recent call last):

File “<stdin>”, line 1, in <module>

AttributeError: ‘myClass’ object has no attribute ‘new_attr’>>>Read only attributes?

Python Slots Machine

Another one is that, if there is some kind of collision between the slot and a class attribute, then the class attribute will overwrite the slot and, as there is no __dict__, the class attribute will be read-only.

Python Slots Dataclass

However if you want to have a __dict__, you can always insert into the __slots__ the ‘__dict__’ value, and all these little side effects will go away

But what if I wanted to add the ‘__dict__’ value into __slots__ at runtime?

Python Slot Machine Code

sorry dude but, no can do.

Python Slots Vs Dict

reference: http://mypythonnotes.wordpress.com/2008/09/04/__slots__/:wq