.. File: types-defined-in-java.rst Types Defined in Java ##################### Introduction ************ Feature ======= In Python, methods are objects:: >>> class C: ... def g(self): pass ... >>> C.g >>> C().g > >>> type(C.g) >>> type(C().g) Notice that the expressions ``C.g`` (the attribute ``g`` of the type ``C``), and ``C().g`` (the attribute ``g`` of an instance of type ``C``), are different. Although their Python type is technically the same, the bound method object has a reference to ``self`` baked into its value. When methods are defined in the implementation language, whether C or Java, they must be exposed at the Python level as Python objects:: >>> float.is_integer >>> (1.0).is_integer >>> type(float.is_integer) >>> type((1.0).is_integer) How are methods defined in C or Java exposed for the interpreter to handle as Python objects? Exposure in CPython =================== The CPython approach is well-documented in `Extending and Embedding the Python Interpreter`_. For comparison with Jython, we'll look at some examples from the CPython code base. .. _Extending and Embedding the Python Interpreter: https://docs.python.org/2.7/extending/index.html#extending-and-embedding-the-python-interpreter Approach used in Jython *********************** Code generated by exposing a method =================================== Amongst other things, the exposer creates: .. code-block:: text public class org.python.core.PyFloat$float___repr___exposer extends org.python.core.PyBuiltinMethodNarrow { ... public org.python.core.PyObject __call__(); Code: 0: aload_0 1: getfield #38 // Field self:Lorg/python/core/PyObject; 4: checkcast #40 // class org/python/core/PyFloat 7: invokevirtual #44 // Method org/python/core/PyFloat.float___repr__:()Lorg/python/core/PyString; 10: areturn } Clearly this calls the method ``PyFloat.float___repr__()`` that we decorated, using ``invokevirtual``. Exposing non-final methods ========================== Occasionally, we find that the normal pattern of implementation is broken, as in ``PyFloat`` (at the time of writing): .. code-block:: java @ExposedMethod(doc = BuiltinDocs.float_hex_doc) public PyObject float_hex() { return new PyString(pyHexString(getValue())); } @ExposedMethod(doc = BuiltinDocs.float_as_integer_ratio_doc) public PyTuple as_integer_ratio() { // ... implementation omitted ... return new PyTuple(numerator, denominator); } The overridable ``float_hex`` and ``as_integer_ratio`` are exposed, not a final method. The name ``float_hex`` is what we would expect. Notice that the exposer is able to infer the name ``hex``, since it knows that the class is exposed as ``float``, it knows to remove ``float_`` from the front of the name. In the second case, the exact Java name ``as_integer_ratio``, since it does not begin , is the name of this method in the dictionary. What difference does it make that these mathods are not final? None to the wrapper object that appears in the dictionary: .. code-block:: text public class org.python.core.PyFloat$float_hex_exposer extends org.python.core.PyBuiltinMethodNarrow { public org.python.core.PyObject __call__(); Code: 0: aload_0 1: getfield #38 // Field self:Lorg/python/core/PyObject; 4: checkcast #40 // class org/python/core/PyFloat 7: invokevirtual #43 // Method org/python/core/PyFloat.float_hex:()Lorg/python/core/PyObject; 10: areturn } public class org.python.core.PyFloat$as_integer_ratio_exposer extends org.python.core.PyBuiltinMethodNarrow { public org.python.core.PyObject __call__(); Code: 0: aload_0 1: getfield #38 // Field self:Lorg/python/core/PyObject; 4: checkcast #40 // class org/python/core/PyFloat 7: invokevirtual #44 // Method org/python/core/PyFloat.as_integer_ratio:()Lorg/python/core/PyTuple; 10: areturn }