Types Defined in Java

Introduction

Feature

In Python, methods are objects:

>>> class C:
...     def g(self): pass
...
>>> C.g
<unbound method C.g>
>>> C().g
<bound method C.g of <__main__.C instance at 0x00000000033A2848>>
>>> type(C.g)
<type 'instancemethod'>
>>> type(C().g)
<type 'instancemethod'>

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
<method 'is_integer' of 'float' objects>
>>> (1.0).is_integer
<built-in method is_integer of float object at 0x00000000031F50E8>
>>> type(float.is_integer)
<type 'method_descriptor'>
>>> type((1.0).is_integer)
<type 'builtin_function_or_method'>

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.

Approach used in Jython

Code generated by exposing a method

Amongst other things, the exposer creates:

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):

@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:

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
}