Pyjinn
목차
- Pyjinn이란 무엇인가?
- Minescript 5.0의 Pyjinn
- Pyjinn을 사용해야 할 때
- Python 스크립트에 Pyjinn 임베딩하기
- Java 통합
- Python 언어 기능
- Python 3.x 기능 지원
Pyjinn이란 무엇인가?
Pyjinn (“피전(pidgeon)”처럼 발음)은 Java 프로그램과 깊이 통합되는 Python 문법(syntax)을 사용하는 스크립팅 언어(scripting language)입니다. Python처럼 보이고 느껴지지만 구현과 런타임(runtime) 동작은 Java에 기반을 둔 “피진(pidgin)” 언어입니다. (“Pyjinn”이라는 이름은 “Python”과 지니(genie)를 뜻하는 다른 단어인 “jinn”의 합성어입니다.)
Pyjinn은 Python 표준 라이브러리(standard library)를 지원하지 않지만, Pyjinn 스크립트(script)는 Java 표준 라이브러리와 Pyjinn 스크립트가 임베딩된(embedded) Java 프로그램에 로드된 공개적으로 접근 가능한 모든 Java 클래스에 접근할 수 있습니다.
Minescript 5.0의 Pyjinn
Pyjinn은 곧 출시될 Minescript 5.0에 통합되어 있습니다. 이를 통해 Python 문법 스크립트를 별도의 Python 설치(installation) 없이도 Minecraft의 Java 프로세스(process) 내에서 Minescript 모드(mod)가 직접 실행할 수 있습니다. 외부에서 실행하는 Python 스크립트도 계속 지원됩니다. Minescript Python 스크립트와 Minescript Pyjinn 스크립트는 이벤트 처리를 제외하고 동일한 스크립트 API를 공유합니다. Minescript Python 스크립트는 EventQueue 클래스(class)가 관리하는 이벤트 큐(event queue)를 사용하는 반면, Minescript Pyjinn 스크립트는 JavaScript에서 영감을 받은 단일 스레드(thread) 이벤트 처리 방식을 사용합니다:
add_event_listener(event_type: str, callback: Callable[..., None], **args) -> intset_interval(callback: Callable[..., None], timer_millis: int, *args, **kwargs) -> intset_timeout(callback: Callable[..., None], timer_millis: int, *args, **kwargs) -> intremove_event_listener(listener_id: int) -> bool
지원되는 이벤트 유형은 다음과 같습니다:
- “tick”, “render”, “key”, “mouse”, “chat”, “outgoing_chat_intercept”, “add_entity”, “block_update”, “explosion”, “take_item”, “damage”, “chunk”, “world”
또한 Pyjinn 스크립트는 EventLoop 클래스를 사용하여 Python 스크립트의 EventQueue와 유사한 통합 루프(loop)에서
이벤트를 처리할 수 있으며, EventLoop.event()와
EventLoop.sleep()을 사용하는 async/await 문법을 사용합니다:
async def handle_events(event_loop: EventLoop):
while True:
# 3초 동안 이벤트를 기다립니다(매개변수(parameter)를 생략하면 무기한 대기):
event = await event_loop.event(timeout_seconds=3)
if event is None:
print("No events in last 3 seconds. Awaiting more events...")
elif event.type == "mouse":
if event.button == 1 and event.action == 0:
print("Got right-click release. Quitting.")
break
else:
print("Got mouse event.")
event_loop = EventLoop()
event_loop.add_listener("mouse")
event_loop.run(handle_events)
스크립트는 Minescript 표준 라이브러리를 명시적으로 임포트(import)할 수 있습니다. 간단한 IDE 통합(예: VSCode)을 위해서는 다음과 같은 임포트를 사용할 수 있습니다:
from system.pyj.minescript import *import system.pyj.minescript as m
기존 Python 스크립트와의 일관성을 위해서는 다음과 같은 임포트를 사용할 수 있습니다:
from minescript import *import minescriptimport minescript as m
메인 스크립트에 minescript 또는 system.pyj.minescript에 대한 임포트가 없으면
다음과 같이 암묵적으로 임포트됩니다:
from system.pyj.minescript import *
IDE 호환성을 위해 .pyj 파일은 메인 스크립트 파일에만 사용되며
다른 스크립트에서 임포트되지 않습니다. 이는 VSCode와 같은 IDE가 .pyj 파일의
임포트를 인식하지 못하기 때문입니다. Python 문법 지원(구문 강조,
자동 완성 등)을 활성화하려면 .pyj
파일 맨 위에 다음 줄을 추가하세요:
#!python
Pyjinn의 임포트 검색 경로(PYTHONPATH와 동등하지만 현재는 하드코딩(hardcoded)되어 있음)는 다음과 같습니다:
minecraft/minescriptminecraft/minescript/system/pyj
minecraft/minescript 디렉터리(directory)에 있는 Pyjinn 라이브러리는 .py
파일 확장자를 제거하여 임포트할 수 있습니다. 예를 들어 minecraft/minescript/my_kewl_library.py는 다음과 같이 Pyjinn
스크립트에 임포트할 수 있습니다:
import my_kewl_library
Pyjinn 스크립트(.pyj)와 Python 스크립트(.py)는 해당 라이브러리가 Python과 Pyjinn 둘 다와
호환되는 경우 동일한 .py 라이브러리를 임포트할 수 있습니다.
임포트된 .py 라이브러리는 sys.version에 문자열(string) "Pyjinn"이 포함되어 있는지 확인하여
자신이 Pyjinn 컨텍스트(context)에서 실행 중인지 감지할 수 있습니다. 예를 들어 Python 스크립트가
Pyjinn 전용 .py 라이브러리를 임포트하지 못하도록 하려면 라이브러리 맨 위에 다음과 같은 코드를 추가하면 됩니다:
import sys
if "Pyjinn" not in sys.version:
raise ImportError(f"Module '{__name__}' requires a Pyjinn interpreter.")
Pyjinn을 사용해야 할 때
Pyjinn은 다음과 같은 상황에서 가장 유용하게 사용됩니다:
- Python이 설치되어 있지 않은 시스템에서 실행할 수 있는 스크립트를 개발하는 경우.
- 빠르게 시작해야 하며 Python 표준 라이브러리나 서드파티(third-party) Python 라이브러리를 사용하지 않는 스크립트. (Pyjinn 스크립트는 서브프로세스(subprocess)를 생성하는 대신 게임의 Java 프로세스 내부에서 실행되므로 Python 스크립트보다 더 빠르게 시작됩니다.)
- 게임 이벤트와의 동기화(synchronization)가 필요한 스크립트. 예를 들어 게임의 렌더링(rendering) 스레드를 차단한 상태에서 임의로 복잡한 사용자 정의 스크립트 코드를 실행해야 하는 스크립트 기반 게임 렌더링이 있습니다.
Python 스크립트는 Java 코드(Minecraft 코드 및 Minescript Java 코드를 포함해 현재 로드된 모든 모드 코드; java.py
모듈(module) 참고)와 Pyjinn 코드(eval_pyjinn_script() 및
import_pyjinn_script() 참고)를 호출할 수 있습니다.
Java와 Pyjinn은 서로 동기(synchronous) 호출을 할 수 있습니다. 이는 각각이 서로에 대해 함수 또는 메서드(method) 호출을 수행하고 동일한 Java 스레드에서 반환값(return value)을 받을 수 있음을 의미하며, 이를 통해 Pyjinn 스크립트는 게임 틱(tick)과 게임 렌더링 중에 호출되는 콜백(callback)을 등록할 수 있습니다.
Java와 Pyjinn은 Python 코드를 동기적으로 호출할 수 없습니다. 이렇게 하면 게임이 기껏해야 버벅거리고,
최악의 경우 응답 불능 상태가 됩니다. Java 코드는 EventQueue를 통해 Python으로 이벤트를
비동기적으로(asynchronously) 전송할 수 있지만, Python 코드는 이벤트를 발생시킨 Java의 게임 틱이나
렌더링된 프레임에 동기화되지 않습니다. 예를 들어 게임 이벤트를 등록한 Python 스크립트는
해당 이벤트를 발생시킨 틱보다 나중 틱에서 호출될 수 있습니다.
다음 다이어그램(diagram)은 Python, Pyjinn, Java 간의 호출 가능성(callability)을 요약합니다. 노란색 타원은 Python 스크립트 프로세스를 나타내고, 초록색 타원들은 게임의 Java 프로세스에서 실행되는 코드를 나타내며, 실선 화살표는 동기 함수 또는 메서드 호출을 나타내고, 점선 화살표는 비동기 호출을 나타냅니다:

Python 스크립트에 Pyjinn 임베딩하기
Minescript에 미리 설치된 Python용 java 라이브러리(minescript/system/lib/java.py)는 Pyjinn 스크립트를
Python 스크립트 내에 임베딩하여 해당 스크립트의 전역 변수와 함수에 접근할 수 있도록 지원합니다.
예를 들어 아래 Python 스크립트는 java.eval_pyjinn_script(...)를 사용하여 다음을 정의하는 Pyjinn 스크립트를
임베딩합니다:
- 전역 변수(variable)
x x의 값을 출력하는 전역 함수(function)print_x()- 주어진 단위로 현재 초당 프레임 수(FPS)를 반환하는 전역 함수
get_fps(units: str)
참고: 아래 스크립트는 이름 매핑(name mappings)을 사용할 수도 있는 Java 코드(net.minecraft.client.Minecraft)에
접근합니다. 자세한 내용은 매핑을 참고하세요. 요약: Fabric
모드를 사용 중이라면 아래 스크립트를 실행하기 전에 \install_mappings를 실행하여 매핑을 설치하세요.
# pyjinn_in_python_example.py
import java
# 또는: import system.lib.java as java
script = java.eval_pyjinn_script(r"""
x = 42
def print_x():
print(f"x from Pyjinn = {x}")
Minecraft = JavaClass("net.minecraft.client.Minecraft")
def get_fps(units: str) -> str:
return f"{Minecraft.getInstance().getFps()} {units}"
""")
get_fps = script.get("get_fps")
print("fps:", get_fps("frames per second"))
print(f"x from Python = {script.get('x')}")
print_x = script.get("print_x")
print_x()
script.set("x", 99)
print_x()
채팅 출력:
fps: 101 frames per second
x from Python = 42
x from Pyjinn = 42
x from Pyjinn = 99
이 Python 스크립트는 Pyjinn 스크립트의 전역 변수(globals)에 접근합니다:
script.get(variable_name: str)를 사용해 Pyjinn 전역 변수를 가져옵니다script.set(variable_name: str, value: Any)를 사용해 Pyjinn 전역 변수를 설정합니다
Python에서 접근할 수 있는 Pyjinn 전역 변수의 지원되는 타입(type)에는 bool, float, int, str,
dict, list, Java 클래스 및 객체(object), Java 배열, 사용자 정의 Pyjinn 클래스 및 객체가 포함됩니다.
Java 통합
JavaClass
문자열 리터럴(literal)을 인자로 받는 JavaClass()를 사용해 Java 클래스를 임포트하세요:
List = JavaClass("java.util.List")
JavaClass는 Java Class<?>를 감싸는 Pyjinn의 래퍼(wrapper)이며, 함수 호출(function-call) 문법을 사용하는
클래스의 생성자(constructor)와 메서드 호출(method-call) 문법을 사용하는 정적(static) 메서드에 대한 접근을 제공합니다. 이는
Class<?> 인스턴스(instance)와는 다른데, 이 인스턴스는 리플렉션(reflection) 정보에 접근할 수 있는
메타클래스(metaclass)입니다. JavaClass에 대해 type()을 호출하면 Java 메타클래스(예: String.class)를 반환합니다.
print(JavaClass("java.lang.String"))
# 출력: JavaClass("java.lang.String")
print(type("This is a string"))
# 출력: JavaClass("java.lang.String")
print("This is a string".getClass())
# 출력: Class<String>: class java.lang.String
print(type(42))
# 출력: JavaClass("java.lang.Integer")
print(type(42).MAX_VALUE)
# `Integer.MAX_VALUE`와 동일한 값 출력: 2147483647
print(type(42)(99))
# `new Integer(99)`와 동일한 값 출력: 99
print(type(Integer))
# 메타클래스(metaclass) Integer.class 출력: class java.lang.Integer
print(Integer.TYPE)
# 기본형(primitive type) int.class 출력: int
정적 및 비정적 Java 메서드(method) 호출
Java 클래스(class)의 정적 메서드 호출:
List = JavaClass("java.util.List")
java_list = List.of(1, 2, 3)
Java 객체의 비정적 메서드 호출:
print(java_list.size())
# Python 호환 형태로도 사용 가능: len(java_list)
JavaList
JavaList는 Pyjinn 리스트를 받아 Java List를 반환합니다:
java_list = JavaList([1, 2, 3])
반환된 Java List는 Pyjinn 리스트를 내부적으로 표현한 것이므로, 한쪽을 변경하면 다른 쪽에도 반영됩니다.
JavaMap
JavaMap은 Pyjinn 딕셔너리를 받아 Java Map을 반환합니다:
java_map = JavaMap({1: "one", 2: "two"})
반환된 Java Map은 Pyjinn 딕셔너리를 내부적으로 표현한 것이므로, 한쪽을 변경하면 다른 쪽에도 반영됩니다.
JavaSet
JavaSet은 Pyjinn 집합을 받아 Java Set을 반환합니다:
java_set = JavaSet({1, 2, 3})
반환된 Java Set은 Pyjinn 집합을 내부적으로 표현한 것이므로, 한쪽을 변경하면 다른 쪽에도 반영됩니다.
JavaArray
JavaArray는 Pyjinn 튜플을 받아 Java 배열(Object[])을 반환합니다:
my_tuple = (1, 2, 3, "foo", "bar")
java_array = JavaArray(my_tuple)
print(len(java_array)) # Java 코드 java_array.length와 동일합니다
Java 배열과 이터러블(iterable)은 자동으로 Pyjinn 시퀀스(sequence)로 취급되며 슬라이스(slice) 표기법을 지원합니다:
int_tuple = (1, 2, 3)
java_array = JavaArray(int_tuple) # java_array의 타입(type)은 Object[]입니다
for x in java_array:
print(x)
# Java 배열에 Python 슬라이스 문법을 적용하여
# 동일한 타입의 새 Java 배열을 반환합니다:
print(java_array[-2:])
두 번째 인자로 타입을 전달하여 튜플을 특정 타입(예: int[])의 Java 배열로 변환할 수
있습니다:
Integer = JavaClass("java.lang.Integer")
# 다음 Java 코드와 동일합니다:
# int[] java_int_array = new int[] { 1, 2, 3 };
java_int_array = JavaArray((1, 2, 3), Integer.TYPE)
print(type(java_int_array)) # 출력: JavaClass("[I")
Pyjinn 튜플을 특정 타입의 Java 배열로 변환할 때, 튜플의 모든 요소는 요청된 배열 타입에 할당 가능해야 합니다.
Pyjinn에서 Java 인터페이스(interface) 구현하기
Pyjinn 함수 중 매개변수 타입이 Java 인터페이스인 메서드에 전달되는 함수는 자동으로 해당
인터페이스의 구현체로 변환됩니다. 이 예시에서 Stream::map은 Function<>을 받는 Java 메서드이고, Stream::filter는 Predicate<>를 받는 Java 메서드입니다. 여기서는 입력 숫자를 제곱하고
그 결과값 중 짝수인 것만 걸러내기 위해 Pyjinn lambda 표현식(expression)을 이러한 Java
메서드에 전달합니다:
java_list = JavaList([x for x in range(10)])
print(
java_list.stream()
.map(lambda x: x * x)
.filter(lambda x: x % 2 == 0)
.toList())
# 출력: [0, 4, 16, 36, 64]
Pyjinn 함수는 Java 인터페이스를 Python 생성자(constructor)처럼 호출하여 수동으로 Java 인터페이스로 변환할 수도 있습니다:
Runnable = JavaClass("java.lang.Runnable")
x = Runnable(lambda: print("hello!"))
x.run() # 출력: hello!
숫자 타입
Pyjinn int는 값을 표현하는 데 필요한 비트 수에 따라 32비트 또는 64비트 정수 값을
나타냅니다. 예를 들어 x = 123은 java.lang.Integer를 사용하여 32비트 정수로 표현되고,
y = 4_000_000_000은 java.lang.Long을 사용하여 64비트 정수로 표현됩니다. 32비트를 사용하는
값과 64비트를 사용하는 두 int 값에 이항 산술 연산자를 적용하면, Java에서 int가 long으로
승격되는 것과 유사하게 32비트 값이 64비트로 승격됩니다. Pyjinn 숫자 값은 Pyjinn 내장 함수
JavaInt(...)를 사용하여 Java int 또는 Integer와 동일한 32비트 정수 값으로
캐스팅(casting)할 수 있습니다.
Pyjinn float는 64비트 배정밀도(double-precision) 부동소수점(floating point) 숫자로, Python
float 및 Java double과 동일합니다. Pyjinn 숫자 값은 Pyjinn 내장 함수 JavaFloat(...)를
사용하여 Java float 또는 java.lang.Float와 동일한 32비트 단정밀도(single-precision)
부동소수점 값으로 캐스팅할 수 있습니다.
Pyjinn에서 float와 int가 관련된 이항 산술 연산에서는 int가 자동으로 float로
변환됩니다.
Java와 유사하게, Pyjinn은 Java 메서드에 전달될 때 다음과 같은 숫자 변환을 지원합니다:
- 32비트 값을 가진 Pyjinn
int는 Javaint,long,float,double로 암시적으로 변환됩니다 - 64비트 값을 가진 Pyjinn
int는 Javalong,float,double로 암시적으로 변환됩니다 - Pyjinn
float는 Javafloat또는double로 암시적으로 변환됩니다
참고로 Java double은 float를 기대하는 Java 메서드에 직접 전달할 수 없지만, Pyjinn
float(Java double과 동일합니다)는 편의상 float를 기대하는 Java 메서드에 전달할 수
있습니다.
문자열
Pyjinn의 문자열 객체(예: "this is a test")는 java.lang.String의 인스턴스(instance)입니다. 일부
Python 호환 메서드를 Pyjinn 문자열에서 호출할 수 있으며(Python 3.x 기능 지원:
str 참조), java.lang.String에서 제공하는 약 50개의 메서드도 사용할 수 있습니다.
Pyjinn 문자열은 Python 슬라이스 연산을 지원합니다:
s = "foobarbaz"
print(s[0]) # 출력: f
print(s[-1]) # 출력: z
print(s[3:]) # 출력: barbaz
print(s[3:6]) # 출력: bar
Java에서 String은 서브클래스(subclass)를 만들 수 없는 final 클래스이지만, Pyjinn 문자열은
마치 String의 서브클래스인 것처럼 동작하며, 몇 가지 Python 전용 메서드가 추가되어 있습니다.
(실제로 String의 서브클래스는 아니며, Pyjinn 스크립트에서 String 객체에 추가 메서드를
호출할 수 있도록 인터프리터(interpreter) 내부에 관련 로직이 구현되어 있을 뿐입니다.)
# Python 호환 방식으로 str.startswith() 호출:
print("foo".startswith("o", 1)) # 출력: True
# Java 방식으로 String.startsWith() 호출(대소문자 표기가 다른 점에 유의):
print("foo".startsWith("f")) # 출력: True
split()과 같은 일부 문자열 메서드는 Python과 Java에서 이름은 같지만 동작이 다릅니다.
Pyjinn 문자열 메서드가 Python 호환 동작을 가지면서 동일한 이름의 Java String 메서드가 존재하는
경우, Pyjinn 문자열은 기본적으로 Python에서와 동일하게 동작합니다. 스크립트가 Python 호환 str
동작과 충돌하는 Java String 기능에 접근해야 하는 드문 경우에는, 문자열을 JavaString()으로
감싸서 Java 동작에 접근할 수 있습니다:
s = "this is a test"
# Python 호환 str.split() 호출:
print(s.split()) # 출력: ["this", "is", "a", "test"]
# 정규 표현식(regular expression)을 받는 Java String.split() 호출:
print(JavaString(s).split(r'\s+')) # 출력: ["this", "is", "a", "test"]
JavaString(...)의 반환값은 java.lang.String의 모든 Java 메서드에 접근할 수 있게
해주지만(Python 호환 메서드는 포함되지 않습니다), 그 런타임(runtime) 타입은
org.pyjinn.interpreter.JavaString입니다.
Pyjinn 문자열과 JavaString 객체는 모두 java.lang.String을 기대하는 Java 메서드에 별도의
변환 없이 전달할 수 있습니다. JavaString을 다시 String으로 명시적으로 변환해야 하는 드문
경우에는, 스크립트에서 toString() 메서드를 호출하면 됩니다:
s = "foo"
print(s is JavaString(s).toString()) # 출력: True
JavaString은 고급 기능이며, 대부분의 스크립트에서는 필요하지 않습니다.
Python 언어 기능
다음은 Pyjinn에서 지원하는 Python 언어 기능입니다.
UPPER_CASE_WITH_UNDERSCORES 형식의 이름은 예시 이름입니다.
...는 생략된 코드를 나타냅니다.
Python 표현식:
# 상수 표현식:
None # NoneType
True # bool
False # bool
123 # int
3.14 # float
"hi" # str
'bye' # str
r'\o/' # str (원시 리터럴)
"""triple quoted"""
'''triple quoted'''
# 포맷 문자열(f-string):
X = 1
Y = 2
print(f"{X} + {Y} = {X+Y}") # 출력: 1 + 2 = 3
# 튜플 리터럴:
(X, Y, Z)
# 튜플 할당:
X, Y = 1, 2
X, Y = (1, 2)
X, Y = [1, 2]
# 리스트 리터럴:
[X, Y, Z]
# 딕셔너리 리터럴:
{K1: V1, K2: V2, ...}
# 이항 연산자:
X is Y
X is not Y
X == Y
X < Y
X <= Y
X > Y
X >= Y
X != Y
X in Y
X not in Y
# 사용자 정의 클래스(class)를 위한 연산자 오버로딩 (Pyjinn 0.12부터 지원):
class CLASS_NAME:
def __add__(self, rhs): ...
def __sub__(self, rhs): ...
def __mul__(self, rhs): ...
def __truediv__(self, rhs): ...
def __floordiv__(self, rhs): ...
def __pow__(self, rhs): ...
def __mod__(self, rhs): ...
def __lshift__(self, rhs): ...
def __rshift__(self, rhs): ...
def __eq__(self, rhs): ...
def __lt__(self, rhs): ...
def __le__(self, rhs): ...
def __gt__(self, rhs): ...
def __ge__(self, rhs): ...
def __ne__(self, rhs): ...
def __contains__(self, rhs): ...
def __len__(self): ...
def __getitem__(self, key): ...
def __setitem__(self, key, value): ...
def __call__(self, *args): ...
# 반복 가능한 시퀀스(iterable sequence)를 개별 인자로 풀어서 함수 호출:
FUNC(*[1, 2, 3]) # FUNC(1, 2, 3)처럼 호출됨
# str 키를 가진 딕셔너리를 함수의 키워드 인자(keyword argument)로 변환:
# (Pyjinn 0.9부터 지원)
FUNC(**{"K1": V1, "K2": V2, ...})
# 다음과 동일함: FUNC(K1=V1, K2=V2, ...)
# 함수에 전달된 키워드 인자를 딕셔너리로 캡처:
# (Pyjinn 0.9부터 지원)
def FUNC(**kwargs):
...
# 연산자:
-X # 숫자 타입에 대해
X and Y
X or Y
not X
X + Y
X - Y
X * Y
X / Y
X // Y # Pyjinn 0.9부터 지원
X ** Y
X % Y
X << Y # Pyjinn 0.6부터 지원
X >> Y # Pyjinn 0.6부터 지원
# 내장 함수:
abs(X)
bool(X)
chr(INT)
dict:
dict()
dict(DICT_TO_COPY)
dict(ITERABLE_OF_PAIRS) # 예: dict([(K1, V1), (K2, V2)])
dict(K1=V1, K2=V2, ...)
enumerate(ITERABLE)
float(X)
globals()
hex(X)
int(X)
len(ITERABLE)
list:
list()
list(ITERABLE)
max(X, Y, ...)
min(X, Y, ...)
ord(STR)
print(...)
range(...)
round(X)
str(X)
tuple(ITERABLE)
type(X)
# 인덱스(index)/슬라이스(slice) 연산:
X[INDEX]
X[FROM:]
X[:TO]
X[:]
X[FROM:TO:STEP]
X[:-1] # 음수 인덱스는 시퀀스의 끝을 기준으로 합니다.
# if-else 표현식(expression):
TRUE_VALUE if CONDITION else FALSE_VALUE
# 리스트 컴프리헨션(list comprehension):
[X * 2 for X in range(5)] # 평가 결과: [0, 2, 4, 6, 8]
[C for C in "hello"] # 평가 결과: ["h", "e", "l", "l", "o"]
# 람다(lambda) 표현식:
lambda: print("no args")
lambda X: print("1 arg:", X)
lambda X, Y: print("2 args:", X, Y)
Python 문(statement):
# 임포트(import):
import MODULE
import MODULE as ALIAS
from MODULE import NAME1 as ALIAS1, NAME2 as ALIAS2, ...
from MODULE import *
# 할당:
VAR = VALUE
VAR += VALUE
VAR -= VALUE
VAR *= VALUE
VAR /= VALUE
# 삭제:
del OBJECT
del DICT[KEY]
del LIST[INDEX]
# 표준 출력(stdout)에 출력:
print("SOME STRING")
# 표준 오류(stderr)에 출력:
print("SOME STRING", file=sys.stderr)
# 함수 정의:
def FUNCTION_NAME(ARG1, ...):
...
return VALUE
def FUNCTION_NAME(ARG1, *VAR_ARG):
...
def FUNCTION_NAME(ARG1, KEYWORD1=VALUE1, KEYWORD2=VALUE2):
...
# 클래스 정의:
class CLASS_NAME:
def __init__(self, ...):
self.X = VALUE
self.Y = VALUE
...
@classmethod
def METHOD(CLASS, ...):
...
@staticmethod
def METHOD(...):
...
# 클래스의 인스턴스(instance) 생성:
OBJECT = CLASS_NAME(...)
# 객체의 필드(field) 참조:
print(OBJECT.X)
# 가변(mutable) dataclass:
@dataclass
class CLASS_NAME:
FIELD1: TYPE
FIELD2: TYPE = DEFAULT_VALUE
...
# 불변(immutable) dataclass:
@dataclass(frozen=True)
class CLASS_NAME:
...
if CONDITION:
...
elif CONDITION:
...
else:
...
for VAR in ITERABLE:
...
break
...
continue # Pyjinn 0.5부터 지원
while CONDITION:
...
break
...
continue # Pyjinn 0.5부터 지원
try:
...
except EXCEPTION as NAME:
...
except:
pass
raise EXCEPTION(...)
def FUNCTION_NAME(...):
global GLOBAL_VAR
VAR = ...
def INNER_FUNCTION(...):
nonlocal VAR
...
Python 3.x 기능 지원
이 섹션은 Minescript 5.0b9 및 Pyjinn 0.12까지의 내용을 반영합니다.
언어 기능
Pyjinn에서 현재 지원하지 않는 언어 기능:
- Python 표준 라이브러리 (단,
sys모듈(module)의 일부 기본 기능인sys.argv,sys.version,sys.stdout,sys.stderr는 제외) for와while블록 뒤에 오는else블록- 제너레이터(generator)와
yield문 - 스레딩(threading), asyncio, async/await 문법 (대신 Java
Thread가 지원됨) - 상속(inheritance)
with문match문 (Python 3.10+)- 함수의 키워드 전용 인자 (PEP 3102)
- f-string 할당 표현식, 예를 들어
f"{x = }"("x = "가 아니라 x의 값만 출력함) - 슬라이스 표현식의 스텝 증가값 (파싱은 되지만, 1과 같지 않은 스텝 값은 예외가 발생함)
- 이중 밑줄(double underscore)이 붙은 특수 클래스 메서드(method) (단, 지원되는
__init__()는 예외) - 임의 정밀도(arbitrary-precision) 정수 (Java
Integer,Long과 같은 고정 크기 정수만 지원됨) - 사용자 정의 데코레이터(decorator)
- Python 스타일의 메타클래스(metaclass)
str
class str(런타임 타입(runtime type)은java.lang.String)endswith(prefix: str, start: int = None, end: int = None) -> boolfind(sub: str, start: int = None, end: int = None) -> intjoin(iterable) -> strlower() -> strlstrip(chars: str = None) -> strreplace(old: str, new: str, count: int = -1) -> strrstrip(chars: str = None) -> strsplit(sep: str = None, maxsplit: int = -1)startswith(prefix: str, start: int = None, end: int = None) -> boolstrip(chars: str = None) -> strupper() -> str- 그 외에도
java.lang.String의 메서드 약 50개 지원 (Java 통합: 문자열 참고)
tuple
class tuple(런타임 타입은org.pyjinn.interpreter.Script.PyTuple)__add__(value) -> tuple__contains__(key) -> bool__eq__(value) -> bool__ne__(value) -> bool__len__() -> int__getitem__(key) -> Anycount(value) -> intindex(value) -> int
list
class list(런타임 타입은org.pyjinn.interpreter.Script.PyjList)__add__(value) -> list__contains__(key) -> bool__delitem__(key)__eq__(value) -> bool__ne__(value) -> bool__iadd__(value)__len__() -> int__getitem__(key) -> Any__setitem__(key, value)append(object)clear()copy() -> listcount(value) -> intextend(iterable)index(value) -> intinsert(index: int, object)pop() -> Anypop(index: int) -> Anyremove(value)reverse()sort()
dict
class dict(런타임 타입은org.pyjinn.interpreter.Script.PyjDict)items() -> iterablekeys() -> iterablevalues() -> iterable__len__() -> intget(key) -> Anyget(key, default_value) -> Anysetdefault(key) -> Anysetdefault(key, default_value) -> Any__getitem__(key) -> Any__setitem__(key, value)__contains__(key) -> bool__delitem__(key)
set
class set(런타임 타입은org.pyjinn.interpreter.Script.PyjSet)__contains__(element) -> bool__len__() -> int__lt__(self, rhs) -> bool__le__(self, rhs) -> bool__gt__(self, rhs) -> bool__ge__(self, rhs) -> booladd(element)clear()discard(element)pop() -> Anyupdate(iterable)difference(iterable) -> setdifference_update(iterable)intersection(iterable) -> setintersection_update(iterable)symmetric_difference(iterable) -> setsymmetric_difference_update(iterable)union(iterable) -> setcopy() -> setisdisjoint(iterable) -> boolissubset(iterable) -> boolissuperset(iterable) -> bool
내장 함수
Pyjinn에서 내장 함수 지원 현황:
abs()– 예aiter()– 아니오all()– 아니오anext()– 아니오any()– 아니오ascii()– 아니오bin()– 아니오bool()– 예breakpoint()– 아니오bytearray()– 아니오bytes()– 아니오callable()– 아니오chr()– 예classmethod()– 예compile()– 아니오complex()– 아니오delattr()– 아니오dict()– 예dir()– 아니오divmod()– 아니오enumerate()– 예eval()– 아니오exec()– 아니오filter()– 아니오float()– 예format()– 아니오frozenset()– 아니오getattr()– 아니오globals()– 예hasattr()– 아니오hash()– 아니오help()– 아니오hex()– 예id()– 아니오input()– 아니오int()– 예isinstance()– 예issubclass()– 아니오iter()– 아니오len()– 예 (Python 호환 타입과 Java의 반복 가능한(iterable) 타입 모두에 대해 지원됨)list()– 예locals()– 아니오map()– 아니오max()– 예memoryview()– 아니오min()– 예next()– 아니오object()– 아니오oct()– 아니오open()– 아니오ord()– 예pow()– 아니오print()– 예property()– 아니오range()– 예repr()– 아니오reversed()– 아니오round()– 예set()– 예setattr()– 아니오slice()– 아니오sorted()– 아니오staticmethod()– 예str()– 예sum()– 예super()– 아니오tuple()– 예type()– 예vars()– 아니오zip()– 아니오__import__()– 아니오