Skip to content
Advertisement

Segmentation fault in destructor with Python

I have made a class to represent my led strip, and I would like to switch off the strip when I stop it (aka when the program stops and the object is destroyed). Hence, as I would do in C++, I created a destructor to do that. But it looks like Python call it after it destroyed the object. Then I got a segmentation fault error.
Here is my class, the destructor just have to call the function to set the colour of each LED to 0.

class LedStrip:
    def __init__(self, led_count, led_pin, led_freq_hz, led_dma, led_invert, led_brightness, led_channel, color = MyColor(0,0,0)):
        self.__strip = Adafruit_NeoPixel(led_count, led_pin, led_freq_hz, led_dma, led_invert, led_brightness, led_channel)
        self.__color = color
        self.__strip.begin()

    def __del__(self):
        self.__color = MyColor(0,0,0)
        self.colorWipe(10)

# ATTRIBUTS (getter/setter)
    @property
    def color(self):
        return self.__color

    @color.setter
    def color(self, color):
        if isinstance(color, MyColor):
            self.__color = color
        else:
            self.__color = MyColor(0,0,0)

    def __len__(self):
        return self.__strip.numPixels()

# METHODS
    def colorWipe(self, wait_ms=50):
        """Wipe color across display a pixel at a time."""
        color = self.__color.toNum()
        for i in range(self.__strip.numPixels()):
            self.__strip.setPixelColor(i, color)
            self.__strip.show()
            time.sleep(wait_ms/1000.0)

MyColor is just a class that I made to represent an RGB colour. What would be the correct what to achieve that task in Python? I come from C++, hence my OOP method is really C++ oriented, so I have some difficulties thinking in a pythonic way.

Thanks in advance

Advertisement

Answer

You have to be very careful when writing __del__ methods (finalizers). They can be called at virtually any time after an object is no longer referenced (it doesn’t necessarily happen immediately) and there’s really no guarantee that they’ll be called at interpreter exit time. If they do get called during interpreter exit, other objects (such as global variables and other modules) might already have been cleaned up, and therefore unavailable to your finalizer. They exist so that objects can clean up state (such as low-level file handles, connections, etc.), and don’t function like C++ destructors. In my Python experience, you rarely need to write your own __del__ methods.

There are other mechanisms you could use here. One choice would be try/finally:

leds = LedStrip(...)
try:
    # application logic to interact with the LEDs
finally:
    leds.clear() # or whatever logic you need to clear the LEDs to zero

This is still pretty explicit. If you want something a bit more implicit, you could consider using the Python context manager structure instead. To use a context manager, you use the with keyword:

with open("file.txt", "w") as outfile:
    outfile.write("Hello!n")

The with statement calls the special __enter__ method to initialize the “context”. When the block ends, the __exit__ method will be called to end the “context”. For the case of a file, __exit__ would close the file. The key is that __exit__ will be called even if an exception occurs inside the block (kind of like finally on a try block).

You could implement __enter__ and __exit__ on your LED strip, then write:

with LedStrip(...) as leds:
    # do whatever you want with the leds

and when the block ends, the __exit__ method could reset the state of all the LEDs.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement