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
}