какая особенность Python проиллюстрирована в этом коде? - PullRequest
5 голосов
/ 05 мая 2009

Я прочитал учебник по Storm ORM на https://storm.canonical.com/Tutorial, и наткнулся на следующий фрагмент кода:


store.find(Person, Person.name == u"Mary Margaret").set(name=u"Mary Maggie")

Я не уверен, что второй аргумент метода find будет оценен как True / False. Я думаю, что это будет интерпретироваться как лямбда. Если это правда, как я могу добиться того же эффекта в моих функциях?

Ответы [ 5 ]

22 голосов
/ 05 мая 2009

Person.name имеет перегруженный метод __eq__, который возвращает не логическое значение, а объект, который хранит обе стороны выражения; этот объект можно проверить методом find(), чтобы получить атрибут и значение, которые он будет использовать для фильтрации. Я бы описал это как тип ленивого шаблона оценки.

В Storm это реализовано с объектом Comparable .

9 голосов
/ 05 мая 2009

Person.name - это экземпляр некоторого типа с пользовательским методом __eq__. Хотя __eq__ обычно возвращает логическое значение (ish), на самом деле оно может возвращать все, что вы хотите, включая лямбду. См. Имена специальных методов Python для получения дополнительной информации об этом и связанных методах.

Вероятно, наиболее запутывающей / вводящей в заблуждение частью этого (особенно если вы привыкли к другим языкам OO, например, Java) является то, что Person.name и person.name (где person является экземпляром Person) don ' не должно иметь никакого отношения друг к другу. Например:

class Person(object):
  name = "name of class"
  def __init__(self):
    self.name = "name of instance"

person = Person()
print Person.name
print person.name

Будет напечатано:

name of class
name of instance

Обратите внимание, что свойство класса просто устанавливается в теле класса, а свойство экземпляра устанавливается в методе __init__.

В вашем случае вы бы установили Person.name для объекта с помощью пользовательского метода __eq__, который возвращает лямбду, что-то вроде этого:

class LambdaThingy(object):
  def __init__(self, attrname):
    self.__attrname = attrname

  def __eq__(self, other):
    return lambda x: getattr(x, self.__attrname) == other

class Person(object):
  name = LambdaThingy('name')

  def __init__(self, name):
    self.name = name

equals_fred = Person.name == "Fred"
equals_barney = Person.name == "Barney"

fred = Person("Fred")

print equals_fred(fred)
print equals_barney(fred)

Это печатает:

True
False

Это, конечно, обход "слишком умного" края, поэтому я буду очень осторожен при использовании этого в производственном коде. Явная лямбда, вероятно, будет намного понятнее будущим сопровождающим, даже если она будет более многословной.

8 голосов
/ 05 мая 2009

Магия находится в свойстве Person.name, что приводит к типу, который перегружает __eq__ (& c) для возврата не bools. Вы можете просмотреть исходные тексты Storm (и ВНИМАТЕЛЬНО подражать ;-) на http://bazaar.launchpad.net/~storm/storm/trunk/files/head%3A/storm/ - как вы увидите, они не освещают "черную магию"; -)

1 голос
/ 05 мая 2009

Это не похоже на лямбду питона для меня. Я не читал код для Storm, но Майлз, вероятно, прав в том, что он использует ленивую схему оценки.

Чтобы узнать больше о лямбда-функциях Python, прочитайте превосходную главу из Dive Into Python .

0 голосов
/ 05 мая 2009

так как я программист на Java ... я думаю ... это перегрузка оператора? Person.name == - перегруженный оператор, который вместо этого выполняет сравнение ... он создает SQL-запрос

мои 0,02 $

...