2016-11-19 2 views
0

python 3.5에서 값을 지연 계산하는 데 다음 코드가 있습니다. 나는 또한 동일한 결과를 가진 @cached_propertydecorator을 시도했다, 그래서 나는 이것을 간단하게 사용할 것이다. 아래에서Python에서 인수로 전달할 때 지연 속성 평가를 피하는 방법

def bar(some_parameter, another_parameter): 
    if some_parameter != 10: 
     print(some_parameter) 
    else: 
     print(another_parameter) 

: I가이 예와 같이 끝 내부에 사용되지 않더라도, 함수의 인수로 전달할 때

class Foo:  
    @property 
    def expensive_object(self): 
     if not hasattr(self, "_expensive_object"):    
      print("Lengthy initialization routine") 
      self._expensive_object = 2 
     return self._expensive_object   

문제는 평가 도착이다 우리는 출력물이 전달 됨으로써 평가된다는 것을 알았지 만, 코드가 그것을 사용하려고하지 않았기 때문에 꼭 필요한 것은 아니었다.

In [23]: foo1 = Foo() 
    ...: bar(3, foo1.expensive_object) 
     Lengthy initialization routine 
     3 

In [24]: bar(3, foo1.expensive_object) 
     3 

내 스크립트가 적 평가를 할 필요없이 실행할 수있는 상황의가있다, 그러나 때문에 이러한 경우의 어쨌든 그 일을 끝납니다. 매개 변수를 인수 분해하는 것도 실제적이지 않습니다. 또한 구성된 멤버 개체로 __init__에서 사용합니다.

가능한 경우 실제로 읽을 때만 평가해야한다는 점에서이 속성을 더욱 게으 르고 싶습니다.

+1

가 lazier을 확인하는 것입니다 수 있도록하는 유일한 방법 'bar'가 필요할 때 호출하는 함수. 함수 인수는 항상 즉시 평가됩니다. – chepner

답변

4

파이썬은 당신이 추구하는 레벨에서 단순하고 관용적 인 게으른 속성 평가가 부족합니다.

게으른 속성 평가를 받기위한 여러 가지 방법이 있지만 호출 된 함수 (bar)의 참여와 협력이 필요합니다. 예 : 당신은 객체와 속성 이름에 전달할 수

def bar2(x, y, propname): 
    if x != 10: 
     print(x) 
    else: 
     print(getattr(y, propname)) 

bar2(3, foo1, 'expensive_object') 

또는 당신은 람다 같은 호출에 전달할 수 :

def bar3(x, y): 
    if x != 10: 
     print(x) 
    else: 
     print(y()) 

bar3(3, lambda: foo1.expensive_object) 

그러나 모든 정제에 대해, 파이썬은 매우 간단한 언어에서입니다 심장. 가장 간단한 C 또는 Java 컴파일러 인 조차도 일상적으로 수행하는 최적화에는 많은 것을하지 않아도됩니다. 그것은 거의 형이상학 적 lvalue/rvalue를 유지하지 않습니다. Perl에서 볼 수있는 구별 (이것은 정말로 도움이 될 것입니다). 그리고 속성 호출을 지연시키기 위해 thunks을 동적으로 삽입하고 평가하려고 시도하지 않습니다. foo1.expensive_object으로 전화하면 해당 값이 계산되어 이 넘겨집니다. 다르게 수행되기를 원하면 과 같이 중요한 다른 조치를 취해야합니다.

당신이 정기적으로 지연/게으른 평가를해야 할 거라면, 그것이 평가-경우-필요한 도우미 함수 정의하기 편리 할 수 ​​있습니다 :

def get_value(x): 
    return x() if hasattr(x, '__call__') else x 

이 다소 Y 평가를 정례화 할 수 있습니다 그 방법을 필요로 할 때 . 사용하는 기능은 여전히 ​​협력해야한다, 그러나 이것은 당신이 원하는 때 평가 lazier해야 할 때 나, 정적 값에 람다를 전달할 수 있습니다 :

def bar4(x, y): 
    if x != 10: 
     print(x) 
    else: 
     print(get_value(y)) 

bar4(3, 33) # works 
bar4(4, lambda: foo1.expensive_object) # also works! 
+0

나는 지나가거나 부름 받았을 때 그 속성에서 차별화 할 수있는 방법을 찾기를 희망했지만, 지금은 그렇지 않을 것이라고 생각합니다. 나는 getter 함수를 위해 정착 할 것이다. 좋은 예였습니다! – mvbentes

관련 문제