Erstellen Sie Awaitable mit der Python / C-API

Einführung

Da sich das Jahresende diesem Jahr nähert, werde ich [Python C / API] vergeblich verwenden. Umkehrung von Zweck und Mitteln. Dieses Mal strebe ich Awaitable an, so etwas wie Coroutine, das durch Ausführen des folgenden Coroutine-Funktions-Spam erhalten wird.

import asyncio
import sys


async def spam():
    print('do something')
    ret = await asyncio.sleep(1, 'RETURN VALUE')
    return ret.lower()


async def main():
     ret = await spam()
     print(ret)


if __name__ == '__main__':
    if sys.version_info < (3, 7):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
        loop.close()
    else:
        asyncio.run(main())

Drucken Sie etwas aus, warten Sie auf den Ruhezustand, um das Ergebnis zu erhalten, und rufen Sie die niedrigere Methode auf, um das Ergebnis zurückzugeben. 3 Betrieb. Die Sende-, Wurf- und Schließmethoden, die Coroutine und Generator nicht haben, werden dieses Mal nicht reproduziert.

warten und nachgeben von

Warten Sie, bevor Sie den als async def geschriebenen Code nachahmen. Lassen Sie uns überprüfen, was dies überhaupt ist. Der Text, in dem diese Sprachfunktionen Python zusätzlich vorgeschlagen wurden, lautet PEP 492. Nachdem ich dies gelesen hatte, erinnerte ich mich schlampig daran, dass das Warten tatsächlich ein Ertrag von war. Ich denke, der Grund, warum dies vorbereitet wurde, war folgender. "Die Generatorspezifikation wurde ursprünglich im Hinblick auf die Verwendung als Coroutine entwickelt. Die Fähigkeit zum Anhalten und Fortsetzen war der Iterator selbst und die Fähigkeit, Werte zu senden PEP 342. Ich habe es hinzugefügt. Und ich habe es gut vor Python 3.4 gemacht. Es wurden jedoch Probleme aufgrund der Ununterscheidbarkeit von Generator und Iterator und Coroutine gemeldet, sodass die Sprachspezifikation von Python 3.5 unterschieden werden kann. Erstellen Sie eine andere Methode mit dem Namen \ _ \ _ await \ _ \ _ anstelle von \ _ \ _iter \ _ \ _. Lenken Sie den Ertrag nicht von der Anweisung für die Generatorfunktion ab, sondern anstelle der Coroutine-Funktion. Eine weitere Anweisung, die auf die Verwendung zur Verwendung im Inneren wartet, wurde neu hinzugefügt, um sie zu unterscheiden. " Es gibt verschiedene Namen \ _ \ _ warten \ _ \ _ und \ _ \ _ iter \ _ \ _, aber das Verhalten ist nicht unterschiedlich. Tp_iter und tp_as_sync. Am_await werden auch in der PyTypeObject-Struktur von CPython bereitgestellt und als separate Mitglieder behandelt.

__await__

Jetzt, wo ich Awaitable besser verstehe. Notieren Sie den Spam der Coroutine-Funktion sofort mit einer Klassenanweisung. Der Unterschied zu Iteratable besteht darin, dass \ _ \ _ \ _ \ _ anstelle von \ _ \ _ iter \ _ \ _ warten muss. Der einzige Unterschied besteht jedoch darin, dass Iterator von hier zurückgegeben wird.

class Spam:
    def __await__(self):
        ...  # TODO:Welcher Itarator kann zurückgegeben werden, um die Spam-Coroutine nachzuahmen?

\ _ \ _ Iter \ _ \ _ und \ _ \ _ next \ _ \ _

Weiter zerlegen. Iterator gibt sich mit \ _ \ _ iter \ _ \ _ zurück, setzt die Verarbeitung mit \ _ \ _next \ _ \ _ fort, erstellt den nächsten Wert und gibt den Wert zurück, während die Verarbeitung unterbrochen wird.

class _Spam:
    def __iter__(self):
        return self

    def __next__(self):
        ...  # TODO:Wie kann ich die Spam-Coroutine imitieren?

class Spam:
    def __await__(self):
        return _Spam()

Was brauchen wir nun, um "Erwartet ähnlich wie Coroutine, das durch Ausführen von Coroutine-Funktions-Spam erhalten wird" zu implementieren? Es behält den Status bei, wie viele der drei Aktionen "Drucken Sie etwas, warten Sie auf den Ruhezustand, um das Ergebnis zu erhalten, rufen Sie die niedrigere Methode auf und geben Sie das Ergebnis zurück". Das Objekt hat das Attribut \ _state. Dieses Mal habe ich vorerst 0, 1, 2 int verwendet, aber wenn Sie es ordentlich schreiben möchten, ist es besser, Enum zu verwenden. Implementieren Sie dann \ _ \ _next \ _ \ _, das nach Status verarbeitet wird. Das Problem hier ist abzuwarten oder nachzugeben. Es delegiert die Verarbeitung an einen anderen Iterator als den Ertrag von. Wiederholt sich iterativ, bis ein anderer Iterator stoppt und der erhaltene Wert so zurückgegeben wird, wie er ist. Sie müssen einen anderen Iterator laufen lassen, um das Äquivalent zu implementieren. Aus diesem Grund haben wir das Attribut \ _it hinzugefügt. Wenn dieser Iterator stoppt, wird eine StopIteration-Ausnahme gesendet. Sehen Sie sich also das value-Attribut an. Dies entspricht dem Wert der Wartezeit, Ausbeute aus Ausdruck in der return-Anweisung der Coroutine-Funktion oder Generatorfunktion. Achten Sie auf die Position der unteren Methode. Wenn Sie dagegen einen Wert zurückgeben, geben Sie der StopIteration-Ausnahme einen Wert. Nach dem Stoppen des Iterators gilt Einschränkung, dass die StopIteration-Ausnahme weiterhin zurückgegeben werden muss. Ergreifen Sie daher Maßnahmen dagegen. .. \ _ \ _ Weiter \ _ \ _ endet mit Raise StopIteration. Das State-Holding-Attribut sollte mit \ _ beginnen, um anzuzeigen, dass es nicht extern neu geschrieben werden soll. Diese \ _Statusinitialisierung wird in \ _ \ _ new \ _ \ _ durchgeführt, um sie gegen mehrere Aufrufe von \ _ \ _ init \ _ \ _ resistent zu machen.

class _Spam:
    def __new__(cls):
        obj = super().__new__(cls)
        obj._state = 0
        obj._it = None
        return obj

    def __iter__(self):
        return self

    def __next__(self):
        if self._state == 0:
            print('do something')
            self._it = asyncio.sleep(1, 'RETURN VALUE').__await__()
            self._state = 1
        if self._state == 1:
            try:
                v = next(self._it)
            except StopIteration as e:
                ret = e.value
                self._it = None
                self._state = 2
                raise StopIteration(ret.lower())
            else:
                return v
        raise StopIteration


class Spam:
    def __await__(self):
        return _Spam()

Schreiben wir eine Klasse mit Python C / API

Weil die Demontage vorbei ist. Schreiben Sie dies mit Python C / API. C Sprache von hier. Um eine Klasse zu erstellen, definieren Sie PyTypeObject-Struktur direkt schreiben oder PyType_Spec und rufen Sie PyType_FromSpec auf. Diesmal in Richtung der Verwendung von PyType_FromSpec. Beginnen Sie mit Spam, der einfacher ist als \ _Spam. Um \ _ \ _await \ _ \ _ zu erstellen, registrieren Sie die Funktion in tp_as_sync. Am_await. Da diese Methode eine Instanz von \ _Spam zurückgeben muss, stellen wir sicher, dass die Attribute der Spam-Klasse die \ _Spam-Klasse haben. Der Prozess zum Hinzufügen von Klassenattributen wird ausgeführt, nachdem die Klasse mit PyType_FromSpec im Initialisierungsprozess des als Py_mod_exec registrierten Moduls erstellt wurde.

typedef struct {
    PyObject_HEAD
} SpamObject;


static PyObject *
advent2019_Spam_await(SpamObject *self)
{
    PyObject *_Spam_Type = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "_Spam");
    if (_Spam_Type == NULL) { return NULL; }
    PyObject *it = PyObject_CallFunction(_Spam_Type, "");
    Py_DECREF(_Spam_Type);

    return it;
}


static PyType_Slot advent2019_Spam_slots[] = {
    {Py_am_await, (unaryfunc)advent2019_Spam_await},
    {0, 0},
};


static PyType_Spec advent2019_Spam_spec = {
    .name = "advent2019.Spam",
    .basicsize = sizeof(SpamObject),
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    .slots = advent2019_Spam_slots,
};

static int advent2019_exec(PyObject *module) {
    int ret = -1;
    PyObject *_Spam_Type = NULL;  // TODO
    PyObject *Spam_Type = NULL;

    if (!(Spam_Type = PyType_FromSpec(&advent2019_Spam_spec))) { goto cleanup; }
    // Spam._Spam = _Spam
    if (PyObject_SetAttrString(Spam_Type, "_Spam", _Spam_Type)) { goto cleanup; }

    if (PyObject_SetAttrString(module, "Spam", Spam_Type)) { goto cleanup; }
    if (PyObject_SetAttrString(module, "_Spam", _Spam_Type)) { goto cleanup; }

    ret = 0;
cleanup:
    Py_XDECREF(_Spam_Type);
    Py_XDECREF(Spam_Type);

    if (ret) { Py_XDECREF(module); }
    return ret;
}

Iterator in C / API geschrieben

Übrigens wurde die Implementierung von Iterator \ _Spam verschoben. Zuerst aus der \ _SpamObject-Struktur und \ _ \ _ new \ _ \ _. Bereiten Sie einen Wertstatus vor, der den Status und den asyncio.sleep () enthält. \ _ \ _ Await \ _ \ _ iterator. Da es andere PyObject * enthält, stellen Sie sicher, dass Sie Speicher mit PyObject_GC_New zuweisen, der dem Garbage Collection-Mechanismus entspricht. Rufen Sie nach der Initialisierung außerdem PyObject_GC_Track auf und registrieren Sie sich im Garbage Collector.

typedef struct {
    PyObject_HEAD
    unsigned char state;
    PyObject *it;
} _SpamObject;


static PyObject *
advent2019__Spam_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = {NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist)) {
        return NULL;
    }

    _SpamObject *obj = PyObject_GC_New(_SpamObject, type);
    if (!obj) { return NULL; }
    obj->state = 0;
    obj->it = NULL;

    PyObject_GC_Track(obj);

    return (PyObject *)obj;
}

Sie benötigen eine Funktion, wenn die Speicherbereinigung funktioniert. Es gibt drei Arten: Traverse, mit dem Sie das Objekt, das Sie halten, aufnehmen können, Clear, das die Referenz zerstört, und Dealloc, das sich selbst zerstört. Py_VISIT-Makro ist nützlich zum Schreiben von Traversen. PyObject_GC_UnTrack, das mit PyObject_GC_Track gepaart ist, sollte zu Beginn des Dealloc aufgerufen werden.

static int
advent2019__Spam_traverse(_SpamObject *self, visitproc visit, void *arg)
{
    Py_VISIT(self->it);
    return 0;
}

static int
advent2019__Spam_clear(_SpamObject *self)
{
    Py_CLEAR(self->it);
    return 0;
}

static void
advent2019__Spam_dealloc(_SpamObject *self)
{
    PyObject_GC_UnTrack(self);
    advent2019__Spam_clear(self);
    PyObject_GC_Del(self);
}

\ _ \ _ Iter \ _ \ _ ist einfach, weil es sich einfach selbst zurückgibt. Vergessen Sie nicht, den Referenzzähler zu bedienen.

static PyObject *
advent2019__Spam_iter(_SpamObject *self)
{
    Py_INCREF(self);
    return (PyObject *)self;
}

Endlich \ _ \ _ next \ _ \ _. In der Python C / API heißt es iternext. Die integrierten Funktionen print und sleep des Asyncio-Moduls sollten beim Erstellen der Klasse in den Klassenattributen mit den Namen \ _print und \ _sleep enthalten sein, genau wie Spam._Spam. Danach lautet der in Python geschriebene Code PyObject_GetAttrString, [PyObject_CallFunction](https: //docs.python) .org / ja / 3 / c-api / object.html # c.PyObject_CallFunction) und andere werden zum stetigen Portieren verwendet. Überprüfen Sie bei jedem Aufruf, ob der Rückgabewert NULL ist. Das Reduzieren der Referenzanzahl unnötiger Objekte ist langwierig. PyErr_Fetch, PyErr_GivenExceptionMatches zum Portieren von try-Anweisungen /ja/3/c-api/exceptions.html#c.PyErr_GivenExceptionMatches), PyErr_Restore Ich werde.

static PyObject *
advent2019__Spam_iternext(_SpamObject *self)
{
    if (self->state == 0) {
        // print('do something')
        PyObject *printfunc = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "_print");
        if (!printfunc) { return NULL; }
        PyObject *ret = PyObject_CallFunction(printfunc, "s", "do something");
        Py_DECREF(printfunc);
        if (!ret) { return NULL; }
        Py_DECREF(ret);

        // self._it = asyncio.sleep(1, 'RETURN VALUE').__await__()
        PyObject *sleep_cofunc = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "_sleep");
        if (!sleep_cofunc) { return NULL; }
        PyObject *sleep_co = PyObject_CallFunction(sleep_cofunc, "is", 1, "RETURN VALUE");
        Py_DECREF(sleep_cofunc);
        if (!sleep_co) { return NULL; }
        if (!(Py_TYPE(sleep_co)->tp_as_async)) { Py_DECREF(sleep_co);  return NULL; }
        if (!(Py_TYPE(sleep_co)->tp_as_async->am_await)) { Py_DECREF(sleep_co);  return NULL; }
        PyObject *temp = self->it;
        self->it = Py_TYPE(sleep_co)->tp_as_async->am_await(sleep_co);
        Py_DECREF(sleep_co);
        Py_XDECREF(temp);
        if (self->it == NULL) { return NULL; }

        self->state = 1;
    }
    if (self->state == 1) {
        // next(self.it)
        if (Py_TYPE(self->it)->tp_iternext == NULL) { PyErr_SetString(PyExc_TypeError, "no iternext"); return NULL; }
        PyObject *ret = Py_TYPE(self->it)->tp_iternext(self->it);
        if (!ret) {
            // except StopIteration as e
            PyObject *type, *value, *traceback;
            PyErr_Fetch(&type, &value, &traceback);
            if (PyErr_GivenExceptionMatches(type, PyExc_StopIteration)) {
                Py_XDECREF(type);
                Py_XDECREF(traceback);
                if (!value) { PyErr_SetString(PyExc_ValueError, "no StopIteration value"); return NULL; }
                // ret = e.value.lower()
                PyObject *value2 = PyObject_CallMethod(value, "lower", NULL);
                Py_DECREF(value);
                if (!value2) { return NULL; }
                // raise StopIteration(ret)
                PyErr_SetObject(PyExc_StopIteration, value2);
                Py_DECREF(value2);

                Py_CLEAR(self->it);
                self->state = 2;
            } else {
                // except:
                //     raise
                PyErr_Restore(type, value, traceback);
            }
        }
        return ret;
    }

    // raise StopIteration(None)
    PyErr_SetNone(PyExc_StopIteration);
    return NULL;
}

Nachdem wir die Methoden der \ _Spam-Klasse haben, definieren Sie PyType_Spec. Stellen Sie sicher, dass das Flag Py_TPFLAGS_HAVE_GC gesetzt ist, um anzugeben, dass die Klasse von der Garbage Collection verwaltet werden soll.

static PyType_Slot advent2019__Spam_slots[] = {
    {Py_tp_new, advent2019__Spam_new},
    {Py_tp_iter, advent2019__Spam_iter},
    {Py_tp_iternext, advent2019__Spam_iternext},
    {Py_tp_traverse, advent2019__Spam_traverse},
    {Py_tp_clear, advent2019__Spam_clear},
    {Py_tp_dealloc, advent2019__Spam_dealloc},
    {0, 0},
};


static PyType_Spec advent2019__Spam_spec = {
    .name = "advent2019._Spam",
    .basicsize = sizeof(_SpamObject),
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
    .slots = advent2019__Spam_slots,
};

abschließend

Ich habe versucht, Awaitable mit Python C / API zu implementieren. Wir konnten auch Links zu offiziellen Dokumenten sammeln, die die dafür erforderlichen Informationen enthalten. Apropos. Ist das nützlich? Der Code dafür ist viel länger und kann Ihnen helfen, CPython besser zu verstehen, genau wie Sie die Bequemlichkeit der asynchronen Def erkannt haben und auf die Syntax warten ...

setup.cfg


[metadata]
name = advent2019
version = 0.0.0

[options]
python_requires = >=3.5.0

setup.py


from setuptools import Extension, setup

extensions = [Extension('advent2019', sources=['advent2019.c'])]

setup(ext_modules=extensions)

advent2019.c


#define PY_SSIZE_T_CLEAN
#include <Python.h>


typedef struct {
    PyObject_HEAD
    unsigned char state;
    PyObject *it;
} _SpamObject;


static PyObject *
advent2019__Spam_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
    static char *kwlist[] = {NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist)) {
        return NULL;
    }

    _SpamObject *obj = PyObject_GC_New(_SpamObject, type);
    if (!obj) { return NULL; }
    obj->state = 0;
    obj->it = NULL;

    PyObject_GC_Track(obj);

    return (PyObject *)obj;
}


static PyObject *
advent2019__Spam_iter(_SpamObject *self)
{
    Py_INCREF(self);
    return (PyObject *)self;
}


static PyObject *
advent2019__Spam_iternext(_SpamObject *self)
{
    if (self->state == 0) {
        // print('do something')
        PyObject *printfunc = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "_print");
        if (!printfunc) { return NULL; }
        PyObject *ret = PyObject_CallFunction(printfunc, "s", "do something");
        Py_DECREF(printfunc);
        if (!ret) { return NULL; }
        Py_DECREF(ret);

        // self._it = asyncio.sleep(1, 'RETURN VALUE').__await__()
        PyObject *sleep_cofunc = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "_sleep");
        if (!sleep_cofunc) { return NULL; }
        PyObject *sleep_co = PyObject_CallFunction(sleep_cofunc, "is", 1, "RETURN VALUE");
        Py_DECREF(sleep_cofunc);
        if (!sleep_co) { return NULL; }
        if (!(Py_TYPE(sleep_co)->tp_as_async)) { Py_DECREF(sleep_co);  return NULL; }
        if (!(Py_TYPE(sleep_co)->tp_as_async->am_await)) { Py_DECREF(sleep_co);  return NULL; }
        PyObject *temp = self->it;
        self->it = Py_TYPE(sleep_co)->tp_as_async->am_await(sleep_co);
        Py_DECREF(sleep_co);
        Py_XDECREF(temp);
        if (self->it == NULL) { return NULL; }

        self->state = 1;
    }
    if (self->state == 1) {
        // next(self.it)
        if (Py_TYPE(self->it)->tp_iternext == NULL) { PyErr_SetString(PyExc_TypeError, "no iternext"); return NULL; }
        PyObject *ret = Py_TYPE(self->it)->tp_iternext(self->it);
        if (!ret) {
            // except StopIteration as e
            PyObject *type, *value, *traceback;
            PyErr_Fetch(&type, &value, &traceback);
            if (PyErr_GivenExceptionMatches(type, PyExc_StopIteration)) {
                Py_XDECREF(type);
                Py_XDECREF(traceback);
                if (!value) { PyErr_SetString(PyExc_ValueError, "no StopIteration value"); return NULL; }
                // ret = e.value.lower()
                PyObject *value2 = PyObject_CallMethod(value, "lower", NULL);
                Py_DECREF(value);
                if (!value2) { return NULL; }
                // raise StopIteration(ret)
                PyErr_SetObject(PyExc_StopIteration, value2);
                Py_DECREF(value2);

                Py_CLEAR(self->it);
                self->state = 2;
            } else {
                // except:
                //     raise
                PyErr_Restore(type, value, traceback);
            }
        }
        return ret;
    }

    // raise StopIteration(None)
    PyErr_SetNone(PyExc_StopIteration);
    return NULL;
}


static int
advent2019__Spam_traverse(_SpamObject *self, visitproc visit, void *arg)
{
    Py_VISIT(self->it);
    return 0;
}

static int
advent2019__Spam_clear(_SpamObject *self)
{
    Py_CLEAR(self->it);
    return 0;
}

static void
advent2019__Spam_dealloc(_SpamObject *self)
{
    PyObject_GC_UnTrack(self);
    advent2019__Spam_clear(self);
    PyObject_GC_Del(self);
}


static PyType_Slot advent2019__Spam_slots[] = {
    {Py_tp_new, advent2019__Spam_new},
    {Py_tp_iter, advent2019__Spam_iter},
    {Py_tp_iternext, advent2019__Spam_iternext},
    {Py_tp_traverse, advent2019__Spam_traverse},
    {Py_tp_clear, advent2019__Spam_clear},
    {Py_tp_dealloc, advent2019__Spam_dealloc},
    {0, 0},
};


static PyType_Spec advent2019__Spam_spec = {
    .name = "advent2019._Spam",
    .basicsize = sizeof(_SpamObject),
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
    .slots = advent2019__Spam_slots,
};


typedef struct {
    PyObject_HEAD
} SpamObject;


static PyObject *
advent2019_Spam_await(SpamObject *self)
{
    PyObject *_Spam_Type = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "_Spam");
    if (_Spam_Type == NULL) { return NULL; }
    PyObject *it = PyObject_CallFunction(_Spam_Type, "");
    Py_DECREF(_Spam_Type);

    return it;
}


static PyType_Slot advent2019_Spam_slots[] = {
    {Py_am_await, (unaryfunc)advent2019_Spam_await},
    {0, 0},
};


static PyType_Spec advent2019_Spam_spec = {
    .name = "advent2019.Spam",
    .basicsize = sizeof(SpamObject),
    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    .slots = advent2019_Spam_slots,
};


static int advent2019_exec(PyObject *module) {
    int ret = -1;
    PyObject *builtins = NULL;
    PyObject *printfunc = NULL;
    PyObject *asyncio_module = NULL;
    PyObject *sleep = NULL;
    PyObject *_Spam_Type = NULL;
    PyObject *Spam_Type = NULL;

    if (!(builtins = PyEval_GetBuiltins())) { goto cleanup; }  /* borrowed */
    // fetch the builtin function print
    if (!(printfunc = PyMapping_GetItemString(builtins, "print"))) { goto cleanup; }

    // import asyncio
    if (!(asyncio_module = PyImport_ImportModule("asyncio"))) { goto cleanup; }
    if (!(sleep = PyObject_GetAttrString(asyncio_module, "sleep"))) { goto cleanup; };

    if (!(_Spam_Type = PyType_FromSpec(&advent2019__Spam_spec))) { goto cleanup; }
    // _Spam._print = print
    if (PyObject_SetAttrString(_Spam_Type, "_print", printfunc)) { goto cleanup; }
    // _Spam._sleep = asyncio.sleep
    if (PyObject_SetAttrString(_Spam_Type, "_sleep", sleep)) { goto cleanup; }

    if (!(Spam_Type = PyType_FromSpec(&advent2019_Spam_spec))) { goto cleanup; }
    // Spam._Spam = _Spam
    if (PyObject_SetAttrString(Spam_Type, "_Spam", _Spam_Type)) { goto cleanup; }

    if (PyObject_SetAttrString(module, "Spam", Spam_Type)) { goto cleanup; }
    if (PyObject_SetAttrString(module, "_Spam", _Spam_Type)) { goto cleanup; }

    ret = 0;
cleanup:
    Py_XDECREF(printfunc);
    Py_XDECREF(asyncio_module);
    Py_XDECREF(sleep);
    Py_XDECREF(_Spam_Type);
    Py_XDECREF(Spam_Type);

    if (ret) { Py_XDECREF(module); }
    return ret;
}


static PyModuleDef_Slot advent2019_slots[] = {
    {Py_mod_exec, advent2019_exec},
    {0, NULL}
};


static struct PyModuleDef advent2019_moduledef = {
    PyModuleDef_HEAD_INIT,
    .m_name = "advent2019",
    .m_slots = advent2019_slots,
};


PyMODINIT_FUNC PyInit_advent2019(void) {
    return PyModuleDef_Init(&advent2019_moduledef);
}

Codebeispiel, um dies zu verwenden

import sys
import asyncio

import advent2019


async def main():
    v = await advent2019.Spam()
    print(v)


if __name__ == '__main__':
    if sys.version_info < (3, 7):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
        loop.close()
    else:
        asyncio.run(main())

Recommended Posts

Erstellen Sie Awaitable mit der Python / C-API
Erstellen Sie automatisch eine Python-API-Dokumentation mit Sphinx
[Python] Erstellen Sie schnell eine API mit Flask
C-API in Python 3
Erstellen Sie schnell einen API-Server mit Python + Falcon
Verwenden Sie die Trello-API mit Python
Erstellen Sie eine API mit Django
Verwenden Sie die Twitter-API mit Python
Erstellen Sie ein 3D-GIF mit Python3
Web-API mit Python + Falcon
Rufen Sie die API mit python3 auf.
Verwenden Sie die Unterschall-API mit Python3
Erstellen Sie ein Verzeichnis mit Python
[LINE Messaging API] Erstellen Sie einen Papageienrückgabe-BOT mit Python
Löse ABC163 A ~ C mit Python
Erstellen Sie eine Plotanimation mit Python + Matplotlib
Rufen Sie C von Python mit DragonFFI auf
[AWS] API mit API Gateway + Lambda erstellen
Holen Sie sich Bewertungen mit Python Googlemap API
Führen Sie Rotrics DexArm mit der Python-API aus
Quine Post mit Qiita API (Python)
Erstellen Sie eine virtuelle Umgebung mit Python!
Klicken Sie mit Python auf die Etherpad-Lite-API
Löse ABC168 A ~ C mit Python
Erstellen Sie Google Mail in Python ohne Verwendung der API
AtCoder ABC 114 C-755 mit Python3 gelöst
Löse ABC162 A ~ C mit Python
Löse ABC167 A ~ C mit Python
Erstellen Sie eine API mit hug mit mod_wsgi
Löse ABC158 A ~ C mit Python
Erstellen Sie mit AWS SAM schnell eine API mit Python, Lambda und API Gateway
[Python] API zum Senden von Google Mail erstellen
Erstellen Sie mit Python3 + Falcon eine REST-API, die die aktuelle Uhrzeit zurückgibt
[LINE Messaging API] Erstellen Sie einen BOT, der eine Verbindung zu jemandem mit Python herstellt
Sammeln von Informationen von Twitter mit Python (Twitter API)
Erstellen Sie mit Class einen Python-Funktionsdekorator
Erstellen Sie mit python3 eine Wortwolke aus Ihrem Tweet
Einfacher Slack API-Client mit Python
Erstellen Sie mit Python + PIL ein Dummy-Image.
Holen Sie sich Lebensmitteldaten mit Amazon API (Python)
[Python] Erstellen Sie mit Anaconda eine virtuelle Umgebung
Erstellen wir mit Python eine kostenlose Gruppe
Erstellen Sie schnell eine Excel-Datei mit Python #python
Python-Modul erstellen [CarSensor API-Unterstützungsmodul csapi]
[C] [Python] Lesen mit AquesTalk unter Linux
Erstellen Sie mit Docker eine Python + uWSGI + Nginx-Umgebung
Erstellen und entschlüsseln Sie Caesar-Code mit Python
Erstellen verschiedener Photoshop-Videos mit Python + OpenCV ③ Erstellen Sie verschiedene Photoshop-Videos
Erstellen Sie eine Excel-Datei mit Python + Ähnlichkeitsmatrix
Erstellen Sie mit Python 3.4 einen Worthäufigkeitszähler
Erstellen Sie eine englische Wort-App mit Python
Verwenden von C ++ - Funktionen aus Python mit pybind11