[PYTHON] Essayez de créer quelque chose comme C # LINQ

Aperçu

L'idée de LINQ en C # peut-elle être utilisée dans Maya Python? J'ai essayé de le découvrir.

motivation

――Je souhaite utiliser la liste plus facilement et plus facilement. ――Si vous pouvez écrire quelque chose de similaire à C #, le coût de commutation devrait baisser.

Qu'est-ce que LINQ

Je laisserai l'explication sur LINQ à d'autres sites (les sites de référence sont résumés en bas de page) En gros, c'est "* une fonction pour filtrer et traiter les valeurs d'une manière semblable à une instruction SQL pour les listes, etc. *". Le code qui utilise réellement LINQ est le suivant.

LinqSample.cs


var hoge = new int[] { 0, 1, 2, 3, 4, 5 };
var hogehoge = hoge.where(n => n > 3).select(n => n * n);
foreach (var x in hogehoge)
    Debug.WriteLine(x);

>>> 16
>>> 25

Si vous écrivez le code ci-dessus dans la ** notation d'inclusion de liste ** de Python, ce sera comme suit.

list_comprehension_sample.py


hoge = [0, 1, 2, 3, 4, 5]
hogehoge = [x * x for x in hoge if x > 3]
for x in hogehoge:
    print x

>>> 16
>>> 25

Si vous l'écrivez comme ceci, je pense que ce serait bien s'il y avait une notation d'inclusion de liste. (Ryuishi Python) De plus, comme les tranches peuvent être utilisées en Python, il y a peu de problèmes avec les opérations de liste.

Les fonctionnalités de LINQ incluent ** la chaîne de méthodes ** et ** l'évaluation du retard **. Je pense que le gros avantage est qu'il est facile à comprendre et à écrire tout en raccourcissant simplement le code. L'écriture d'opérations complexes avec des inclusions et des tranches de liste Python peut être beaucoup moins lisible.

Sur la base de cette situation, j'ai réfléchi à la façon de reproduire les bonnes parties de LINQ.

** Premier prototype **

Tout d'abord, j'ai essayé de ne faire que l'interface comme ça pour vérifier l'atmosphère. Le premier essai consiste à préparer la même méthode que LINQ et à essayer de rapprocher uniquement l'effet unique.

iterator_v1.py


class GeneralIterator(object):
    """Une classe qui encapsule les opérations de liste à l'aide des noms de méthode LINQ

    <usage>
    selection = GeneralIterator(cmds.ls(sl=True))
    selection.count()
    for x in selection.generator(): print x
    selection.last()
    selection.first()
    selection.at(3)
    selection.distinct()
    selection.skip(3)
    selection.take(3)
    selection.all(lambda x: x.startswith('mesh_'))
    selection.any(lambda x: x.startswith('skel_'))
    selection.contains("grp_")
    selection.union(["group1", "group2"])
    selection.reverse()
    selection.select(lambda x: cmds.getAttr(x + '.tx'))
    selection.where(lambda x: x.endswith('_offset'))
    """

    def __init__(self, list=None):
        self.set_list(list)

    def set_list(self, list):
        self.__list = list

    def is_empty(self):
        return self.__list is None or len(self.__list) == 0

    def print_items(self):
        for x in self.generator():
            print x

    def count(self):
        if self.is_empty():
            return 0
        return len(self.__list)

    def generator(self):
        for x in self.__list:
            yield x
    
    def first(self, default=None):
        if self.is_empty():
            return default
        return self.__list[0]

    def last(self, default=None):
        if self.is_empty():
            return default
        return self.__list[-1]

    def at(self, index, default=None):
        if index <= self.count():
            return self.__list[index]
        return default

    def distinct(self):
        return list(set(self.__list))

    def skip(self, count):
        if count < self.count():
            return self.__list[count:]
        
    def take(self, count):
        if count <= self.count():
            return self.__list[:count]

    def all(self, func):
        for x in self.generator():
            if not func(x):
                return False
        return True

    def any(self, func):
        for x in self.generator():
            if func(x):
                return True
        return False

    def contains(self, obj):
        for x in self.generator():
            if x == obj:
                return True
        return False

    def union(self, list):
        return self.__list + list

    def reverse(self):
        return list(reversed(self.__list))

    def select(self, func):
        return [func(x) for x in self.__list]

    def where(self, func):
        return [x for x in self.__list if func(x)]

** 2ème prototype **

Comme étape suivante, je veux une chaîne de méthodes. Je voudrais voir une exécution retardée. Après avoir lu la méthode d'implémentation de LINQ, j'ai pensé que je pourrais faire quelque chose de similaire en utilisant la fermeture, et j'ai essayé la seconde.

iterator_v2.py


class EnumerableIterator(object):
    """Classe de manipulation de liste qui a essayé la chaîne de méthodes et l'exécution paresseuse comme LINQ
    
        [usage]
        hoge = EnumerableIterator(range(10))
        for x in hoge.where(lambda x: x > 7).select(lambda x: x * x): print x
    """

    def __init__(self, list=None, func=None):
        self._set_list(list)
        self.func = func

    def _set_list(self, list):
        self.__list = list

    def __execute_func(self):
        if self.func is None:
            return self.__list
        return self.func(self.__list)
        
    def __iter__(self):
        for x in self.__execute_func():
            yield x

    def to_list(self):
        return self.__execute_func()

    def count(self):
        return len(self.__execute_func())

    def __is_empty(self, list):
        return list is None or len(list) == 0

    def first(self, default=None):
        result = self.__execute_func()
        if self.__is_empty(result):
            return default
        return result[0]

    def last(self, default=None):
        result = self.__execute_func()
        if self.__is_empty(result):
            return default
        return result[-1]

    def at(self, index, default=None):
        result = self.__execute_func()
        if self.__is_empty(result):
            return default
        if index <= len(result):
            return list[index]
        return default

    def distinct(self):
        return list(set(self.__execute_func()))

    def skip(self, count):
        result = self.__execute_func()
        return result[count:]
        
    def take(self, count):
        result = self.__execute_func()
        return result[:count]

    def all(self, func):
        for x in self:
            if not func(x):
                return False
        return True

    def any(self, func):
        for x in self:
            if func(x):
                return True
        return False

    def contains(self, obj):
        for x in self:
            if x == obj:
                return True
        return False

    def union(self, list):
        return self.__execute_func() + list

    def reverse(self):
        return list(reversed(self.__execute_func()))

    def where(self, func):
        def action(list):
            result = list
            if self.func is not None:
                result = self.func(list)
            return [x for x in result if func(x)]
        return EnumerableIterator(self.__list, action)

    def select(self, func):
        def action(list):
            result = list
            if self.func is not None:
                result = self.func(list)
            return [func(x) for x in result]
        return EnumerableIterator(self.__list, action)

** Utilisez le deuxième prototype **

Si rien n'est fait, le contenu ne sera pas lié à Maya, je vais donc essayer de l'utiliser dans Maya.

iterator_v2.py


class EnumerableSelection(EnumerableIterator):
    """Itérateur de sélection d'objets

    [usage]
    selection = Selection()

    for x in selection.where(lambda x: x.endswith('_offset')).select(lambda x: cmds.getAttr(x + '.tx')):
        print x

    print selection \
        .where(lambda  x: x.endswith('Group')) \
        .select(lambda x: cmds.getAttr(x + '.tx')) \
        .where(lambda  x: x > 0.1) \
        .first()
    """

    def __init__(self, flat=True):
        super(EnumerableSelection, self).__init__()
        self.__flat = flat
        self.update()

    def update(self):
        self._set_list(cmds.ls(sl=True, fl=self.__flat))

** Impression **

Il existe également des itertools et d'autres itertools, mais je préfère LINQ comme style d'écriture. Je pense que si je peux comprendre et utiliser davantage les spécifications du langage, je serai capable d'écrire dans un style pythonique. Je souhaite continuer à étudier en attendant des conseils et des conseils issus de domaines variés.

** Site de référence **

Recommended Posts

Essayez de créer quelque chose comme C # LINQ
Essayez de créer un module Python en langage C
Quelque chose comme 40-32 / 2 = 4!
Faisons un noyau jupyter
Fabriquez-vous quelque chose comme une fusée?
Essayez quelque chose comme Python for-else dans Ruby
Essayez de créer votre propre AWS-SDK avec bash
Souhaitez-vous créer un CV Twitter?
Les débutants en IA essaient de faire des étudiants professionnels Bot
Essayez de créer un code de "décryptage" en Python
Essayez de créer un groupe de dièdre avec Python
Je veux créer du code C ++ à partir de code Python!
Essayez de rendre le client FTP le plus rapide avec Pythonista
J'ai essayé de faire quelque chose comme un chatbot avec le modèle Seq2Seq de TensorFlow
Essayez d'utiliser le Python On-box de Junos #Bonus 1 Quelque chose comme ChatOps / Commit et publiez sur Slack
Faisons un outil de veille de commande avec python
Essayez de créer une API RESTful avec MVC à l'aide de Flask 1.0.2
Les débutants en apprentissage automatique essaient de créer un arbre de décision
Essayez d'implémenter yolact
Essayez de le faire avec GUI, PyQt en Python
Je veux faire quelque chose comme sort uniq en Python
Lorsque j'essaye de créer Apache SSL, cela ne démarre pas.
[Introduction à Tensorflow] Comprendre correctement Tensorflow et essayer de créer un modèle
Créez le nuage de mots de Qiita à partir de l'historique de votre navigateur