Skip to content

Pythonkunde

Bart Snijder edited this page Jul 13, 2025 · 13 revisions

Al programmerende leer je meer van de mogelijkheden van een taal, of anders gezegd gaandeweg het programmeren zie je in dat je van een facet van de taal geen bal snapt. Dan zoek je dat uit. Deze pagina is een verzameling van die zoektocht, om te voorkomen dat hetgeen geleerd is weer zo makkelijk vervliegt.

Python & bytes

https://stackoverflow.com/questions/28130722/python-bytes-concatenation

https://stackoverflow.com/questions/8263899/read-into-a-bytearray-at-an-offset

Python i.c.m. Windows 11

Soms kijk je bij problemen niet tegen een Python eigenschap aan, maar een Windows beheer dingetje.

  1. Voor het makkelijk beheren van verschillen Python versies naast elkaar, installeer pyenv voor Windows. Voor informatie hierover klik hier
  2. Als je pyenv de Python versies laat beheren, zorg dan dat alle referenties naar andere geinstalleerde varianten van Python uit de Path omgevingsvariabele zijn gehaald. Waarbij geldt: zowel uit jouw user path als uit je system path. Doe je dat niet dan zal Windows bij missende pakketjes verder zoeken in het path en als er dan een python versie die de functie wel heeft, pakt Windows die!

Python's datamodel

Zie ref.

  • Alles is een object
  • Elk object heeft een identiteit, een type en (een) waarde.
  • De identiteit van een object verandert nooit: dus aanpassen van een object na creatie is onmogelijk!
  • De is() operator vergelijkt de identiteit van twee objecten met elkaar.
  • De id() functie geeft de identiteit van een object in een integer waarde weer, wat ultimo overeenkomt met het geheugenadres van het object.
  • Het type van een object bepaalt welke operaties het object ondersteunt. De type() functie retourneert een object type, wat zelf ook een object is. Het type van object verandert nooit.

Bovenstaande in praktijk

Voor de ontwikkeling van Labcontrol bleek gaandeweg dat ik te weinig Python kennis had: je denkt dat je de functionaliteit op de juiste wijze hebt gecodeerd, weigert de boel! Voorbeeld is het geklier met de @property decorator i.c.m. overerving. Het geheel werkte niet lekker, dus heb ik alle decorators weer uit de code gehaald. Vervolgens ben je weer een poosje aan het klooien met een implementatie van een andere feature. Oorzaak is telkens hetzelfde: te weinig kennis van Pythons binnenkant i.c.m. de hoop dat ik met bestaande (C++/C#/Java) kennis er wel uitkom. Niet dus en vaak is dat de levenscyclus van een object binnen Python en met name de start ervan. Hier wordt het proces van het aanmaken van een object uitgelegd. Standaard dingen zijn niet moeilijk, maar als je dat nu net niet wilt, staat hier uitgelegd hoe e.e.a in elkaar steekt. Er zijn twee methoden/functies belangrijk in het creatietraject: new en init.

Uit de link kun je het volgende halen:

  • New() en init() hoef jezelf niet perse te implementeren. Python maakt voor jouw klasse een standaard new() en init() methode aan.
  • Init() zorgt voor de initialisatie van de datamembers. Implementaties van init() komt eerder voor dan van new().
  • New() wordt door Python eerst aangeroepen, hier wordt het object gemaakt. Daarom retourneert new() meestal het aangemaakte object en zoals hierboven te lezen is: als een object bestaat, kun de id ervan niet meer aanpassen.
  • Na new() wordt init() aangeroepen, waarin het object startwaardes kan worden meegegeven. Omdat het object bestaat en niet veranderd kan worden, retourneert init() nooit iets. Probeer je dat wel (anders dan None), dan krijg je foutmelding.

Ik wil een factory-pattern

  • Bovenstaande betekent simpel weg dat een factory-patroon in/via/voor het eind van de new functie geregeld moet zijn.
  • tijdens de uitvoering van new() verander dan je het type (=de waarde van cls) -> Zorg dan dat je voor het verlaten van new() de aangepast cls als parameter meegeeft aan de instructie super().new(). Doe je dat niet, dan wordt er ook geen object gecreeërd, althans niet de goede.
  • Als new() het nieuwe object retourneert, hoef je nergens in het proces de init() van jouw eigen klasse aan te roepen. Wel kan het verstandig zijn om binnen de eigen init() functie eerst super().init() uit te laten voeren, zodat je er zeker van kan zijn dat alle members van het nieuwe object op juiste wijze geïnitialiseerd worden.
  • Sinds Python 3.6 worden klassen op een andere wijze geïnitialiseerd. Dit staat beschreven in PEP487, zie link. Op deze manier kun je gemakkelijk een soort van plug-in systeem maken, iets wat labcontrol wel kan gebruiken.

Voorbeeld factory

In file1.py staat de code voor een BaseScope implementatie

class BaseScope(object):
    scopeList = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.scopeList.append(cls)

    @classmethod
    def getDevice(cls, id):
        return None

    def __new__(cls, id=0):
        instance = None
        for scope in cls.scopeList:
            scopeObj = scope.getDevice(id)
            if scopeObj is not None:
                #return scopeObj
                return super().__new__(scopeObj)
            else:
                instance = super().__new__(cls)  
                return instance
        return instance

    def __init__(self, id=0):
        self.myid = id
        self.channels = None

    def method1(self):
        print("method1 BaseScope")

    def method2(self):
        print("method2 BaseScope")

En in file2.py staat code die overerft van BaseScope:

from file1 import BaseScope

class MyScope1(BaseScope):

    @classmethod
    def getDevice(cls, id):
        if cls is MyScope1:
            if id==1:
                return cls
        return None

    def __init__(self, id):
        super().__init__(id)
        self.varretje1 = 5
        self.channels = []

    def method1(self):
        print("method1 myscope")
        #super().method1()

Het geheel wordt aangeroepen in main.py:

from file1 import BaseScope
from file2 import MyScope1

scope = BaseScope()
scope2 = MyScope1(1)

scope2.method1()
scope2.method2()
scope.method1()
scope.method2()

wat dan de volgende output oplevert:

method1 myscope
method2 BaseScope
method1 BaseScope
method2 BaseScope

Jupyter

Jupyter Notebook. In eigen woorden: een webbased opensource Word met ingebouwde opensource MATLAB. Anders geformuleerd: een beperkte online tekstverwerker (Markup) met krachtige gereedstaande symbolische calculator.

Waarom?

Vanaf eerste moment dat ik het tegenkwam, vond ik het een mooi en interessant platform. Absoluut geen eendagsvlieg, want bestaat al > 10 jaar. Zie hier om meer te weten van de herkomst van Jupyter. Hoewel ik wist dat het bestond en er erg goed uitzag, heb ik het lang links laten liggen vanwege onhandigheid met Python. Via Douwe en Leo vd P gezien wat het zou kunnen en vanwege de goede ervaringen van het documenteren in Markup op Github, er toch zelf mee aan de slag gegaan. Hoewel dat zeker niet het plan was, zie Jupyter nu als het raamwerk waarvan ik denk dat het de beste manier is om Labcontrol te draaien, in tegenstelling tot handmatige uitvoering of executie binnen een IDE, zoals Visual Studio (Code).

Notebook gaat Lab worden.

Jupyter's website vermeld duidelijk dat JupyterLab de toekomst. Moet ik maar eens proberen.

Jupyter voorbeelden

Er zijn hele mooie Notebooks gemaakt. Deze paragraaf somt een aantal van die mooie voorbeelden op. De lijst zal over de tijd heen vast wel groeien. Sommige mensen zijn bijzonder slim en hebben te veel tijd, of zoiets.

  1. Dynamics and Control
  2. Python Control System Lib
  3. Math notebooks
  4. LecturesOnSignalProcessing
  5. IPythonCookBook een boek of Python en Jupyter
  6. scikit-dsp-comm
  7. Notebook Gallery
  8. Physical Computing Lab
  9. PCP from Audio Labs (o.a. Fraunhofer institut)
Clone this wiki locally