2013-08-09 7 views
4

В настоящее время я пытаюсь порта некоторого Scala код проекта Python, и я наткнулся на следующем битый Scala кода:Python эквивалент ленивого Вала Скала

lazy val numNonZero = weights.filter { case (k,w) => w > 0 }.keys 

weights является действительно длинным списком кортежей и их взвешенное взвешенное значение. Элементы часто добавляются и удаляются из этого списка, но проверка того, сколько элементов имеет ненулевую вероятность, относительно редка. Есть несколько других редких, но дорогостоящих операций, подобных этому в коде, который я переношу, который, похоже, очень выгоден от использования lazy val. Какой самый идиоматический способ Python сделать что-то похожее на Scala's lazy val?

ответ

2

Generator expression

>>> weights = [(1,2), (2,0), (3, 1)] 
>>> numNonZero = (k for k, w in weights if w > 0) 
>>> next(numNonZero) 
1 
>>> next(numNonZero) 
3 
>>> next(numNonZero) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
>>> next(numNonZero, -1) 
-1 

>>> numNonZero = (k for k, w in weights if w > 0) 
>>> for k in numNonZero: 
...  print(k) 
... 
1 
3 

Python tutorial: Generator expressions

+0

Может ли они использоваться для атрибутов класса? – shuttle87

+0

@ shuttle87, я не понимаю, что вы имеете в виду. – falsetru

3

По сути, вы хотите изменить, как атрибут работы доступа к numNonZero. Python делает это с descriptor. В частности, взгляните на их заявку на Properties.

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

6

В Scala lazy val - это конечная переменная, которая оценивается один раз в момент ее первого доступа, а не во время ее объявления. Это, по сути, функция memoized без аргументов. Вот один из способов вы можете реализовать запоминанием декоратора в Python:

from functools import wraps 

def memoize(f): 
    @wraps(f) 
    def memoized(*args, **kwargs): 
     key = (args, tuple(sorted(kwargs.items()))) # make args hashable 
     result = memoized._cache.get(key, None) 
     if result is None: 
      result = f(*args, **kwargs) 
      memoized._cache[key] = result 
     return result 
    memoized._cache = {} 
    return memoized 

Вот как это можно использовать. С property вы можете даже оставить пустые круглые скобки, как и Scala:

>>> class Foo: 
...  @property 
...  @memoize 
...  def my_lazy_val(self): 
...   print "calculating" 
...   return "some expensive value" 

>>> a = Foo() 
>>> a.my_lazy_val 
calculating 
'some expensive value' 

>>> a.my_lazy_val 
'some expensive value' 
+0

Интересный подход, спасибо, что поделились им. – shuttle87

Смежные вопросы