Domanda

È possibile utilizzare i tipi LINQ e i metodi di estensione in IronPython?

Se sì, come? E c'è anche più pitone a fare la stessa cosa?

È stato utile?

Soluzione

IronPython 2.7 colma finalmente questa lacuna con il metodo clr.ImportExtensions che aggiunge i metodi di estensione da uno spazio dei nomi ai tipi di destinazione, ad esempio

>& 'C:\Program Files\IronPython 2.7\ipy.exe'
IronPython 2.7 (2.7.0.40) on .NET 4.0.30319.225
Type "help", "copyright", "credits" or "license" for more information.
>>> import clr
>>> clr.AddReference("System.Core")
>>> from System.Collections.Generic import List
>>> dir (List)
['Add', 'AddRange', 'AsReadOnly', 'BinarySearch', 'Capacity', 'Clear', 'Contains', 'ConvertAll', 'CopyTo', 'Count', 'Enu
merator', 'Equals', 'Exists', 'Find', 'FindAll', 'FindIndex', 'FindLast', 'FindLastIndex', 'ForEach', 'GetEnumerator', '
GetHashCode', 'GetRange', 'GetType', 'IndexOf', 'Insert', 'InsertRange', 'IsReadOnly', 'IsSynchronized', 'Item', 'LastIn
dexOf', 'MemberwiseClone', 'ReferenceEquals', 'Remove', 'RemoveAll', 'RemoveAt', 'RemoveRange', 'Reverse', 'Sort', 'Sync
Root', 'ToArray', 'ToString', 'TrimExcess', 'TrueForAll', '__add__', '__class__', '__contains__', '__delattr__', '__doc_
_', '__format__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__iter__', '__len__', '__new__', '__reduce
__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__']
>>> import System
>>> clr.ImportExtensions(System.Linq)
>>> dir (List)
['Add', 'AddRange', 'Aggregate', 'All', 'Any', 'AsEnumerable', 'AsParallel', 'AsQueryable', 'AsReadOnly', 'Average', 'Bi
narySearch', 'Capacity', 'Cast', 'Clear', 'Concat', 'Contains', 'ConvertAll', 'CopyTo', 'Count', 'DefaultIfEmpty', 'Dist
inct', 'ElementAt', 'ElementAtOrDefault', 'Enumerator', 'Equals', 'Except', 'Exists', 'Find', 'FindAll', 'FindIndex', 'F
indLast', 'FindLastIndex', 'First', 'FirstOrDefault', 'ForEach', 'GetEnumerator', 'GetHashCode', 'GetRange', 'GetType',
'GroupBy', 'GroupJoin', 'IndexOf', 'Insert', 'InsertRange', 'Intersect', 'IsReadOnly', 'IsSynchronized', 'Item', 'Join',
 'Last', 'LastIndexOf', 'LastOrDefault', 'LongCount', 'Max', 'MemberwiseClone', 'Min', 'OfType', 'OrderBy', 'OrderByDesc
ending', 'ReferenceEquals', 'Remove', 'RemoveAll', 'RemoveAt', 'RemoveRange', 'Reverse', 'Select', 'SelectMany', 'Sequen
ceEqual', 'Single', 'SingleOrDefault', 'Skip', 'SkipWhile', 'Sort', 'Sum', 'SyncRoot', 'Take', 'TakeWhile', 'ToArray', '
ToDictionary', 'ToList', 'ToLookup', 'ToString', 'TrimExcess', 'TrueForAll', 'Union', 'Where', 'Zip', '__add__', '__clas
s__', '__contains__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__hash__', '__init__',
 '__iter__', '__len__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__'
, '__str__', '__subclasshook__']
>>>

che lo allinea al metodo di IronRuby 1.1 using_clr_extensions .

Altri suggerimenti

Alcune delle cose che faresti con LINQ possono essere fatte con la comprensione dell'elenco:

[myFunc(i) for i in numbers if i > 3]

Oppure puoi usare la mappa, ridurre e filtrare:

map(myFunc, filter(lambda x: x > 3, numbers))

Ma la comprensione dell'elenco è molto più "Pythonic" che usare i costrutti di programmazione funzionale. Per ridurre le cose, considera l'utilizzo di " " .join o somma . E puoi verificare il valore di verità di interi iterabili usando qualsiasi e tutti

Ricorda solo queste traduzioni:

Select -> map
Where -> filter
Aggregate -> reduce

E sarai sulla buona strada!

In IronPython 2.7.1 hai clr.ImportExtensions per questo caso d'uso .

import clr
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)

# will print 3 and 4 :)
[2, 3, 4].Where(lambda x: x != 2).ToList().ForEach(System.Console.WriteLine)

Un po 'di storia: IronPython 2.7 inizialmente ha introdotto questa funzione, ma c'era un problema che ha impedito che fosse realmente utilizzabile.

I ha descritto una classe wrapper C # attorno ai metodi di estensione LINQ per ottenere una sintassi simile alla sintassi del" metodo di estensione concatenato "di C # in IronPython.

L'idea è di avere una sorta di classe decoratore attorno a IEnumerable che chiama semplicemente i metodi di estensione. Probabilmente questa classe wrapper può essere scritta altrettanto bene in IronPython, ma non sono ancora fluente in Python :-)

public class ToLinq<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> _wrapped;

    public ToLinq(IEnumerable<T> wrapped)
    {
       _wrapped = wrapped;
    }

    public ToLinq<T> Where(Func<T, bool> predicate)
    {
        return new ToLinq<T>(_wrapped.Where(predicate));
    }


    // ... similar methods for other operators like Select, Count, Any, ...

}

Ciò consente una sintassi simile a questa:

johns = ToLinq[Customer](customers)\
          .Where(lambda c: c.Name.StartsWith("John"))\
          .Select(lambda c: c.Name)

Disclaimer: questo è qualcosa che ho provato come esercizio di apprendimento, non l'ho usato in un progetto del mondo reale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top