você pode usar tipos LINQ e os métodos de extensão em IronPython?
-
06-07-2019 - |
Pergunta
É possível usar os tipos de LINQ e os métodos de extensão em IronPython?
Se sim, como? E também há muitas vezes mais Python para fazer a mesma coisa?
Solução
IronPython 2,7 finalmente preenche esta lacuna com o método clr.ImportExtensions
que adiciona os métodos de extensão a partir de um espaço de nomes para os tipos de destino e.g.
>& '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__']
>>>
que traz-lo em linha com o método using_clr_extensions
IronRuby 1.1 do.
Outras dicas
Algumas das coisas que você faria com o LINQ pode ser feito com compreensões lista:
[myFunc(i) for i in numbers if i > 3]
Ou você pode usar o mapa, reduzir e filtro:
map(myFunc, filter(lambda x: x > 3, numbers))
Mas compreensões lista são muito mais "Pythonic" do que usando as construções de programação funcional. Para reduzir as coisas, considere o uso de "". Juntar-se ou sum . E você pode verificar o valor de verdade de iterables inteiras usando qualquer e todas
Basta lembrar estas traduções:
Select -> map
Where -> filter
Aggregate -> reduce
E você será bem no seu caminho!
Na IronPython 2.7.1 você tiver clr.ImportExtensions para este caso de 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)
Um pouco de fundo: IronPython 2.7 inicialmente introduzido este recurso, mas não havia an que parou de ser realmente utilizável.
I descreveu um C # classe wrapper em torno dos métodos de extensão LINQ para alcançar uma sintaxe semelhante ao C # 's 'encadeada método de extensão' sintaxe no IronPython.
A idéia é ter uma espécie de classe decorador torno IEnumerable
que simplesmente chama os métodos de extensão. Provavelmente esta classe de mensagens publicitárias pode ser escrito tão bem em IronPython, mas eu não sou tão fluente em python ainda: -)
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, ...
}
Isto permite uma sintaxe semelhante a esta:
johns = ToLinq[Customer](customers)\
.Where(lambda c: c.Name.StartsWith("John"))\
.Select(lambda c: c.Name)
Disclaimer: este é algo que eu tentei como um exercício de aprendizagem, eu não usei isso em um projeto do mundo real.