[PYTHON] Versuchen Sie etwas wie C # LINQ zu machen

Überblick

Kann die Idee von LINQ in C # in Maya Python verwendet werden? Ich versuchte es herauszufinden.

Motivation

――Ich möchte die Liste einfacher und einfacher bedienen. ――Wenn Sie etwas Ähnliches wie C # schreiben können, sollten die Umstellungskosten sinken.

Was ist LINQ?

Ich werde die Erklärung zu LINQ anderen Websites überlassen (Referenzseiten sind am Ende der Seite zusammengefasst). Grob gesagt ist es "* eine Funktion zum Filtern und Verarbeiten von Werten in einer SQL-Anweisung-ähnlichen Weise für Listen usw. *". Der Code, der tatsächlich LINQ verwendet, lautet wie folgt.

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

Wenn Sie den obigen Code in Pythons ** Listeneinschlussnotation ** schreiben, ist dies wie folgt.

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

Wenn Sie es so schreiben, wäre es meiner Meinung nach schön, wenn es eine Listeneinschlussnotation gäbe. (Ryuishi Python) Da Slices in Python verwendet werden können, gibt es außerdem nur wenige Probleme mit Listenoperationen.

Die Funktionen von LINQ umfassen ** Methodenkette ** und ** Verzögerungsbewertung **. Ich denke, der große Vorteil ist, dass es leicht zu verstehen und zu schreiben ist, während der Code einfach gekürzt wird. Das Schreiben komplexer Operationen mit Python-Listeneinschlüssen und Slices kann erheblich weniger lesbar sein.

Aufgrund dieser Situation habe ich darüber nachgedacht, wie die guten Teile von LINQ reproduziert werden können.

** Erster Prototyp **

Zuerst habe ich versucht, nur die Schnittstelle so zu gestalten, um die Atmosphäre zu überprüfen. Der erste Versuch besteht darin, dieselbe Methode wie LINQ vorzubereiten und nur den einzelnen Effekt näher zu bringen.

iterator_v1.py


class GeneralIterator(object):
    """Eine Klasse, die Listenoperationen mit LINQ-Methodennamen umschließt

    <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. Prototyp **

Als nächsten Schritt möchte ich eine Methodenkette. Ich würde gerne eine verspätete Ausführung sehen. Nachdem ich die Implementierungsmethode von LINQ gelesen hatte, dachte ich, dass ich mit dem Verschluss etwas Ähnliches machen könnte, und versuchte es mit der zweiten.

iterator_v2.py


class EnumerableIterator(object):
    """Listen Sie die Manipulationsklasse auf, die Methodenkette und verzögerte Ausführung wie LINQ ausprobiert hat
    
        [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)

** Verwenden Sie den zweiten Prototyp **

Wenn nichts unternommen wird, wird der Inhalt nicht mit Maya in Verbindung gebracht, daher werde ich versuchen, ihn in Maya zu verwenden.

iterator_v2.py


class EnumerableSelection(EnumerableIterator):
    """Objektauswahl-Iterator

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

** Eindruck **

Es gibt auch itertools und mehr-itertools, aber ich bevorzuge LINQ als Schreibstil. Ich habe das Gefühl, dass ich im pythonischen Stil schreiben kann, wenn ich die Sprachspezifikationen besser verstehen und verwenden kann. Ich möchte weiter studieren und auf Ratschläge und Ratschläge aus verschiedenen Bereichen warten.

** Referenzseite **

Recommended Posts

Versuchen Sie etwas wie C # LINQ zu machen
Versuchen Sie, ein Python-Modul in C-Sprache zu erstellen
So etwas wie 40-32 / 2 = 4!
Machen wir einen Jupyter-Kernel
Machst du so etwas wie eine Rakete?
Versuchen Sie etwas wie Python für-else in Ruby
Versuchen Sie, Ihr eigenes AWS-SDK mit bash zu erstellen
Möchten Sie einen Twitter-Lebenslauf erstellen?
KI-Anfänger versuchen, professionelle Studenten Bot zu machen
Versuchen Sie, in Python einen "Entschlüsselungs" -Code zu erstellen
Versuchen Sie, mit Python eine Diedergruppe zu bilden
Ich möchte C ++ - Code aus Python-Code erstellen!
Versuchen Sie, Client-FTP mit Pythonista am schnellsten zu machen
Ich habe versucht, mit dem Seq2Seq-Modell von TensorFlow so etwas wie einen Chatbot zu erstellen
Versuchen Sie es mit Junos 'On-Box Python #Bonus 1 So etwas wie ChatOps / Commit und posten Sie es bei Slack
Lassen Sie uns ein Befehls-Standby-Tool mit Python erstellen
Versuchen Sie, mit MVC eine RESTful-API mit Flask 1.0.2 zu erstellen
Anfänger des maschinellen Lernens versuchen, einen Entscheidungsbaum zu erstellen
Versuchen Sie, yolact zu implementieren
Versuchen Sie es mit GUI, PyQt in Python
Ich möchte so etwas wie Uniq in Python sortieren
Wenn ich versuche, Apache SSL zu erstellen, wird es nicht gestartet.
[Einführung in Tensorflow] Verstehen Sie Tensorflow richtig und versuchen Sie, ein Modell zu erstellen
Erstellen Sie die Word Cloud von Qiita aus Ihrem Browserverlauf