Я хотел посмотреть, сохраняются ли комментарии или строки в файлах $ py.class, поэтому я попытался поэкспериментировать с Jython 2.5.3 и Jython 2.7.0. (В моем случае исходные файлы .py не делаются опубликованными c, но файлы $ py.class являются частью публикуемого файла .jar; я не хочу, чтобы некоторые комментарии были видны)
C:\tmp\jython>java -jar c:\app\java\lib\jython-standalone-2.7.0.jar
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_152
Type "help", "copyright", "credits" or "license" for more information.
>>> import py_compile
>>> py_compile.compile('loose_lips.py')
, где содержитoose_lips.py:
def loose_lips_sink_ships(x):
"""CM1 Doc comment"""
# CM2 line comment
"""
CM3 Another multiline string that doesn't do anything
but is not a doc comment
"""
return x+1
"""
CM4 Yet another comment that could theoretically
be optimized out, since we can never get here
"""
Я предсказал, что CM1 будет единственным строковым содержимым, сохраняемым в результирующем выводе, потому что он имеет четко определенную семантику в Python --- это строка документации, поэтому она вставляется в loose_lips.loose_lips_sink_ships.__doc__
. Нет никаких оснований для того, чтобы все остальное заканчивалось каким-либо кодом времени выполнения.
Если я запускаю py_compile.compile('loose_lips.py')
в Python 2.7.14 (или просто import loose_lips
), тогда он генерирует файл .py c содержит байт-код и единственный сохраненный текст - CM1, как и предсказывалось.
Если я запускаю py_compile.compile('loose_lips.py')
в Jython 2.5.3 или Jython 2.7.0, то полученный файл $ py.class содержит CM1 и CM3.
Почему CM3 сохраняется во время выполнения? Есть ли какое-либо внешне видимое поведение, которое пытается обеспечить интерпретатор Jython (например, сохранение исходного кода?), Которое требует сохранения многострочных строк? Можно ли это как-то предотвратить?
Я декомпилировал файл $ py.class в http://www.javadecompilers.com и вот результаты:
import org.python.core.PyRunnableBootstrap;
import org.python.core.CodeBootstrap;
import org.python.core.CodeLoader;
import org.python.core.PyFunction;
import org.python.core.PyString;
import org.python.core.Py;
import org.python.core.PyObject;
import org.python.core.ThreadState;
import org.python.core.PyFrame;
import org.python.core.PyCode;
import org.python.compiler.Filename;
import org.python.compiler.MTime;
import org.python.compiler.APIVersion;
import org.python.core.PyRunnable;
import org.python.core.PyFunctionTable;
//
// Decompiled by Procyon v0.5.36
//
@APIVersion(36)
@MTime(1578883953709L)
@Filename("loose_lips.py")
public class loose_lips$py extends PyFunctionTable implements PyRunnable
{
static loose_lips$py self;
static final PyCode f$0;
static final PyCode loose_lips_sink_ships$1;
public PyObject f$0(final PyFrame pyFrame, final ThreadState threadState) {
pyFrame.setline(1);
pyFrame.setlocal("loose_lips_sink_ships", (PyObject)new PyFunction(pyFrame.f_globals, Py.EmptyObjects, loose_lips$py.loose_lips_sink_ships$1, (PyObject)PyString.fromInterned("CM1 Doc comment")));
pyFrame.f_lasti = -1;
return Py.None;
}
public PyObject loose_lips_sink_ships$1(final PyFrame pyFrame, final ThreadState threadState) {
pyFrame.setline(2);
PyString.fromInterned("CM1 Doc comment");
pyFrame.setline(9);
PyString.fromInterned(" \n CM3 Another multiline string that doesn't do anything\n but is not a doc comment\n ");
pyFrame.setline(11);
final PyObject add = pyFrame.getlocal(0)._add((PyObject)Py.newInteger(1));
pyFrame.f_lasti = -1;
return add;
}
public loose_lips$py(final String s) {
loose_lips$py.self = this;
f$0 = Py.newCode(0, new String[0], s, "<module>", 0, false, false, (PyFunctionTable)loose_lips$py.self, 0, (String[])null, (String[])null, 0, 4096);
loose_lips_sink_ships$1 = Py.newCode(1, new String[] { "x" }, s, "loose_lips_sink_ships", 1, false, false, (PyFunctionTable)loose_lips$py.self, 1, (String[])null, (String[])null, 0, 4097);
}
public PyCode getMain() {
return loose_lips$py.f$0;
}
public static void main(final String[] array) {
Py.runMain(CodeLoader.createSimpleBootstrap(new loose_lips$py("loose_lips$py").getMain()), array);
}
public static CodeBootstrap getCodeBootstrap() {
return PyRunnableBootstrap.getFilenameConstructorReflectionBootstrap((Class)loose_lips$py.class);
}
public PyObject call_function(final int n, final PyFrame pyFrame, final ThreadState threadState) {
switch (n) {
case 0: {
return this.f$0(pyFrame, threadState);
}
case 1: {
return this.loose_lips_sink_ships$1(pyFrame, threadState);
}
default: {
return null;
}
}
}
}