투명 프록시 (사용 중단됨)

Warning

이는 오래전에 실험적으로 시도되었던 기능이며, 정말 좋은 사용 사례를 찾지 못했습니다. 기본 기능은 여전히 남아 있지만, 사용을 권장하지는 않습니다. 아래 예제 중 일부는 더 이상 동작하지 않을 수 있습니다(예를 들어, 더 이상 리스트 객체를 tproxy할 수 없습니다). 나머지는 표준 Python으로 직접 구현하면 됩니다. tproxy 작업에 다시 관심 있는 분이 있다면 환영하지만, 우리는 이를 흥미로운 확장 기능으로 여기지 않습니다.

PyPy의 투명 프록시(Transparent Proxies)는 객체에 대한 연산을 호출 가능한 객체(callable)로 라우팅할 수 있게 해줍니다. 애플리케이션 수준(application-level) 코드는 타입 시스템을 방해하지 않으면서 객체를 커스터마이즈할 수 있습니다 - proxied_list가 프록시된 내장 list일 때 type(proxied_list) is list는 참을 유지합니다 - 동시에 proxied_list에서 수행되는 모든 연산에 대한 완전한 제어권을 제공합니다.

투명 프록시(transparent proxies)의 더 많은 맥락, 동기, 사용법에 대해서는 [D12.1]을 참고하십시오.

핵심 메커니즘의 예시

다음 예제는 리스트를 프록시하며, 모든 덧셈 연산에 대해 42를 반환합니다:

$ py.py --objspace-std-withtproxy
>>>> from __pypy__ import tproxy
>>>> def f(operation, *args, **kwargs):
>>>>    if operation == '__add__':
>>>>         return 42
>>>>    raise AttributeError
>>>>
>>>> i = tproxy(list, f)
>>>> type(i)
list
>>>> i + 3
42

내장 객체(builtins)에 대한 모든 연산 기록 예시

나중에 분석하기 위해 자신에게 수행된 모든 연산을 저장하는 리스트를 갖고 싶다고 가정하십시오. 내장 인스턴스를 투명하게 프록시하는 데 도움을 주기 위해 lib_pypy/tputil.py 모듈을 사용할 수 있습니다:

from tputil import make_proxy

history = []
def recorder(operation):
    history.append(operation)
    return operation.delegate()

>>>> l = make_proxy(recorder, obj=[])
>>>> type(l)
list
>>>> l.append(3)
>>>> len(l)
1
>>>> len(history)
2

make_proxy(recorder, obj=[])는 연산을 recorder() 함수로 위임할 수 있게 해주는 투명한 리스트 프록시를 생성합니다. type(l)을 호출해도 어떤 연산도 전혀 실행되지 않습니다.

유의할 점은 append()__getattribute__()로 나타나고, type(l)은 전혀 나타나지 않는다는 것입니다 - 타입은 프록시 컨트롤러가 변경할 수 없는 인스턴스의 유일한 측면입니다.

Transparent Proxy를 위한 PyPy 내장 기능 및 지원

–objspace-std-withtproxy옵션을 사용하는 경우, __pypy__ 모듈은 다음과 같은 빌트인을 제공합니다:

tproxy(type, controller)

Returns a proxy object representing the given type and forwarding all operations on this type to the controller. On each operation, controller(opname, *args, **kwargs) will be called.

get_tproxy_controller(obj)

Returns the responsible controller for a given object. For non-proxied objects None is returned.

tputil 헬퍼 모듈

모듈 lib_pypy/tputil.py는 다음을 제공합니다:

make_proxy(controller, type, obj)

Creates a transparent proxy controlled by the given controller callable. The proxy will appear as a completely regular instance of the given type, but all operations on it are sent to the specified controller - which receives a ProxyOperation instance on each operation. If type is not specified, it defaults to type(obj) if obj is specified.

ProxyOperation instances have the following attributes:

proxyobj

The transparent proxy object of this operation.

opname

The name of this operation.

args

Any positional arguments for this operation.

kwargs

Any keyword arguments for this operation.

obj

(Only if provided to make_proxy())

A concrete object.

delegate()

If a concrete object instance obj was specified in the call to make_proxy(), then proxyoperation.delegate() can be called to delegate the operation to the object instance.

추가로 살펴볼 만한 내용

투명 프록시를 사용하여 다음을 포함한 다양한 작업을 수행할 수 있습니다:

  • 직접 연산을 수행할 수 있는 원격 객체 버전(투명 분산을 생각해 보세요)
  • 데이터베이스와 같은 영구 저장소에 대한 접근(다른 객체처럼 보이는 SQL 객체 매퍼를 상상해보십시오).
  • 다른 언어와 같은 외부 데이터 구조에 일반 객체로 접근할 수 있습니다(물론 일부 연산은 예외를 발생시킬 수 있지만, 연산이 애플리케이션 수준에서 실행되므로 큰 문제는 아닙니다)

구현 노트

PyPy의 표준 객체 공간(object space)은 내부적으로 하나의 타입에 대해 여러 구현을 가지고 실행 시간에 구현을 변경할 수 있게 해주지만, 애플리케이션 레벨 코드는 항상 정확히 동일한 타입과 객체를 보게 됩니다. 이 기능들을 사용한 여러 성능 최적화가 이미 구현되어 있습니다: 대체 객체 구현. Transparent Proxy는 이 아키텍처를 사용하여 애플리케이션 레벨 코드에 제어권을 돌려줍니다.

투명 프록시는 표준 객체 공간(object space)를 기반으로 pypy/objspace/std/proxyobject.py, pypy/objspace/std/proxyobject.py, pypy/objspace/std/transparent.py에 구현되어 있습니다. 이를 사용하려면 pypy또는 translate.py–objspace-std-withtproxy 옵션을 전달해야 합니다. 이는 W_TransparentXxx라는 이름의 구현을 등록합니다. - 이는 보통 적절한 W_XxxObject에 대응하며 - 그리고 표준 객체 공간(object space)에서 구현하기에는 인터프리터와 지나치게 밀접한 객체를 위해 몇 가지 인터프리터 핵(hack)을 포함합니다. 이런 방식으로 프록시할 수 있는 객체 유형은 사용자가 생성한 클래스 및 함수, 리스트, 딕셔너리, 예외, 트레이스백, 프레임입니다.

[D12.1]고수준 백엔드와 인터프리터 기능 프로토타입, PyPy EU-Report, 2007, https://foss.heptapod.net/pypy/extradoc/-/tree/branch/extradoc/eu-report/D12.1_H-L-Backends_and_Feature_Prototypes-2007-03-22.pdf