[python] 파이썬 함수 속성-사용 및 남용 [폐쇄]

이 기능을 잘 아는 사람은 많지 않지만 Python의 함수 (및 메소드)는 속성 을 가질 수 있습니다 . 보다:

>>> def foo(x):
...     pass
...
>>> foo.score = 10
>>> dir(foo)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name', 'score']
>>> foo.score
10
>>> foo.score += 1
>>> foo.score
11

파이썬에서이 기능의 가능한 사용과 남용은 무엇입니까? 내가 아는 한 가지 좋은 사용법은 구문 규칙을 메소드와 연관시키기 위해 PLY 의 docstring 사용입니다. 그러나 사용자 정의 속성은 어떻습니까? 그것들을 사용해야 할 좋은 이유가 있습니까?



답변

일반적으로 함수 속성을 주석의 저장소로 사용합니다. C # 스타일로 작성하고 싶다고 가정하십시오 (특정 메소드가 웹 서비스 인터페이스의 일부 여야 함을 나타냄)

class Foo(WebService):
    @webmethod
    def bar(self, arg1, arg2):
         ...

그런 다음 정의 할 수 있습니다

def webmethod(func):
    func.is_webmethod = True
    return func

그런 다음 웹 서비스 호출이 도착하면 메소드를 찾고 기본 함수에 is_webmethod 속성이 있는지 확인하고 (실제 값은 관련이 없음) 메소드가 없거나 웹을 통해 호출 될 의도가 아닌 경우 서비스를 거부합니다.


답변

함수의 정적 변수로 사용했습니다. 예를 들어 다음과 같은 C 코드가 제공됩니다.

int fn(int i)
{
    static f = 1;
    f += i;
    return f;
}

파이썬에서 비슷하게 함수를 구현할 수 있습니다.

def fn(i):
    fn.f += i
    return fn.f
fn.f = 1

이것은 스펙트럼의 “구슬”끝에 빠질 것입니다.


답변

JavaScript 방식으로 객체를 수행 할 수 있습니다 … 의미가 없지만 작동합니다.)

>>> def FakeObject():
...   def test():
...     print "foo"
...   FakeObject.test = test
...   return FakeObject
>>> x = FakeObject()
>>> x.test()
foo


답변

나는 그것들을 조금만 사용하지만 매우 편리 할 수 ​​있습니다.

def log(msg):
   log.logfile.write(msg)

이제 log모듈 전체에서 사용할 수 있으며 간단히 설정하여 출력을 리디렉션 할 수 있습니다 log.logfile. 그것을 달성하는 많은 방법이 많이 있지만, 이것은 가볍고 흙이 간단합니다. 처음했을 때 우스운 냄새가 났지만 전역 logfile변수 보다 냄새가 더 좋다고 믿었습니다 .


답변

함수 속성을 사용하여 코드와 관련 데이터를 함께 감싸는 간단한 클로저를 작성할 수 있습니다.

#!/usr/bin/env python

SW_DELTA = 0
SW_MARK  = 1
SW_BASE  = 2

def stopwatch():
   import time

   def _sw( action = SW_DELTA ):

      if action == SW_DELTA:
         return time.time() - _sw._time

      elif action == SW_MARK:
         _sw._time = time.time()
         return _sw._time

      elif action == SW_BASE:
         return _sw._time

      else:
         raise NotImplementedError

   _sw._time = time.time() # time of creation

   return _sw

# test code
sw=stopwatch()
sw2=stopwatch()
import os
os.system("sleep 1")
print sw() # defaults to "SW_DELTA"
sw( SW_MARK )
os.system("sleep 2")
print sw()
print sw2()

1.00934004784

2.00644397736

3.01593494415


답변

이 도우미 데코레이터를 만들어 기능 속성을 쉽게 설정할 수 있습니다.

def with_attrs(**func_attrs):
    """Set attributes in the decorated function, at definition time.
    Only accepts keyword arguments.
    E.g.:
        @with_attrs(counter=0, something='boing')
        def count_it():
            count_it.counter += 1
        print count_it.counter
        print count_it.something
        # Out:
        # >>> 0
        # >>> 'boing'
    """
    def attr_decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            return fn(*args, **kwargs)

        for attr, value in func_attrs.iteritems():
            setattr(wrapper, attr, value)

        return wrapper

    return attr_decorator

유스 케이스는 팩토리 콜렉션을 작성하고 함수 메타 레벨에서 작성할 수있는 데이터 유형을 조회하는 것입니다.
예를 들어 (매우 바보 같은) :

@with_attrs(datatype=list)
def factory1():
    return [1, 2, 3]

@with_attrs(datatype=SomeClass)
def factory2():
    return SomeClass()

factories = [factory1, factory2]

def create(datatype):
    for f in factories:
        if f.datatype == datatype:
            return f()
    return None


답변

때로는 이미 계산 된 값을 캐싱하기 위해 함수의 속성을 사용합니다. 이 방법을 일반화하는 일반 데코레이터를 사용할 수도 있습니다. 동시성 문제와 이러한 기능의 부작용에주의하십시오!