객체 공간(object space) ======================= .. contents:: .. _objectspace: .. _Object Space: 소개 ---- 객체 공간(object space)은 PyPy에서 모든 객체를 생성하며, 그 객체에 대한 연산을 수행하는 방법을 알고 있습니다. 객체 공간(object space)을 고정된 API, 즉 Python 객체의 알려진 의미론에 대응하는 구현과 함께 하는 일련의 *연산*\ 을 제공하는 라이브러리로 생각하면 도움이 될 수 있습니다. 예를 들어, :py:func:`add`\ 는 연산이며, 객체 공간(object space)에는 (:py:func:`add`\ 가 숫자에 대해 동작할 때는) 숫자 덧셈을, (:py:func:`add`\ 가 시퀀스에 대해 동작할 때는) 연결(concatenation)을 수행하는 등의 구현들이 있습니다. 바이트코드 인터프리터에 연결\ 될 수 있는 몇 가지 작동하는 객체 공간(object space)이 있습니다: - *표준 객체 공간(object space)*\ 은 파이썬의 다양한 내장 타입과 객체에 대한 완전한 구현입니다. 표준 객체 공간(object space)은 바이트코드 인터프리터와 함께 우리 파이썬 구현의 기반입니다. 내부적으로 이것은 정수, 문자열, 리스트, 타입 등 다양한 :ref:`application-level ` 객체를 구현하는 :ref:`interpreter-level ` 클래스의 집합입니다. CPython과 비교하자면, 표준 객체 공간(object space)은 C 구조체 :c:type:`PyIntObject`, :c:type:`PyListObject` 등에 상응하는 것을 제공합니다. - 다양한 `객체 공간(object space) 프록시`_\ 는 다른 객체 공간(object space)(예: 표준 객체 공간)을 감싸고, 지연 계산 객체(연산이 수행될 때만 계산되는 객체), 보안 검사 객체, 여러 기계에 분산되어 있는 분산 객체 등과 같은 새로운 기능을 추가합니다. 여기에 문서화된 다양한 객체 공간(object space)들은 :source:`pypy/objspace`\ 에서 찾을 수 있습니다. 대부분의 객체 공간(object space) 연산은 :ref:`application-level ` 객체를 받아 반환하며, 인터프리터는 이 객체를 불투명한 "블랙박스"로 취급합니다. 극히 일부 연산만이 바이트코드 인터프리터가 application-level 객체의 값에 대해 어느 정도 알 수 있게 해줍니다. .. _objspace-interface: 객체 공간(object space) 인터페이스 ---------------------------------- 이것은 모든 객체 공간(object space)이 구현하는 공개 API입니다: 관리 함수 ~~~~~~~~~ .. py:function:: getexecutioncontext() Return the currently active execution context. (:source:`pypy/interpreter/executioncontext.py`). .. py:function:: getbuiltinmodule(name) Return a :py:class:`Module` object for the built-in module given by ``name``. (:source:`pypy/interpreter/module.py`). 객체 공간(object space)의 객체에 대한 연산 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 이 함수들은 "래핑된"(즉, :ref:`application-level `) 객체를 받고 반환합니다. 다음 함수들은 언어 수준 구문에 직접 대응하는, 명확한 의미를 가진 연산을 구현합니다: ``id, type, issubtype, iter, next, repr, str, len, hash,`` ``getattr, setattr, delattr, getitem, setitem, delitem,`` ``pos, neg, abs, invert, add, sub, mul, truediv, floordiv, div, mod, divmod, pow, lshift, rshift, and_, or_, xor,`` ``nonzero, hex, oct, int, float, long, ord,`` ``lt, le, eq, ne, gt, ge, cmp, coerce, contains,`` ``inplace_add, inplace_sub, inplace_mul, inplace_truediv, inplace_floordiv, inplace_div, inplace_mod, inplace_pow, inplace_lshift, inplace_rshift, inplace_and, inplace_or, inplace_xor,`` ``get, set, delete, userdel`` .. py:function:: call(w_callable, w_args, w_kwds) Calls a function with the given positional (``w_args``) and keyword (``w_kwds``) arguments. .. py:function:: index(w_obj) Implements index lookup (`as introduced in CPython 2.5`_) using ``w_obj``. Will return a wrapped integer or long, or raise a :py:exc:`TypeError` if the object doesn't have an :py:func:`__index__` special method. .. _as introduced in CPython 2.5: https://www.python.org/dev/peps/pep-0357/ .. py:function:: is_(w_x, w_y) Implements ``w_x is w_y``. .. py:function:: isinstance(w_obj, w_type) Implements :py:func:`issubtype` with ``type(w_obj)`` and ``w_type`` as arguments. .. py:function::exception_match(w_exc_type, w_check_class) Checks if the given exception type matches :py:obj:`w_check_class`. Used in matching the actual exception raised with the list of those to catch in an except clause. 편의 함수 ~~~~~~~~~ 다음 함수들은 매우 자주 사용되어\ 서 단축 표현으로 도입할 가치가 있었습니다. 다만, 다른 여러 객체 공간(object space) 메서드를 사용하여 표현할 수 있으므로 반드시 필요한 것은 아닙니다. .. py:function:: eq_w(w_obj1, w_obj2) Returns :py:const:`True` when :py:obj:`w_obj1` and :py:obj:`w_obj2` are equal. Shortcut for ``space.is_true(space.eq(w_obj1, w_obj2))``. .. py:function:: is_w(w_obj1, w_obj2) Shortcut for ``space.is_true(space.is_(w_obj1, w_obj2))``. .. py:function:: hash_w(w_obj) Shortcut for ``space.int_w(space.hash(w_obj))``. .. py:function:: len_w(w_obj) Shortcut for ``space.int_w(space.len(w_obj))``. 위 네 함수가 :ref:`application-level ` 객체가 아니라 :ref:`interpreter-level ` 객체를 반환한다는 점에 *주의*\ 하십시오! .. py:function:: not_(w_obj) Shortcut for ``space.newbool(not space.is_true(w_obj))``. .. py:function:: finditem(w_obj, w_key) Equivalent to ``getitem(w_obj, w_key)`` but returns an **interpreter-level** None instead of raising a KeyError if the key is not found. .. py:function:: call_function(w_callable, *args_w, **kw_w) Collects the arguments in a wrapped tuple and dict and invokes ``space.call(w_callable, ...)``. .. py:function:: call_method(w_object, 'method', ...) Uses :py:meth:`space.getattr` to get the method object, and then :py:meth:`space.call_function` to invoke it. .. py:function:: unpackiterable(w_iterable[, expected_length=-1]) Iterates over :py:obj:`w_x` (using :py:meth:`space.iter` and :py:meth:`space.next`) and collects the resulting wrapped objects in a list. If ``expected_length`` is given and the length does not match, raises an exception. Of course, in cases where iterating directly is better than collecting the elements in a list first, you should use :py:meth:`space.iter` and :py:meth:`space.next` directly. .. py:function:: unpacktuple(w_tuple[, expected_length=None]) Equivalent to :py:func:`unpackiterable`, but only for tuples. .. py:function:: callable(w_obj) Implements the built-in :py:func:`callable`. 애플리케이션 레벨 객체 생성 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. py:function:: wrap(x) **Deprecated! Eventually this method should disappear.** Returns a wrapped object that is a reference to the interpreter-level object :py:obj:`x`. This can be used either on simple immutable objects (integers, strings, etc.) to create a new wrapped object, or on instances of :py:class:`W_Root` to obtain an application-level-visible reference to them. For example, most classes of the bytecode interpreter subclass :py:class:`W_Root` and can be directly exposed to application-level code in this way - functions, frames, code objects, etc. .. py:function:: newint(i) Creates a wrapped object holding an integral value. ``newint`` creates an object of type ``W_IntObject``. .. py:function:: newlong(l) Creates a wrapped object holding an integral value. The main difference to ``newint`` is the type of the argument (which is ``rpython.rlib.rbigint.rbigint``). On PyPy3 this method will return an :py:class:`int` (PyPy2 it returns a :py:class:`long`). .. py:function:: newbytes(t) The given argument is a rpython bytestring. Creates a wrapped object of type :py:class:`bytes` (both on PyPy2 and PyPy3). .. py:function:: newtext(t) The given argument is a rpython bytestring. Creates a wrapped object of type :py:class:`str`. On PyPy3 this will return a wrapped unicode object. The object will hold a utf-8-nosg decoded value of `t`. The "utf-8-nosg" codec used here is slightly different from the "utf-8" implemented in Python 2 or Python 3: it is defined as utf-8 without any special handling of surrogate characters. They are encoded using the same three-bytes sequence that encodes any char in the range from ``'\u0800'`` to ``'\uffff'``. PyPy2 will return a bytestring object. No encoding/decoding steps will be applied. .. py:function:: newbool(b) Creates a wrapped :py:class:`bool` object from an :ref:`interpreter-level ` object. .. py:function:: newtuple([w_x, w_y, w_z, ...]) Creates a new wrapped tuple out of an interpreter-level list of wrapped objects. .. py:function:: newlist([..]) Creates a wrapped :py:class:`list` from an interpreter-level list of wrapped objects. .. py:function:: newdict Returns a new empty dictionary. .. py:function:: newslice(w_start, w_end, w_step) Creates a new slice object. .. py:function:: newunicode(ustr) Creates a Unicode string from an rpython unicode string. This method may disappear soon and be replaced by :py:function:`newutf8`. .. py:function:: newutf8(bytestr) Creates a Unicode string from an rpython byte string, decoded as "utf-8-nosg". On PyPy3 it is the same as :py:function:`newtext`. 더 많은 공간(space) 연산은 :source:`pypy/interpreter/baseobjspace.py`\ 와 :source:`pypy/objspace/std/objspace.py`\ 에서 찾을 수 있습니다. 애플리케이션 레벨에서 인터프리터 레벨로의 변환 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. py:function:: unwrap(w_x) Returns the interpreter-level equivalent of :py:obj:`w_x` -- use this **ONLY** for testing, because this method is not RPython and thus cannot be translated! In most circumstances you should use the functions described below instead. .. py:function:: is_true(w_x) Returns an interpreter-level boolean (:py:const:`True` or :py:const:`False`) that gives the truth value of the wrapped object :py:obj:`w_x`. This is a particularly important operation because it is necessary to implement, for example, if-statements in the language (or rather, to be pedantic, to implement the conditional-branching bytecodes into which if-statements are compiled). .. py:function:: int_w(w_x) If :py:obj:`w_x` is an application-level integer or long which can be converted without overflow to an integer, return an interpreter-level integer. Otherwise raise :py:exc:`TypeError` or :py:exc:`OverflowError`. .. py:function:: bigint_w(w_x) If :py:obj:`w_x` is an application-level integer or long, return an interpreter-level :py:class:`rbigint`. Otherwise raise :py:exc:`TypeError`. .. automethod:: pypy.interpreter.baseobjspace.ObjSpace.bytes_w(w_x) .. automethod:: pypy.interpreter.baseobjspace.ObjSpace.text_w(w_x) .. py:function:: str_w(w_x) **Deprecated. use text_w or bytes_w instead** If :py:obj:`w_x` is an application-level string, return an interpreter-level string. Otherwise raise :py:exc:`TypeError`. .. py:function:: unicode_w(w_x) Takes an application level :py:class:`unicode` and return an interpreter-level unicode string. This method may disappear soon and be replaced by :py:function:`text_w`. .. py:function:: float_w(w_x) If :py:obj:`w_x` is an application-level float, integer or long, return an interpreter-level float. Otherwise raise :py:exc:`TypeError` (or:py:exc:`OverflowError` in the case of very large longs). .. py:function:: getindex_w(w_obj[, w_exception=None]) Call ``index(w_obj)``. If the resulting integer or long object can be converted to an interpreter-level :py:class:`int`, return that. If not, return a clamped result if :py:obj:`w_exception` is None, otherwise raise the exception at the application level. (If :py:obj:`w_obj` can't be converted to an index, :py:func:`index` will raise an application-level :py:exc:`TypeError`.) .. py:function:: interp_w(RequiredClass, w_x[, can_be_None=False]) If :py:obj:`w_x` is a wrapped instance of the given bytecode interpreter class, unwrap it and return it. If :py:obj:`can_be_None` is :py:const:`True`, a wrapped :py:const:`None` is also accepted and returns an interpreter-level :py:const:`None`. Otherwise, raises an :py:exc:`OperationError` encapsulating a :py:exc:`TypeError` with a nice error message. .. py:function:: interpclass_w(w_x) If :py:obj:`w_x` is a wrapped instance of an bytecode interpreter class -- for example :py:class:`Function`, :py:class:`Frame`, :py:class:`Cell`, etc. -- return it unwrapped. Otherwise return :py:const:`None`. 데이터 멤버 ~~~~~~~~~~~ .. py:data:: space.builtin The :py:class:`Module` containing the builtins. .. py:data:: space.sys The ``sys`` :py:class:`Module`. .. py:data:: space.w_None The ObjSpace's instance of :py:const:`None`. .. py:data:: space.w_True The ObjSpace's instance of :py:const:`True`. .. py:data:: space.w_False The ObjSpace's instance of :py:const:`False`. .. py:data:: space.w_Ellipsis The ObjSpace's instance of :py:const:`Ellipsis`. .. py:data:: space.w_NotImplemented The ObjSpace's instance of :py:const:`NotImplemented`. .. py:data:: space.w_int space.w_float space.w_long space.w_tuple space.w_str space.w_unicode space.w_type space.w_instance space.w_slice Python's most common basic type objects. .. py:data:: space.w_[XYZ]Error Python's built-in exception classes (:py:class:`KeyError`, :py:class:`IndexError`, etc). .. TODO: is it worth listing out all ~50 builtin exception types (https://docs.python.org/2/library/exceptions.html)? .. py:data:: ObjSpace.MethodTable List of tuples containing ``(method_name, symbol, number_of_arguments, list_of_special_names)`` for the regular part of the interface. *NOTE* that tuples are interpreter-level. .. py:data:: ObjSpace.BuiltinModuleTable List of names of built-in modules. .. py:data:: ObjSpace.ConstantTable List of names of the constants that the object space should define. .. py:data:: ObjSpace.ExceptionTable List of names of exception classes. .. py:data:: ObjSpace.IrregularOpTable List of names of methods that have an irregular API (take and/or return non-wrapped objects). .. _standard-object-space: 표준 객체 공간(object space) ---------------------------- 소개 ~~~~ 표준 객체 공간(object space)(:source:`pypy/objspace/std/`)은 CPython의 객체 라이브러리(배포판의 ``Objects/`` 하위 디렉터리)에 직접 대응합니다. 이는 공통 파이썬 타입들을 더 낮은 수준의 언어로 구현한 것입니다. 표준 객체 공간(object space)은 추상 부모 클래스인 :py:class:`W_Object`\ 뿐만 아니라 :py:class:`W_IntObject`, :py:class:`W_ListObject` 등과 같은 하위 클래스도 정의합니다. 래핑된 객체(바이트코드 인터프리터의 메인 루프에게는 "블랙박스")는 이 클래스들 중 하나의 인스턴스입니다. 메인 루프가 두 래핑된 객체 :py:obj:`w1`\ 과 :py:obj:`w2` 사이에서 (덧셈과 같은) 연산을 호출하면, 표준 객체 공간(object space)은 (CPython의\ ``Object/abstract.c``\ 와 유사한) 내부 디스패치를 수행하고, 해당 연산을 수행할 수 있는 적절한 :py:class:`W_XYZObject` 클래스의 메서드를 호출합니다. 연산 자체는 RPython이 허용하는 기본 연산(primitive)으로 수행되며, 결과는 래핑된(wrapped) 객체로 구성됩니다. 예를 들어, 다음의 정수 덧셈 구현을 ``Object/intobject.c``\ 안의 :c:func:`int_add()` 함수와 비교해 보십시오: :: def add__Int_Int(space, w_int1, w_int2): x = w_int1.intval y = w_int2.intval try: z = ovfcheck(x + y) except OverflowError: raise FailedToImplementArgs(space.w_OverflowError, space.wrap("integer addition")) return W_IntObject(space, z) 정수 객체만을 위해 이렇게 많은 작업을 하는 것처럼 보일 수도 있습니다(왜 일반 정수를 사용하는 대신 :py:class:`W_IntObject` 인스턴스로 감싸는 걸까요?), 하지만 모든 객체(단순한 정수부터 더 복잡한 타입까지)를 동일한 방식으로 감쌈으로써 코드는 단순하고 읽기 쉽게 유지됩니다. (흥미롭게도, 위의 명백한 최적화는 실제로 PyPy에서 이루어졌지만, 이 수준에서 하드코딩되어 있지는 않습니다 -- :doc:`interpreter-optimizations`\ 를 참조하십시오.) 객체 타입 ~~~~~~~~~ 대부분의 :source:`pypy/objspace/std/` 패키지 코드는 파이썬의 표준 내장 객체 타입 라이브러리를 정의하고 구현합니다. 각 타입 ``xxx`` (:py:class:`int`, :py:class:`float`, :py:class:`list`, :py:class:`tuple`, :py:class:`str`, :py:class:`type` 등)은 일반적으로 ``xxxobject.py`` 모듈에서 구현됩니다. ``W_AbstractXxxObject``\ 클래스는 존재하는 경우 추상 베이스 클래스이며, 주로 Python 레벨 타입 객체에 나타나는 것을 정의합니다. 그런 다음 서브클래스로서 실제 구현체들이 있는데, 여러 다른 구현체가 있는 경우에는 ``W_XxxObject``\ 또는 그 변형으로 불립니다. 예를 들어, :source:`pypy/objspace/std/bytesobject.py`\ 는 ``str``\ 앱 레벨 타입을 만드는 데 필요한 모든 것을 담고 있는 ``W_AbstractBytesObject``\ 를 정의합니다. 그리고 서브클래스로 ``W_BytesObject`` (일반적인 문자열)와 ``W_Buffer`` (반복적인 추가에 맞춰 조정된 특수 구현으로, :source:`pypy/objspace/std/bufferobject.py`\ 에 있음)가 있습니다. 리스트나 딕셔너리와 같은 가변 데이터 타입의 경우, 실제 데이터에 대한 간접 참조와 전략(strategy)을 가진 단일 클래스 ``W_ListObject``\ 또는 ``W_DictMultiObject``\ 가 있습니다. 이 전략은 객체의 내용이 변경됨에 따라 바뀔 수 있습니다. 사용자 관점에서 볼 때, ``W_AbstractXxxObject`` 하위 클래스가 여러 개 있더라도 이는 보이지 않습니다: 앱 레벨에서는 여전히 모두 정확히 동일한 Python 타입의 인스턴스입니다. PyPy는 (예를 들어) 인터프리터 레벨의 ``W_BytesObject`` 인스턴스의 애플리케이션 레벨 타입이 str이라는 것을 알고 있는데, 이는 ``W_BytesObject``\ 에 :source:`pypy/objspace/std/bytesobject.py`\ 의 문자열 타입 명세를 가리키는 ``typedef`` 클래스 속성이 있기 때문입니다; 문자열의 다른 모든 구현체도 :source:`pypy/objspace/std/bytesobject.py`\ 의 동일한 ``typedef``\ 를 사용합니다. 동일한 Python 타입에 대한 여러 구현의 다른 예시는 :doc:`interpreter-optimizations`\ 를 참고하십시오. .. _yeokja-doc-2b3bab3cd83d237b-target-18301: 객체 공간(object space) 프록시 ------------------------------ 우리는 다른 객체 공간(일반적으로 표준 객체 공간)을 감싸 모든 객체에 몇 가지 기능을 추가하는 여러 *프록시 객체 공간(object space)*\ 들을 구현했습니다. 더 알아보려면 :doc:`objspace-proxies`\ 를 참고하십시오.