Introduction
Lunatic Python is a two-procedure bridge between Python and Lua, allowing these languages to intercommunicate. Being two-procedure procedure that it permits Lua inner Python, Python inner Lua, Lua inner Python inner Lua, Python inner Lua inner Python, and so on.
Why?
Despite the actual fact that the conducting used to be born as an experiment, it be already being former in staunch world initiatives to integrate aspects from both languages.
Please, let me know whilst you utter it in staunch world initiatives.
Examples
Lua inner Python
A general example.
>>> import lua >>> lg = lua.globals() >>> lg.string>>> lg.string.decrease >>> lg.string.decrease("Whats up world!") 'hi there world!'
Now, let’s set a local object into Lua space.
>>> d = {} >>> lg.d = d >>> lua.attach("d['key'] = 'fee'") >>> d {'key': 'fee'}
Enact we secure the reference relieve from Lua space?
>>> d2 = lua.eval("d") >>> d is d2 Accurate
Ideal! Is the python interface available contained within the Lua interpreter?
>>> lua.eval("python")
Certain, it looks so. Let’s nest some reports and peek a local reference passing by.
>>> class MyClass: pass ... >>> obj = MyClass() >>> obj <__main__.MyClass instance at 0x403ccb4c> >>> lua.eval(r"python.eval('lua.eval("python.eval('obj')")')") <__main__.MyClass instance at 0x403ccb4c>
Are you mild following me? Ideal. Then you definately’ve presumably noticed that the Python interpreter order contained within the Lua interpreter order is the identical because the outdoors Python we’re running. Let’s peek that in a more overjoyed procedure.
>>> lua.attach("pg = python.globals()") >>> lua.eval("pg.obj") <__main__.MyClass instance at 0x403ccb4c>
Things secure more attention-grabbing when we open to if truth be told combine Lua and Python code.
>>> desk = lua.eval("desk") >>> def show(key, fee): ... print "secret's %s and sign is %s" % (`key`, `fee`) ... >>> t = lua.eval("{a=1, b=2, c=3}") >>> desk.foreach(t, show) secret's 'a' and sign is 1 secret's 'c' and sign is 3 secret's 'b' and sign is 2 >>>
Of direction, on this case the the same will almost definitely be carried out with out problems with Python.
>>> def show(key, fee): ... print "secret's %s and sign is %s" % (`key`, `fee`) ... >>> t = lua.eval("{a=1, b=2, c=3}") >>> for ok in t: ... show(ok, t[k]) ... secret's 'a' and sign is 1 secret's 'c' and sign is 3 secret's 'b' and sign is 2
Python inner Lua
Now, let’s believe a peek from another standpoint. The elemental thought is precisely the the same.
> require("python") > python.attach("import string") > pg = python.globals() > =pg.string> =pg.string.decrease("Whats up world!") hi there world!
As Lua is especially an embedding language, having entry to the batteries included in Python will almost definitely be attention-grabbing.
> re = python.import("re") > pattern = re.bring together("^Hel(lo) world!") > match = pattern.match("Whats up world!") > =match.community(1) lo
Refined indulge in within the Python example, let’s set a local object in Python space.
> d = {} > pg.d = d > python.attach("d['key'] = 'fee'") > desk.foreach(d, print) key fee
Again, let’s plan close relieve the reference from Python space.
> d2 = python.eval("d") > print(d == d2) correct
Is the Lua interface available to Python?
> =python.eval("lua")
Ideal. So let’s attach the nested trick in Lua as neatly.
> t = {} > =t desk: 0x80fbdb8 > =python.eval("lua.eval('python.eval("lua.eval(\'t\')")')") desk: 0x80fbdb8 >
It procedure that the Lua interpreter order contained within the Python interpreter is the the same because the outdoors Lua interpreter order. Let’s show that in a more obvious procedure.
> python.attach("lg = lua.globals()") > =python.eval("lg.t") desk: 0x80fbdb8
Now for the integration example.
> feature notthree(num) >> return (num ~= 3) >> halt > l = python.eval("[1, 2, 3, 4, 5]") > filter = python.eval("filter") > =filter(notthree, l) [1, 2, 4, 5]
Documentation
Belief
The bridging mechanism consists of constructing the lacking interpreter order contained within the host interpreter. That is, whilst you tear the bridging device inner Python, a Lua interpreter is created; when you tear the device inner Lua, a Python interpreter is created.
As soon as both interpreter states are available, these interpreters are offered with the critical tools to work together freely with every assorted. The given tools supply no longer only the means of executing statements contained within the alien interpreter, but also to assemble individual objects and work alongside with them contained within the native order. This magic is performed by two special object kinds, which act bridging native object entry to the alien interpreter order.
Nearly every object which is handed between Python and Lua is encapsulated within the language utter bridging object form. The only kinds that must no longer encapsulated are strings and numbers, that are converted to the native the same objects.
Besides that, the Lua side also has special therapy for encapsulated Python functions and methods. The most logical procedure to put in power calling of Python objects contained within the Lua interpreter is to put in power a __call feature within the bridging object metatable. Unfortunately this mechanism is no longer supported in certain situations, since some areas test if the thing form is a feature, which is no longer the case of the bridging object. To crush these problems, Python functions and methods are automatically converted to native Lua feature closures, becoming accessible in every Lua context. Callable object cases that must no longer functions nor methods, on the quite a entire lot of hand, will mild utter the metatable mechanism. Fortunately, they could well well also honest also be converted in a native feature closure the utilization of the asfunc() feature, if critical.
Attribute vs. Subscript object entry
Accessing an attribute or the utilization of the subscript operator in Lua give entry to the the same files. This behavior is reflected within the Python special object that encapsulates Lua objects, allowing Lua tables to be accessed in a more overjoyed procedure, and likewise giving entry to objects which utter safe Python keywords (equivalent to the print feature). To illustrate:
>>> string = lua.eval("string") >>> string.decrease>>> string["lower"]
The utilization of Python from the Lua side requires a small bit bit more consideration, since Python has a more strict syntax than Lua. The later makes no distinction between attribute and subscript entry, so we need some formula to know what form of entry is desired at a given second. This alter is offered the utilization of two functions: asindx() and asattr(). These functions receive a single Python object as parameter, and return the the same object with the given entry self-discipline. Perceive that dictionaries and lists utter the index self-discipline by default, while assorted objects utter the attribute self-discipline. To illustrate:
> dict = python.eval("{}") > =dict.keys nil > dict.keys = 10 > print(dict["keys"]) 10 > =dict {'keys': 10} > =dict.keys = 10 n.asattr(dict) > =dict.keys feature: 0x80fa9b8 > =dict.keys() ['keys']
Lua inner Python
When executing Python because the host language, the Lua functionality is accessed by importing the lua module. When Lua is the host language, the lua module will already be available within the world Python scope.
Below is an overview of the functions available within the lua module.
lua.attach(assertion)
This feature will attach the given assertion contained within the Lua interpreter order.
Examples:
>>> lua.attach("foo = 'bar'")
lua.eval(expression)
This feature will evaluate the given expression contained within the Lua interpreter order, and return the result. It will be former to assemble any object from the Lua interpreter order.
Examples:
>>> lua.eval("'foo'..2") 'foo2' >>> lua.eval('string')>>> string = lua.eval('string') >>> string.decrease("Whats up world!") 'hi there world!'
lua.globals()
Return the Lua world scope from the interpreter order.
Examples:
>>> lg = lua.globals() >>> lg.string.decrease("Whats up world!") 'hi there world!' >>> lg["string"].decrease("Whats up world!") 'hi there world!' >>> lg["print"]>>> lg["print"]("Whats up world!") Whats up world!
lua.require(name)
Executes the require() Lua feature, importing the given module.
Examples:
>>> lua.require("testmod") Accurate >>> lua.attach("func()") I'm func in testmod!
Python inner Lua
Now not like Python, Lua has no default path to its modules. Thus, the default path of the actual Lua module of Lunatic Python is alongside with the Python module, and a python.lua stub is offered. This stub must be positioned in a path accessible by the Lua require() mechanism, and as soon as imported this also can honest find the staunch module and load it.
Unfortunately, there is a minor inconvenience for our functions relating to the Lua device which imports external shared objects. The hardcoded behavior of the loadlib() feature is to load shared objects with out exporting their symbols. This is on the total no longer a save within the Lua world, but we’re going a small bit beyond their fashioned requirements here. We’re loading the Python interpreter as a shared object, and the Python interpreter could well well also honest load its non-public external modules that are compiled as shared objects as neatly, and these will are searching to link relieve to the symbols within the Python interpreter. Fortunately, fixing this command is simpler than explaining the command. It is only a topic of adjusting the flag RTLD_NOW within the loadlib.c file of the Lua distribution by the or’ed version RTLD_NOW|RTLD_GLOBAL. This will retain away from “undefined symbol” errors which could well well also finally occur.
Below is an overview of the functions available within the python module.
python.attach(assertion)
This feature will attach the given assertion contained within the Python interpreter order.
Examples:
> python.attach("foo = 'bar'")
python.eval(expression)
This feature will evaluate the given expression contained within the Python interpreter order, and return the result. It will be former to assemble any object from the Python interpreter order.
Examples:
> python.attach("import string") > =python.eval("string")> string = python.eval("string") > =string.decrease("Whats up world!") hi there world!
python.globals()
Return the Python world scope dictionary from the interpreter order.
Examples:
> python.attach("import string") > pg = python.globals() > =pg.string.decrease("Whats up world!") hi there world! > =pg["string"].decrease("Whats up world!") hi there world!
python.locals()
Return the Python local scope dictionary from the interpreter order.
Examples:
> feature luafunc() >> print(python.globals().var) >> print(python.locals().var) >> halt > python.attach("def func():n var = 'fee'n lua.attach('luafunc()')") > python.attach("func()") nil fee
python.builtins()
Return the Python builtins module dictionary from the interpreter order.
Examples:
> pb = python.builtins() > =pb.len("Whats up world!") 12
python.import(name)
Imports and returns the given Python module.
Examples:
> os = python.import("os") > =os.getcwd() /home/niemeyer/src/lunatic-python
python.asattr(pyobj)
Return a reproduction of the given Python object with an attribute entry self-discipline.
Examples:
> dict = python.eval("{}") > =dict.keys nil > dict.keys = 10 > print(dict["keys"]) 10 > =dict {'keys': 10} > =dict.keys = 10 n.asattr(dict) > =dict.keys feature: 0x80fa9b8 > =dict.keys() ['keys']
python.asindx(pyobj)
Return a reproduction of the given Python object with an index entry self-discipline.
Examples:
> buffer = python.eval("buffer('foobar')") > =buffer[0] stdin:1: unknown attribute in python object stack traceback: [C]: ? stdin:1: in necessary chunk [C]: ? > buffer = python.asindx(buffer) > =buffer[0] f
python.asfunc(pyobj)
Return a reproduction of the given Python object enclosed in a Lua feature closure. This is efficacious to make utter of Python callable cases in areas that require a Lua feature. Python methods and functions are automatically converted to Lua functions, and attach no longer require to be explicitly converted.
Examples:
> python.attach("class Be a part of:n def __call__(self, *args):n return '-'.be a a part of(args)") > be a a part of = python.eval("Be a part of()") > =be a a part of <__main__.Join instance at 0x403a864c> > =be a a part of('foo', 'bar') foo-bar > =desk.foreach({foo='bar'}, be a a part of) stdin:1: unsuitable argument #2 to `foreach' (feature expected, bought userdata) stack traceback: [C]: in feature `foreach' stdin:1: in necessary chunk [C]: ? > =desk.foreach({foo='bar'}, python.asfunc(be a a part of)) foo-bar
License
Lunatic Python is accessible under the LGPL license.
Download
Within the market files:
Author
Gustavo Niemeyer <[email protected]>