Evgenii Legotckoi
Evgenii Legotckoi18. Juli 2018 03:14

Schreiben Sie Ihre eigenen Python-Bindungen

Heute sehen wir uns an, wie Sie Bindungen für Ihr eigenes Projekt erstellen können.

The Qt Company freut sich bekannt zu geben, dass Qt for Python auch Shiboken, Ihr primäres Bindungstool, enthalten wird.

Lesen Sie das folgende Material und Sie erhalten eine Vorstellung davon, wie Sie Python-Bindungen für eine einfache C++-Bibliothek erstellen.

Hoffentlich ermutigt Sie dies, dasselbe mit Ihren eigenen benutzerdefinierten Bibliotheken zu tun.

Wie bei jedem Qt-Projekt stellen wir gerne Artikel über Shiboken zur Verfügung, um so das Verständnis für alle zu verbessern.

Beispielbibliothek

Der Hauptzweck dieses Beitrags wird unsere Verwendung einer etwas unsinnigen benutzerdefinierten Bibliothek namens Universe sein. Es bietet zwei Klassen: Icecream (Eiscreme) und Truck (LKW).


Icecreams zeichnet sich durch Geschmack aus und der Truck dient als Lieferfahrzeug für Icecream an Kinder in der Nachbarschaft. Ziemlich einfach.

Wir möchten diese Klassen in Python verwenden. Der Anwendungsfall besteht darin, zusätzliche Eissorten hinzuzufügen oder zu überprüfen, ob die Eislieferung erfolgreich war. Vereinfacht gesagt wollen wir Python-Bindings für Icecream und Truck bereitstellen, damit wir sie in unserem eigenen Python-Skript verwenden können.

Wir werden der Kürze halber einige Teile überspringen, aber Sie können das Repository für den vollständigen Quellcode überprüfen. Link zum Repository pyside-setup/examples/samplebinding .

C++-Bibliothek

Werfen wir zunächst einen Blick auf die Icecream-Header-Datei

class Icecream
{
public:
    Icecream(const std::string &flavor);
    virtual Icecream *clone();
    virtual ~Icecream();
    virtual const std::string getFlavor();

private:
    std::string m_flavor;
};

und Header-Datei Truck

class Truck {
public:
    Truck(bool leaveOnDestruction = false);
    Truck(const Truck &other);
    Truck& operator=(const Truck &other);
    ~Truck();

    void addIcecreamFlavor(Icecream *icecream);
    void printAvailableFlavors() const;

    bool deliver() const;
    void arrive() const;
    void leave() const;

    void setLeaveOnDestruction(bool value);
    void setArrivalMessage(const std::string &message);

private:
    void clearFlavors();

    bool m_leaveOnDestruction = false;
    std::string m_arrivalMessage = "A new icecream truck has arrived!\n";
    std::vector m_flavors;
};

Die meisten APIs sollten ziemlich einfach zu verstehen sein, aber wir fassen die wichtigen Teile zusammen:

  • Icecream ist ein polymorpher Typ und soll überschrieben werden
  • getFlavor() gibt den Flavor abhängig vom tatsächlichen abgeleiteten Typ zurück
  • Truck speichert einen Vektor von Icecream-Objekten, die er besitzt, die über addIcecreamFlavor() hinzugefügt werden können
  • LKW-Ankunftsnachricht kann mit setArrivalMessage() konfiguriert werden
  • liefern() teilt uns mit, ob die "Eis"-Lieferung erfolgreich war oder nicht

System vom Shiboken-Typ

Um Shiboken über die API zu informieren, benötigen wir Bindungen. Dazu erstellen wir eine Header-Datei, die die Typen enthält, an denen wir interessiert sind:

#ifndef BINDINGS_H
#define BINDINGS_H
#include "icecream.h"
#include "truck.h"
#endif // BINDINGS_H

Darüber hinaus erfordert Shiboken auch eine XML-Typsystemdatei, die die Beziehung zwischen C++- und Python-Typen definiert:

<?xml version="1.0"?>
<typesystem package="Universe">
    <primitive-type name="bool"/>
    <primitive-type name="std::string"/>
    <object-type name="Icecream">
        <modify-function signature="clone()">
            <modify-argument index="0">
                <define-ownership owner="c++"/>
            </modify-argument>
        </modify-function>
    </object-type>
    <value-type name="Truck">
        <modify-function signature="addIcecreamFlavor(Icecream*)">
            <modify-argument index="1">
                <define-ownership owner="c++"/>
            </modify-argument>
        </modify-function>
    </value-type>
</typesystem>

Als Erstes ist zu beachten, dass wir „bool“ und „std::string“ als primitive Typen deklarieren. Einige der C++-Methoden verwenden sie als Parameter-/Rückgabetypen und daher muss der Shiboken über sie Bescheid wissen. Es kann dann den entsprechenden Konvertierungscode zwischen C++ und Python generieren.

Die meisten primitiven C++-Typen werden von Shiboken verarbeitet, ohne dass zusätzlicher Code erforderlich ist. Dann deklarieren wir die beiden obigen Klassen. Eines davon als "object-type" (object-type) und das andere als "value-type" (value-object).

Der Hauptunterschied besteht darin, dass „Objekttyp“ im generierten Code als Zeiger übergeben werden, während „Werttyp“ kopiert wird (Wertsemantik).

Durch das Festlegen der Klassennamen in der Typsystemdatei versucht Shiboken automatisch, Bindungen für alle in den Klassen deklarierten Methoden zu erstellen, sodass nicht alle Methodennamen manuell angegeben werden müssen ...

Wenn Sie die Funktion in keiner Weise ändern möchten, bringt uns das zum nächsten Thema, Eigentumsregeln.

Shiboken kann nicht auf magische Weise herausfinden, wer für die Freigabe von in Python-Code platzierten C++-Objekten verantwortlich ist.

Es kann viele Fälle geben: Python muss den C++-Speicher freigeben, wenn die Anzahl der Verweise auf ein Python-Objekt Null wird, oder Python darf niemals ein C++-Objekt löschen, vorausgesetzt, es wird irgendwann in der C++-Bibliothek gelöscht. Oder vielleicht ist es das Elternobjekt eines anderen Objekts (wie zum Beispiel QWidgets). In unserem Fall wird die clone()-Methode nur innerhalb der C++-Bibliothek aufgerufen, und wir gehen davon aus, dass der C++-Code dafür sorgt, dass der Speicher des geklonten Objekts freigegeben wird.

Was addIcecreamFlavor() betrifft, wissen wir, dass sich der Truck im Icecream-Objekt befindet und sofort entfernt wird, nachdem der Truck zerstört wurde. Der Besitz ist also wieder auf „c++“ eingestellt.

Wenn wir keine Eigentumsregeln angegeben hätten, würden C++-Objekte gelöscht, wenn die entsprechenden Python-Namen den Gültigkeitsbereich verlassen würden.

Montage

Um eine benutzerdefinierte Universumsbibliothek zu erstellen und dann Bindungen dafür zu generieren, stellen wir eine gut dokumentierte, meist generische CMakeLists.txt-Datei bereit, die Sie für Ihre eigenen Bibliotheken wiederverwenden können.

Es läuft im Grunde darauf hinaus, „cmake.“ aufzurufen, um das Projekt einzurichten, und dann mit der Werkzeugkette Ihrer Wahl zu bauen (wir empfehlen den „(N) Makefiles“-Generator).

Als Ergebnis der Erstellung eines Projekts erhalten Sie zwei gemeinsam genutzte Bibliotheken: libuniverse. (so/dylib/dll) und Universum. (so/pyd).

Die erste ist eine benutzerdefinierte C++-Bibliothek und die letzte ein Python-Modul, das aus einem Python-Skript (Dokument, Testtreiber) importiert werden kann.

Natürlich gibt es auch von Shiboken erstellte Zwischendateien (.h/.cpp-Dateien, die zum Erstellen von Python-Bindungen erstellt wurden). Machen Sie sich darüber keine Sorgen, wenn Sie keine Fehlerbehebung benötigen oder wenn es aus irgendeinem Grund nicht kompiliert werden kann oder sich nicht so verhält, wie es sollte. Dann können Sie einen Fehlerbericht an Qt Company senden!

Und schließlich kommen wir zum Python-Teil.

Verwenden des Python-Moduls

Im nächsten kleinen Skript werden wir das Universe-Modul verwenden, von Icecream erben, virtuelle Methoden implementieren, Objekte instanziieren und vieles mehr.

from Universe import Icecream, Truck

class VanillaChocolateIcecream(Icecream):
    def __init__(self, flavor=""):
        super(VanillaChocolateIcecream, self).__init__(flavor)

    def clone(self):
        return VanillaChocolateIcecream(self.getFlavor())

    def getFlavor(self):
        return "vanilla sprinked with chocolate"

class VanillaChocolateCherryIcecream(VanillaChocolateIcecream):
    def __init__(self, flavor=""):
        super(VanillaChocolateIcecream, self).__init__(flavor)

    def clone(self):
        return VanillaChocolateCherryIcecream(self.getFlavor())

    def getFlavor(self):
        base_flavor = super(VanillaChocolateCherryIcecream, self).getFlavor()
        return base_flavor + " and a cherry"

if __name__ == '__main__':
    leave_on_destruction = True
    truck = Truck(leave_on_destruction)

    flavors = ["vanilla", "chocolate", "strawberry"]
    for f in flavors:
        icecream = Icecream(f)
        truck.addIcecreamFlavor(icecream)

    truck.addIcecreamFlavor(VanillaChocolateIcecream())
    truck.addIcecreamFlavor(VanillaChocolateCherryIcecream())

    truck.arrive()
    truck.printAvailableFlavors()
    result = truck.deliver()

    if result:
        print("All the kids got some icecream!")
    else:
        print("Aww, someone didn't get the flavor they wanted...")

    if not result:
        special_truck = Truck(truck)
        del truck

        print("")
        special_truck.setArrivalMessage("A new SPECIAL icecream truck has arrived!\n")
        special_truck.arrive()
        special_truck.addIcecreamFlavor(Icecream("SPECIAL *magical* icecream"))
        special_truck.printAvailableFlavors()
        special_truck.deliver()
        print("Now everyone got the flavor they wanted!")
        special_truck.leave()

Nachdem wir die Klassen aus unserem Modul importiert haben, erstellen wir zwei abgeleitete (sekundäre) Icecream-Typen, die mit Geschmacksrichtungen angepasst wurden.

Dann erstellen wir einen LKW (LKW), fügen einige reguläre Varianten (Sorten) von Icecreams (Eiscreme) und zwei spezielle hinzu.

Wir versuchen, Icecream (Eiscreme) zu versenden (zu liefern).

Wenn die Lieferung fehlschlägt, erstellen wir einen neuen LKW mit den alten kopierten Optionen und einer neuen magischen Option, die sicherlich alle Kunden zufrieden stellen wird.

Das obige Skript zeigt kurz die Verwendung von C++-Typrückschlüssen, das Überschreiben virtueller Methoden, das Erstellen und Zerstören von Objekten usw.

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken