(Предупреждение: мамонт отвечает вперед. Часть до первой горизонтальной линии делает хороший раздел tl; dr, я полагаю)
Я не уверен, что я квалифицируюсь как гуру Python ... но у меня есть твердое понимание на итерации на Python, так что давайте попробуйте :)
Прежде всего: запросы Afaik, LINQ выполняются лениво - если это так, выражения генератора представляют собой более близкую концепцию Python (в любом случае, функции list-, dict- и set понимают концептуально просто выражения генератора, list/dict/set constructor!).
Также существует концептуальная разница: LINQ для, как сказано в названии, для запросов структур данных. List-/dict-/set assrehensions - это возможное применение этого (например, фильтрация и проецирование элементов списка). Поэтому они на самом деле менее общие (как мы увидим, многие вещи, встроенные в LINQ, не встроены в них). Подобным образом, выражения генератора - это способ сформулировать одноразовый итератор вперед на месте (мне нравится думать об этом как лямбда для функций генератора, только без уродливого длинного ключевого слова;)), а не для описания сложного запроса , Они перекрываются, да, но они не идентичны. Если вы хотите использовать все возможности LINQ в Python, вам нужно будет написать полноценный генератор. Или объедините многочисленные мощные генераторы, встроенные и в itertools
.
Теперь коллеги Python для возможности LINQ Джон Скит имени:
проекциях: (x.foo for ...)
Фильтрация: (... if x.bar > 5)
- соединений (х присоединиться к у на x.foo equals y.bar)
Ближайшая вещь будет ((x_item, next(y_item for y_item in y if x_item.foo == y_item.bar)) for x_item in x)
, я полагаю.
Обратите внимание, что это не будет перебирать по всей y для каждого x_item, оно получит только первое совпадение.
- Group присоединяется к (х присоединиться к у на x.foo приравнивает y.bar в г)
Это сложнее. Python не имеет анонимные типы, хотя они тривиальны сделать самостоятельно, если вы не возражаете, баловаться с __dict__
:
class Anonymous(object):
def __init__(self, **kwargs):
self.__dict__ = kwargs
Тогда мы могли бы сделать (Anonymous(x=x, y=y) for ...)
, чтобы получить список объектов, которые имеют x
и y
членов с соответствующими значениями. Правильная вещь обычно подает результаты конструктору класса approriate, скажем, XY.
- Группировка (группа x.foo по x.bar)
Теперь он получает волосатой ... нет встроенного способа, AFAIK. Но мы можем определить его OURSELF, если это необходимо:
from collections import defaultdict
def group_by(iterable, group_func):
groups = defaultdict(list)
for item in iterable:
groups[group_func(item)].append(item)
return groups
Пример:
>>> from operator import attrgetter
>>> group_by((x.foo for x in ...), attrgetter('bar'))
defaultdict(<class 'list'>, {some_value_of_bar: [x.foo of all x where x.bar == some_value_of_bar], some_other_value_of_bar: [...], ...})
Это требует, что мы группа по быть hashable, хотя. Этого можно избежать, и я сделаю удар, если будет общественный спрос. Но сейчас, я ленивый :)
Мы также можем просто вернуть итератор групп без ценностей, которые мы сгруппированных по, по телефону .values()
на результат (конечно, мы можем кормить что к list
, чтобы получить то, что мы можем индексировать и повторять несколько раз). Но кто знает, если мы не будем нужны групповые ценности ...
- заказа (OrderBy x.foo по возрастанию, по убыванию y.bar)
Сортировка необходим специальный синтаксис?Встроенный sorted
работает и для итераций: sorted(x % 2 for x in range(10))
или sorted(x for x in xs, key=attrgetter('foo'))
. По умолчанию сортировка по возрастанию, аргумент ключевого слова reverse
дает убывающий порядок.
Увы, сортировка по афайкам по нескольким атрибутам не так проста, особенно при смешении восходящего и нисходящего. Хм ... тема для рецепта?
- Промежуточных переменными (пусть TMP = x.foo)
Нет, не представляется возможным в постижениях или выражениях генератора - они, как название говорит, должно быть выражения (и обычно охватывают только одну или две линии). Это вполне возможно, в функции генератора, хотя:
(x * 2 for x in iterable)
переписано в виде генератора с промежуточной переменной:
def doubles(iterable):
for x in iterable:
times2 = x * 2
yield times2
Сведение: (c for s in ("aa","bb") for c in s)
Обратите внимание, что хотя LINQ к объектам имеет дело с делегаты, другие поставщики запросов (например, LINQ to SQL) могут обрабатывать деревья выражений, которые описывают запрос instea d просто представить исполняемых делегатов. Это позволяет преобразовать запрос в SQL (или другие языки запросов) - опять же, я не знаю, поддерживает ли Python такую вещь или нет. Однако это значительная часть LINQ.
Python определенно не делает этого. Выражения списка соответствуют взаимно однозначным для накопления простого списка в (возможно, вложенном) для цикла, генераторные выражения соответствуют друг другу одному генератору. Учитывая, что в модуле parser
и ast
возможно теоретически , чтобы написать библиотеку для преобразования понимания, например. SQL-запрос. Но никто не заботится.
Если вы ленивы в C# Рассмотрим написание вместо этого: words.Where (ш => w.Length <5) .dump(); – Moberg
Как пояснялось в [этом эпическом объяснении монад] (http://www.youtube.com/watch?v=ZhuHCtR3xq8), LINQ тщательно разработан, чтобы быть монодичным, поэтому его можно строить простым, безопасным и эффективным способом , Монад и функциональное программирование быстро растут. Поэтому я предлагаю людям обратиться к ним в своих ответах. – nealmcb
@nealmcb Монада важна только на языке, который не поддерживает разделяемое изменяемое состояние, так же как и статические методы, полезны только на языках, не поддерживающих первоклассные функции. Это способ обеспечить идеологическую чистоту, чтобы позволить парадигме программирования делать что-то, что не подходит для того, чтобы быть полным. Таким образом, монада никогда не будет возрастать по важности; это костыль, чтобы обойти ограничения, введенные самим собой. Другим примером может служить обобщение и динамическая типизация. – alcalde