Créer Awaitable avec l'API Python / C

introduction

Comme la fin de l'année approche cette année, j'utiliserai [Python C / API] en vain. Inversion du but et des moyens. Cette fois, je vise Awaitable, quelque chose comme Coroutine obtenu en exécutant le spam de la fonction coroutine suivante.

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

Imprimez quelque chose, attendez le sommeil pour obtenir le résultat et appelez sa méthode inférieure pour renvoyer le résultat. 3 opération. Les méthodes send, throw et close que Coroutine et Generator n'ont pas Awaitable ne seront pas reproduites cette fois.

attendre et céder de

Avant d'imiter le code écrit comme async def, attendez. Passons en revue ce que c'est en premier lieu. Le texte lorsque ces fonctionnalités de langage ont été proposées en plus à Python est PEP 492. Après avoir lu ceci, je me suis souvenu négligemment qu'attendre était en fait un rendement. Je pense que la raison pour laquelle cela a été préparé était la suivante. «La spécification Generator a été conçue à l'origine dans le but d'être utilisée comme Coroutine. La capacité de pause et de reprise était l'itérateur lui-même, et la capacité d'envoyer des valeurs PEP 342. Je l'ai ajouté. Et je me débrouillais bien avant Python 3.4. Cependant, des problèmes dus à l'indiscernabilité de Generator et Iterator et Coroutine ont commencé à être signalés, de sorte que la spécification du langage de Python 3.5 peut être distinguée. Créez une autre méthode appelée \ _ \ _ await \ _ \ _ au lieu de \ _ \ _iter \ _ \ _. Ne détournez pas l'instruction yield de la fonction Generator, mais au lieu de la fonction Coroutine Une autre instruction d'attente à utiliser à l'intérieur est nouvellement ajoutée pour la distinguer. " Il existe différents noms \ _ \ _ wait \ _ \ _ et \ _ \ _ iter \ _ \ _, mais le comportement n'est pas différent. Tp_iter et tp_as_sync. Am_await sont également fournis sur la structure PyTypeObject de CPython et sont traités comme des membres séparés.

__await__

Maintenant que j'ai une meilleure compréhension de Awaitable. Notez immédiatement le spam de la fonction coroutine avec une instruction de classe. La différence avec Iteratable est qu'il a \ _ \ _ wait \ _ \ _ au lieu de \ _ \ _ iter \ _ \ _. Cependant, la seule différence est qu'il renvoie Iterator à partir d'ici.

class Spam:
    def __await__(self):
        ...  # TODO:Quel Itarator peut être retourné pour imiter la coroutine de spam?

\ _ \ _ Iter \ _ \ _ et \ _ \ _ suivant \ _ \ _

Continuez le démontage. L'itérateur se renvoie avec \ _ \ _ iter \ _ \ _, reprend le traitement avec \ _ \ _next \ _ \ _, crée la valeur suivante et renvoie la valeur lors de l'interruption du traitement.

class _Spam:
    def __iter__(self):
        return self

    def __next__(self):
        ...  # TODO:Comment imiter la coroutine de spam?

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

Maintenant, de quoi avons-nous besoin pour implémenter "Awaitable similaire à Coroutine obtenu en exécutant la fonction coroutine spam"? C'est le maintien de l'état de la quantité des trois actions «imprimer quelque chose, attendre le sommeil pour obtenir le résultat, appeler la méthode inférieure de celui-ci et renvoyer le résultat». Donne à l'objet l'attribut \ _state. Cette fois, j'ai utilisé 0, 1, 2 int pour le moment, mais si vous voulez l'écrire proprement, il vaut mieux utiliser Enum. Ensuite, implémentez \ _ \ _next \ _ \ _ qui traite par état. Le problème ici est d'attendre ou de céder. Il délègue le traitement à un autre Iterator que celui de yield from. Se répète de manière itérative jusqu'à ce qu'un autre itérateur s'arrête et la valeur obtenue est renvoyée telle quelle. Vous devez garder un autre Iterator en cours d'exécution pour implémenter l'équivalent. Pour cette raison, nous avons ajouté l'attribut \ _it. Lorsque cet Iterator s'arrête, une exception StopIteration est envoyée, regardez donc l'attribut value. Cela correspond à la valeur de l'attente, du rendement de l'expression dans l'instruction return de la fonction coroutine ou de la fonction générateur. Faites attention à la position de la méthode inférieure. Inversement, lors du renvoi d'une valeur, attribuez une valeur à l'exception StopIteration. Iterator une fois arrêté a Restriction qu'il doit continuer à renvoyer l'exception StopIteration, alors prenez des mesures contre cela. .. \ _ \ _ Next \ _ \ _ se termine par augmenter StopIteration. L'attribut de conservation d'état doit commencer par \ _ pour indiquer que vous ne souhaitez pas qu'il soit réécrit en externe. Cette \ _initialisation de l'état est effectuée dans \ _ \ _ nouveau \ _ \ _ pour le rendre résistant à plusieurs appels à \ _ \ _ init \ _ \ _.

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

Écrivons une classe avec Python C / API

Parce que le démontage est terminé. Écrivez ceci dans Python C / API. Langage C d'ici. Pour créer une classe, définissez Ecrire directement la structure PyTypeObject ou PyType_Spec et appelez PyType_FromSpec. Cette fois, dans le sens de l'utilisation de PyType_FromSpec. Commencez par Spam, qui est plus simple que \ _Spam. Pour créer \ _ \ _await \ _ \ _, enregistrez la fonction dans tp_as_sync. Am_await. Étant donné que cette méthode doit renvoyer une instance de \ _Spam, nous nous assurerons que les attributs de la classe Spam ont la classe \ _Spam. Le traitement d'ajout d'attribut de classe est effectué après la création de classe avec PyType_FromSpec dans le traitement d'initialisation du module enregistré en tant que Py_mod_exec.

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;
}

Itérateur écrit en C / API

D'ailleurs, c'est l'implémentation de Iterator \ _Spam qui a été reportée. D'abord à partir de la structure \ _SpamObject et \ _ \ _ nouveau \ _ \ _. Préparez un état de valeur pour contenir l'état et pour qu'il contienne l'itérateur asyncio.sleep (). \ _ \ _ Await \ _ \ _. Comme il contiendra d'autres PyObject *, assurez-vous d'allouer de la mémoire avec PyObject_GC_New correspondant au mécanisme de garbage collection. De plus, après l'initialisation, appelez PyObject_GC_Track et enregistrez-vous dans le ramasse-miettes.

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;
}

Vous aurez besoin d'une fonction pour quand le garbage collection fonctionne. Il existe trois types: traversée, qui vous permet de récupérer l'objet que vous tenez, clear, qui détruit la référence, et dealloc, qui se détruit. La Macro Py_VISIT est utile pour écrire des traversées. PyObject_GC_UnTrack, qui est associé à PyObject_GC_Track, doit être appelé au début de dealloc.

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 \ _ \ _ est facile car il se renvoie simplement. N'oubliez pas d'opérer le comptage de référence.

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

Enfin \ _ \ _ suivant \ _ \ _. Il est nommé iternext sur Python C / API. Les fonctions intégrées print et sleep du module asyncio doivent être incluses dans les attributs de classe avec les noms \ _print et \ _sleep lors de la création de la classe, de la même manière que Spam._Spam. Après cela, le code écrit en Python est PyObject_GetAttrString, [PyObject_CallFunction](https: //docs.python .org / ja / 3 / c-api / object.html # c.PyObject_CallFunction) et d'autres sont utilisés pour le portage régulier. Vérifiez si la valeur de retour est NULL à chaque appel. Le processus de réduction du nombre de références d'objets inutiles est fastidieux. PyErr_Fetch, PyErr_GivenExceptionMatches pour le portage des instructions try /ja/3/c-api/exceptions.html#c.PyErr_GivenExceptionMatches), PyErr_Restore Je vais.

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;
}

Maintenant que nous avons les méthodes de la classe \ _Spam, définissez PyType_Spec. Assurez-vous de définir l'indicateur Py_TPFLAGS_HAVE_GC pour indiquer que la classe doit être gérée par le garbage collection.

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,
};

en conclusion

J'ai essayé d'implémenter Awaitable avec Python C / API. Nous avons également pu collecter des liens vers des documents officiels qui fournissent les informations nécessaires pour ce faire. au fait. Est-ce utile? Le code pour cela est beaucoup plus long, et cela pourrait vous aider à mieux comprendre CPython, tout comme vous avez réalisé la commodité de la syntaxe async def et attendre ...

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);
}

Exemple de code pour utiliser ceci

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

Créer Awaitable avec l'API Python / C
Créez automatiquement la documentation de l'API Python avec Sphinx
[Python] Créez rapidement une API avec Flask
API C en Python 3
Créez rapidement un serveur API avec Python + Falcon
Utiliser l'API Trello avec python
Créer une API avec Django
Utiliser l'API Twitter avec Python
Créer un gif 3D avec python3
API Web avec Python + Falcon
Appelez l'API avec python3.
Utiliser l'API subsonique avec python3
Créer un répertoire avec python
[LINE Messaging API] Créer un BOT de retour de perroquet avec Python
Résoudre ABC163 A ~ C avec Python
Créer une animation de tracé avec Python + Matplotlib
Appeler C depuis Python avec DragonFFI
[AWS] Créer une API avec API Gateway + Lambda
Obtenez des avis avec l'API googlemap de python
Exécutez Rotrics DexArm avec l'API Python
Quine Post avec l'API Qiita (Python)
Créez un environnement virtuel avec Python!
Accédez à l'API Etherpad-lite avec Python
Résoudre ABC168 A ~ C avec Python
Créez Gmail en Python sans utiliser l'API
Résolu AtCoder ABC 114 C-755 avec Python3
Résoudre ABC162 A ~ C avec Python
Résoudre ABC167 A ~ C avec Python
Créez une API en utilisant hug avec mod_wsgi
Résoudre ABC158 A ~ C avec Python
Créez rapidement une API avec Python, lambda et API Gateway à l'aide d'AWS SAM
[Python] Créer une API pour envoyer Gmail
Créer une API REST qui renvoie l'heure actuelle avec Python3 + Falcon
[LINE Messaging API] Créez un BOT qui se connecte à quelqu'un avec Python
Collecter des informations sur Twitter avec Python (API Twitter)
Créer un décorateur de fonction Python avec Class
Créez wordcloud à partir de votre tweet avec python3
Client API Slack simple réalisé avec Python
Créez une image factice avec Python + PIL.
Obtenez des données alimentaires avec l'API Amazon (Python)
[Python] Créez un environnement virtuel avec Anaconda
Créons un groupe gratuit avec Python
Créez rapidement un fichier Excel avec Python #python
Créer un module Python [CarSensor API support module csapi]
[C] [python] Lire avec AquesTalk sous Linux
Créer un environnement Python + uWSGI + Nginx avec Docker
Créer et décrypter du code César avec python
Créez diverses vidéos Photoshop avec Python + OpenCV ③ Créez diverses vidéos Photoshop
Créer un fichier Excel avec Python + matrice de similarité
Créer un compteur de fréquence de mots avec Python 3.4
Créez une application de mots anglais avec python
Utilisation des fonctions C ++ de python avec pybind11