What's a good way to provide additional decora

2020-07-10 08:23发布

We're considering using Python (IronPython, but I don't think that's relevant) to provide a sort of 'macro' support for another application, which controls a piece of equipment.

We'd like to write fairly simple functions in Python, which take a few arguments - these would be things like times and temperatures and positions. Different functions would take different arguments, and the main application would contain user interface (something like a property grid) which allows the users to provide values for the Python function arguments.

So, for example function1 might take a time and a temperature, and function2 might take a position and a couple of times.

We'd like to be able to dynamically build the user interface from the Python code. Things which are easy to do are to find a list of functions in a module, and (using inspect.getargspec) to get a list of arguments to each function.

However, just a list of argument names is not really enough - ideally we'd like to be able to include some more information about each argument - for instance, it's 'type' (high-level type - time, temperature, etc, not language-level type), and perhaps a 'friendly name' or description.

So, the question is, what are good 'pythonic' ways of adding this sort of information to a function.

The two possibilities I have thought of are:

  • Use a strict naming convention for arguments, and then infer stuff about them from their names (fetched using getargspec)

  • Invent our own docstring meta-language (could be little more than CSV) and use the docstring for our metadata.

Because Python seems pretty popular for building scripting into large apps, I imagine this is a solved problem with some common conventions, but I haven't been able to find them.

标签: python
4条回答
姐就是有狂的资本
2楼-- · 2020-07-10 09:00

Decorators are a good way to add metadata to functions. Add one that takes a list of types to append to a .params property or something:

def takes(*args):
    def _takes(fcn):
        fcn.params = args
        return fcn
    return _takes

@takes("time", "temp", "time")
def do_stuff(start_time, average_temp, stop_time):
    pass
查看更多
欢心
3楼-- · 2020-07-10 09:06

The 'pythonic' way to do this are function annotations.

def DoSomething(critical_temp: "temperature", time: "time")
    pass
查看更多
The star\"
4楼-- · 2020-07-10 09:11

I would use some kind of decorator:

class TypeProtector(object):
    def __init__(self, fun, types):
        self.fun, self.types = fun, types
    def __call__(self, *args, **kwargs)
        # validate args with self.types
        pass
        # run function
        return fun(*args, **kwargs)

def types(*args):
    def decorator(fun):
        # validate args count with fun parameters count
        pass
        # return covered function
        return TypeProtector(fun, args)
    return decorator

@types(Time, Temperature)
def myfunction(foo, bar):
    pass

myfunction('21:21', '32C')
print myfunction.types
查看更多
冷血范
5楼-- · 2020-07-10 09:13

For python 2.x, I like to use the docstring

def my_func(txt):
    """{
    "name": "Justin",
    "age"   :15
    }"""
    pass

and it can be automatically assign to the function object with this snippet

for f in globals():
    if not hasattr(globals()[f], '__call__'):
        continue
    try:
        meta = json.loads(globals()[f].__doc__)
    except:
        continue
    for k, v in meta.items():
        setattr(globals()[f], k, v)
查看更多
登录 后发表回答