파이썬 기능은 descriptors입니다. 당신은 단순히 dir
의보고하여이를 확인할 수 있습니다
>>> def fn(self):
... pass
...
>>> dir(fn)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
>>> fn.__get__
<method-wrapper '__get__' of function object at 0x7fa5585550c8>
을 주목 __get__
method. 우리는 바인딩 된 메서드를 생산하기 위해 이것을 사용할 수 있습니다 :
>>> class Bar(object): pass
...
>>> b = Bar()
>>> fn.__get__(b, Bar)
<bound method Bar.fn of <__main__.Bar object at 0x7fa5585cdcd0>>
는 사실, 이것은 당신이 함수 클래스에 속성을 액세스 할 때 파이썬은 자동으로 당신을 위해 무엇이다.
이제 캐싱 문제에 대해 - 어디서나 클래스에 기능을 추가 할 수 있습니다. 위의 경우와 마찬가지로 모든 클래스에 바운드 메서드를 추가 할 수 있습니다. b.fn = fn.__get__(b, Bar)
을 할당하면 b
의 메서드는 fn
이고 다른 인스턴스 인 Bar
에는 해당 메서드가 없습니다. 여러 클래스에서이 작업을 수행 할 수 있습니다. 디스크립터가 값을 캐쉬했다면 인스턴스와 클래스를 찾은 조회 테이블을 유지하여 해당 인스턴스와 클래스에 대한 바인딩 된 메서드가 이미 생성되었는지 확인해야합니다. A
및 B
이 같은 기능에 대한 참조를 유지하는 것이
가
def fn(self):
return self
class A(object):
fn = fn
class B(object):
fn = fn
공지 사항 - 그리고 그들은 모두 그 속성이 인스턴스에 액세스 할 때 필요한 바인딩 방법을 생성 할 수 있습니다 : 여기에 간단한 예입니다.
self
은 해시 가능하지 않을 수 있으므로 조회 표는 처음부터 생성하는 데 문제가 있습니다.매번 새로운 인스턴스를 만드는 주된 이유 일 것입니다. 이 아닌 경우에도 조회 테이블은 실제 참조가 아닌 약한 참조를 저장해야하므로 필요한 경우 가비지 수집이 가능합니다. 나는 새로운 바운드 메소드를 만드는 것이 weakrefs로 작업 할 때 lookup과 resolution을하는 것만큼이나 빠름을이 짐작하고있다.