Evgenii Legotckoi
Evgenii Legotckoi18 липня 2018 р. 03:14

Напишіть власні прив'язки до Python

Сьогодні ми поглянемо, як ви можете створювати прив'язки до власного проекту.

У Qt Company раді повідомити, що Qt для Python також включатиме Shiboken - ваш основний інструмент створення прив'язки.

Прочитайте матеріал нижче і ви отримаєте уявлення про те, як створювати прив'язки Python для простої бібліотеки C++.

Будемо сподіватися, це сприяє тому, що ви зробите теж саме з власними бібліотеками користувача.

Як і в будь-якому проекті Qt ми раді представити статті щодо Shiboken, тим самим покращуючи його розуміння для всіх.

Приклад бібліотеки

Основними цілями цього посту буде використання нами трохи безглуздої бібліотеки користувача під назвою Universe. Вона передбачає два класи: Icecream (морозиво) та Truck (вантажівка).


Icecreams характеризується смаком, а Truck служить як засіб доставки Icecream для дітей в околиці. Досить просто.

Ми хотіли б використовувати ці класи всередині Python. Варіант використання – додавання додаткових уподобань морозива або перевірка успішності доставки морозива. Говорячи простими словами, ми хочемо забезпечити Python прив'язки для Icecream і Truck, щоб ми могли використовувати їх у власному скрипті Python.

Ми пропустимо деяку частину для стислості, але ви можете переглянути у репозиторії повний вихідний код. Посилання на репозиторій pyside-setup/examples/samplebinding

C++ бібліотека

По-перше, давайте поглянемо на заголовний файл Icecream

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

private:
    std::string m_flavor;
};

та заголовковий файл 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;
};

Більшість API повинні бути досить прості для розуміння, але ми підіб'ємо підсумки найважливіших частин:

  • Icecream є поліморфним типом і призначається для перевизначення
  • getFlavor() поверне смак залежно від фактичного похідного типу
  • Truck зберігає вектор об'єктів Icecream, що належать йому, які можуть бути додані через addIcecreamFlavor()
  • Повідомлення прибуття «вантажівки» можна налаштувати за допомогою setArrivalMessage()
  • deliver() скаже нам, була доставка «морозива» успішною чи ні

Система типів Shiboken

Щоб інформувати shiboken про API, ми потребуємо прив'язки, для цього ми робимо файл-заголовок, який включає в себе типи, що нас цікавлять:

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

Крім того, shiboken також потребує XML typesystem файл, який визначає відношення між типами C++ і Python:

<?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>

Перша важлива річ, на яку потрібно звернути увагу – те, що ми оголошуємо "bool" та "std::string", як примітивні типи. Деякі з методів C++ використовують їх як параметр / типи даних, що повертаються, і тому shiboken повинен знати про них. Потім він може генерувати відповідний код перетворення між C++ та Python.

Більшість примітивних типів C++ обробляються shiboken, не потребуючи додаткового коду. Потім ми оголошуємо два вищезгадані класи. Один із них як “object-type”(об'єкт-тип), а інший як “value-type” (значення-об'єкт).

Основна відмінність у тому, що “object-type” передаються у згенерованому коді, як покажчики, тоді як “value-type” копіюються (семантика значень).

Задавши імена класів у файлі системи типів, shiboken автоматично спробує створити прив'язки для всіх методів, оголошених у класах, тому немає необхідності вказувати всі імена методів вручну.

Якщо ви не хочете будь-яким чином змінити функцію, це призводить до наступної теми «Правила володіння».

Shiboken не може чарівним чином дізнатися, хто відповідає за звільнення об'єктів C++, розміщених у коді Python'а.

Може бути безліч випадків: Python повинен звільнити пам'ять C++, коли кількість посилань на об'єкт Python стає нульовим або Python ніколи не повинен видаляти об'єкт C++, допускаючи, що він буде видалений в певний момент всередині бібліотеки C++. Або, можливо, це батьківський елемент іншого об'єкта (наприклад, як у QWidgets). У разі метод clone() викликається лише усередині бібліотеки C++, і ми припускаємо, що код C++ подбає про звільнення пам'яті клонованого об'єкта.

Що стосується addIcecreamFlavor(), ми знаємо, що Truck розташовується в об'єкті Icecream, і буде видалено відразу після знищення Truck. Отже, знову, право володіння встановлюється на “c++.”

Якби ми не вказали правила володіння, то в цьому випадку об'єкти C++ будуть видалені, коли відповідні імена Python вийдуть за межі зони видимості.

Складання

Щоб зібрати користувальницьку бібліотеку Universe і потім згенерувати для неї прив'язки, ми надаємо добре документований, в основному загальний файл CMakeLists.txt, який ви можете повторно використати для власних бібліотек.

В основному це зводиться до виклику "cmake.", щоб налаштувати проект, а потім побудувати за допомогою ланцюжка інструментів на ваш вибір (ми рекомендуємо генератор "(N) Makefiles").

В результаті створення проекту ви отримуєте дві спільні бібліотеки: libuniverse. (so/dylib/dll) та Universe. (so/pyd).

Перша – це бібліотека C++ і остання – це модуль Python, який може бути імпортований зі скрипта (документ, тестовий драйвер) Python.

Звичайно, є також проміжні файли, створені для shiboken (файли .h / .cpp, створені для створення прив'язок Python). Не хвилюйтеся про них, якщо вам не потрібно усувати проблеми або з якоїсь причини не вдається скомпілювати або не поводиться так, як має бути. Тоді ви можете надіслати Qt Company звіт про помилку!

І, нарешті, ми дістаємось до частини Python.

Використання Python модуля

У наступному маленькому скрипті ми використовуватимемо модуль Universe, успадковуємося від Icecream, впровадимо віртуальні методи, інстанцуємо об'єкти та багато іншого

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()

Після імпортування класів з нашого модуля, ми створюємо два похідні (вторинні) типи Icecream, яким налаштували “смаки”.

Потім ми створюємо truck (вантажівка), додаємо до нього деякі звичайні варіанти (різновиди) Icecreams (морозива) та два спеціальні.

Ми намагаємося відправити (доставити) Icecream (морозиво).

Якщо ж доставка не вдалася, ми створюємо новий truck (вантажівка) зі старими варіантами, скопійованими, і новий чарівний варіант, який, безсумнівно, задовольнить усіх клієнтів.

У наведеному вище скрипті коротко показано використання висновків із типів C++, перевизначення віртуальних методів, створення та знищення об'єктів тощо.

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
i
innorwall14 листопада 2024 р. 21:26
Qt/C++ – Урок 031. QCustomPlot – Побудова діаграм з часом buy generic priligy We can just chat, and we will not lose too much time anyway
i
innorwall14 листопада 2024 р. 19:03
Qt/C++ - Урок 060. Налаштування зовнішнього вигляду програми під час виконання I didnt have an issue work colors priligy dapoxetine 60mg revia cost uk August 3, 2022 Reply
i
innorwall14 листопада 2024 р. 11:42
Як скопіювати файли в Linux If only females relatives with DZ offspring were considered these percentages were 23 order priligy online uk
i
innorwall14 листопада 2024 р. 09:09
Qt/C++ - Підручник 068. Hello World за допомогою системи збирання CMAKE в CLion ditropan pristiq dosing With the Yankees leading, 4 3, Rivera jogged in from the bullpen to a standing ovation as he prepared for his final appearance in Chicago buy priligy pakistan
Тепер обговоріть на форумі
i
innorwall14 листопада 2024 р. 03:39
добавить qlineseries в функции priligy amazon canada 93 GREB1 protein GREB1 AB011147 6
i
innorwall11 листопада 2024 р. 10:55
Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
ИМ
Игорь Максимов03 жовтня 2024 р. 04:05
Реализация навигации по разделам Спасибо Евгений!

Слідкуйте за нами в соціальних мережах