|
Re: using decorators for api calls: msg#00009python.ctypes
Niki Spahiev <niki@xxxxxxxxxx> writes: > Thomas Heller wrote: >> I've been playing with Python 2.4 decorators again. >> I found a solution which lets us write compact code, here are two examples: >> @ stdcall("user32", nonzero, "FindWindowW", c_wchar_p, c_wchar_p) >> def FindWindow(classname=None, windowname=None): >> return _call_(classname, windowname) > > I would prefer this empty function to be: > > def FindWindow(classname=None, windowname=None): > "doc" > > and such empty code objects to be replaced by FFI call. I have some code that does this, although it's not nice imo. The problem is that the decorator must create a function like this for the above, given only the function object of the FindWindow above: def somefunc(classname=None, windowname=None): return _call_(classname, windowname) My code uses the inspect module to build a source code string containing the 'somefunc', which is then exec'd, the somefunc function object retrieved, and some properties like func_code and func_defaults are then used to create a new function with new.function. If someone finds an easier way, please speak up - I'll append the code I have written (this code uses _api_ instead of _call_). Thomas -- import new def _create_func_codestring(func, name): # given a function object <func>, build the source code for another # function, having the same argument list, and a function body # which contains a call to an _api_ function. # Assuming the <func> has this definition: # def func(first, second="spam", third=42): # .... # a string containing the following code is returned: # def <name>(first, second="spam", third=42): # return _api_(first, second, third) import inspect args = inspect.getargspec(func) if args[2]: raise TypeError, "function argument list cannot contain ** argument" argnames = args[0] defaults = args[-1] if not defaults: if args[1]: argnames.append("*%s" % args[1]) argnames = ", ".join(argnames) return "def %s(%s): return _api_(%s)" % (name, argnames, argnames) first_list = ", ".join(argnames) args = argnames[:-len(defaults)] args.extend( ["%s=%r" % t for t in zip(argnames[-len(defaults):], defaults)] ) args = ", ".join(args) return """def %s(%s): return _api_(%s)""" % (name, args, first_list) def _decorate_with_api_global(func, call_api): # return a new function derived from <func>, inserting an '_api_' # symbol into the function globals, which is bound to the # <call_api> object. # # If the body of <func> is empty, a new function body is created, # which simply calls the _api_ object with all parameters passed to <func>. if len(func.func_code.co_code) == 4: code_string = _create_func_codestring(func, func.func_name) d = {} exec code_string in d func = d[func.func_name] func_globals = {"_api_": call_api} func_globals.update(func.func_globals) return new.function(func.func_code, func_globals, func.func_name, func.func_defaults) ------------------------------------------------------- This SF.net email is sponsored by: IT Product Guide on ITManagersJournal Use IT products in your business? Tell us what you think of them. Give us Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more http://productguide.itmanagersjournal.com/guidepromo.tmpl |
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | Re: Re: Error on linux: 00009, Thomas Heller |
|---|---|
| Next by Date: | Where to find gcc abi specs?: 00009, Thomas Heller |
| Previous by Thread: | Error on linuxi: 00009, Michele Petrazzo |
| Next by Thread: | Where to find gcc abi specs?: 00009, Thomas Heller |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |