神刀安全网

Lunatic Python

Lunatic Pythonis a two-way bridge between Python and Lua , allowingthese languages to intercommunicate. Being two-way means that it allowsLua inside Python, Python inside Lua, Lua inside Python inside Lua,Python inside Lua inside Python, and so on.

Why?

Even though the project was born as an experiment, it’s alreadybeing used in real world projects to integrate features from bothlanguages.

Please, let me know if you use it in real world projects.

Examples

Lua inside Python

A basic example.

>>> import lua >>> lg = lua.globals() >>> lg.string <Lua table at 0x81c6a10> >>> lg.string.lower <Lua function at 0x81c6b30> >>> lg.string.lower("Hello world!") 'hello world!'

Now, let’s put a local object into Lua space.

>>> d = {} >>> lg.d = d >>> lua.execute("d['key'] = 'value'") >>> d {'key': 'value'}

Can we get the reference back from Lua space?

>>> d2 = lua.eval("d") >>> d is d2 True

Good! Is the python interface available inside the Lua interpreter?

>>> lua.eval("python") <Lua table at 0x81c7540>

Yes, it looks so. Let’s nest some evaluations and see a local referencepassing through.

>>> 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 still following me? Lunatic Python Good. Then you’ve probably noticed thatthe Python interpreter state inside the Lua interpreter state is thesame as the outside Python we’re running. Let’s see that in a morecomfortable way.

>>> lua.execute("pg = python.globals()") >>> lua.eval("pg.obj") <__main__.MyClass instance at 0x403ccb4c>

Things get more interesting when we start to really mix Lua andPython code.

>>> table = lua.eval("table") >>> def show(key, value): ...   print "key is %s and value is %s" % (`key`, `value`) ...  >>> t = lua.eval("{a=1, b=2, c=3}") >>> table.foreach(t, show) key is 'a' and value is 1 key is 'c' and value is 3 key is 'b' and value is 2 >>>

Of course, in this case the same could be achieved easilywith Python.

>>> def show(key, value): ...   print "key is %s and value is %s" % (`key`, `value`) ...  >>> t = lua.eval("{a=1, b=2, c=3}") >>> for k in t: ...   show(k, t[k]) ...  key is 'a' and value is 1 key is 'c' and value is 3 key is 'b' and value is 2

Python inside Lua

Now, let’s have a look from another perspective. The basic ideais exactly the same.

> require("python") > python.execute("import string") > pg = python.globals() > =pg.string <module 'string' from '/usr/lib/python2.3/string.pyc'> > =pg.string.lower("Hello world!") hello world!

As Lua is mainly an embedding language, getting access to the batteriesincluded in Python may be interesting.

> re = python.import("re") > pattern = re.compile("^Hel(lo) world!") > match = pattern.match("Hello world!") > =match.group(1) lo

Just like in the Python example, let’s put a local object inPython space.

> d = {} > pg.d = d > python.execute("d['key'] = 'value'") > table.foreach(d, print) key     value

Again, let’s grab back the reference from Python space.

> d2 = python.eval("d") > print(d == d2) true

Is the Lua interface available to Python?

> =python.eval("lua") <module 'lua' (built-in)>

Good. So let’s do the nested trick in Lua as well.

> t = {} > =t table: 0x80fbdb8 > =python.eval("lua.eval('python.eval(/"lua.eval(//'t//')/")')") table: 0x80fbdb8 >

It means that the Lua interpreter state inside the Python interpreteris the same as the outside Lua interpreter state. Let’s show that ina more obvious way.

> python.execute("lg = lua.globals()") > =python.eval("lg.t") table: 0x80fbdb8

Now for the mixing example.

> function notthree(num) >>   return (num ~= 3) >> end > l = python.eval("[1, 2, 3, 4, 5]") > filter = python.eval("filter") > =filter(notthree, l) [1, 2, 4, 5]

Documentation

Theory

The bridging mechanism consists of creating the missing interpreterstate inside the host interpreter. That is, when you run thebridging system inside Python, a Lua interpreter is created; whenyou run the system inside Lua, a Python interpreter is created.

Once both interpreter states are available, these interpreters areprovided with the necessary tools to interact freely with each other.The given tools offer not only the ability of executing statementsinside the alien interpreter, but also to acquire individual objectsand interact with them inside the native state. This magic is doneby two special object types, which act bridging native object accessto the alien interpreter state.

Almost every object which is passed between Python and Lua isencapsulated in the language specific bridging object type. Theonly types which are not encapsulated are strings and numbers,which are converted to the native equivalent objects.

Besides that, the Lua side also has special treatment forencapsulated Python functions and methods. The most obvious wayto implement calling of Python objects inside the Lua interpreteris to implement a __call function in the bridging objectmetatable. Unfortunately this mechanism is not supported incertain situations, since some places test if the object type isa function, which is not the case of the bridging object. Tooverwhelm these problems, Python functions and methods areautomatically converted to native Lua function closures,becoming accessible in every Lua context. Callable objectinstances which are not functions nor methods, on the other hand,will still use the metatable mechanism. Luckily, they may also beconverted in a native function closure using the asfunc() function, if necessary.

Attribute vs. Subscript object access

Accessing an attribute or using the subscript operator in Lua giveaccess to the same information. This behavior is reflected in thePython special object that encapsulates Lua objects, allowing Luatables to be accessed in a more comfortable way, and also givingaccess to objects which use protected Python keywords (such asthe print function). For example:

>>> string = lua.eval("string") >>> string.lower <Lua function at 0x81c6bf8> >>> string["lower"] <Lua function at 0x81c6bf8>

Using Python from the Lua side requires a little bit more attention,since Python has a more strict syntax than Lua. The later makes nodistinction between attribute and subscript access, so we need someway to know what kind of access is desired at a given moment.This control is provided using two functions: asindx() and asattr() . These functions receive a single Python object asparameter, and return the same object with the given accessdiscipline. Notice that dictionaries and lists use the indexdiscipline by default, while other objects use the attribute discipline.For example:

> dict = python.eval("{}") > =dict.keys nil > dict.keys = 10 > print(dict["keys"]) 10 > =dict {'keys': 10} > =dict.keys = 10 n.asattr(dict) > =dict.keys function: 0x80fa9b8 > =dict.keys() ['keys']

Lua inside Python

When executing Python as the host language, the Lua functionalityis accessed by importing the lua module. When Lua is the hostlanguage, the lua module will already be available in theglobal Python scope.

Below is a description of the functions available in the lua module.

lua.execute(statement)

This function will execute the given statement inside the Luainterpreter state.

Examples:

>>> lua.execute("foo = 'bar'")

lua.eval(expression)

This function will evaluate the given expression inside the Luainterpreter state, and return the result. It may be used toacquire any object from the Lua interpreter state.

Examples:

>>> lua.eval("'foo'..2") 'foo2' >>> lua.eval('string') <Lua table at 0x81c6ae8> >>> string = lua.eval('string') >>> string.lower("Hello world!") 'hello world!'

lua.globals()

Return the Lua global scope from the interpreter state.

Examples:

>>> lg = lua.globals() >>> lg.string.lower("Hello world!") 'hello world!' >>> lg["string"].lower("Hello world!") 'hello world!' >>> lg["print"] <Lua function at 0x8154350> >>> lg["print"]("Hello world!") Hello world!

lua.require(name)

Executes the require() Lua function, importing the givenmodule.

Examples:

>>> lua.require("testmod") True >>> lua.execute("func()") I'm func in testmod!

Python inside Lua

Unlike Python, Lua has no default path to its modules. Thus, thedefault path of the real Lua module of Lunatic Python istogether with the Python module, and a python.lua stub isprovided. This stub must be placed in a path accessible by the Lua require() mechanism, and once imported it will locate thereal module and load it.

Unfortunately, there’s a minor inconvenience for our purposesregarding the Lua system which imports external shared objects.The hardcoded behavior of the loadlib() function is to loadshared objects without exporting their symbols. This is usuallynot a problem in the Lua world, but we’re going a little beyondtheir usual requirements here. We’re loading the Pythoninterpreter as a shared object, and the Python interpreter mayload its own external modules which are compiled as sharedobjects as well, and these will want to link back to the symbolsin the Python interpreter. Luckily, fixing this problem is easierthan explaining the problem. It’s just a matter of replacing theflag RTLD_NOW in the loadlib.c file of the Luadistribution by the or’ed version RTLD_NOW|RTLD_GLOBAL . Thiswill avoid "undefined symbol" errors which could eventuallyhappen.

Below is a description of the functions available in the python module.

python.execute(statement)

This function will execute the given statement inside the Pythoninterpreter state.

Examples:

> python.execute("foo = 'bar'")

python.eval(expression)

This function will evaluate the given expression inside thePython interpreter state, and return the result. It may be usedto acquire any object from the Python interpreter state.

Examples:

> python.execute("import string") > =python.eval("string") <module 'string' from '/usr/lib/python2.3/string.pyc'> > string = python.eval("string") > =string.lower("Hello world!") hello world!

python.globals()

Return the Python global scope dictionary from the interpreter state.

Examples:

> python.execute("import string") > pg = python.globals() > =pg.string.lower("Hello world!") hello world! > =pg["string"].lower("Hello world!") hello world!

python.locals()

Return the Python local scope dictionary from the interpreter state.

Examples:

> function luafunc() >>   print(python.globals().var) >>   print(python.locals().var) >> end > python.execute("def func():/n var = 'value'/n lua.execute('luafunc()')") > python.execute("func()") nil value

python.builtins()

Return the Python builtins module dictionary from the interpreterstate.

Examples:

> pb = python.builtins() > =pb.len("Hello 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 copy of the given Python object with an attributeaccess 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 function: 0x80fa9b8 > =dict.keys() ['keys']

python.asindx(pyobj)

Return a copy of the given Python object with an indexaccess discipline.

Examples:

> buffer = python.eval("buffer('foobar')") > =buffer[0] stdin:1: unknown attribute in python object stack traceback:         [C]: ?         stdin:1: in main chunk         [C]: ? > buffer = python.asindx(buffer) > =buffer[0] f

python.asfunc(pyobj)

Return a copy of the given Python object enclosed in aLua function closure. This is useful to use Python callableinstances in places that require a Lua function. Pythonmethods and functions are automatically converted toLua functions, and don’t require to be explicitly converted.

Examples:

> python.execute("class Join:/n def __call__(self, *args):/n  return '-'.join(args)") > join = python.eval("Join()") > =join <__main__.Join instance at 0x403a864c> > =join('foo', 'bar') foo-bar > =table.foreach({foo='bar'}, join) stdin:1: bad argument #2 to `foreach' (function expected, got userdata) stack traceback:         [C]: in function `foreach'         stdin:1: in main chunk         [C]: ? > =table.foreach({foo='bar'}, python.asfunc(join)) foo-bar

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Lunatic Python

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮