Вопрос

following this topic: allow users to "extend" API functions

class Inspector:
    def __init__(self, passedFunc):
        self.passedFunc = passedFunc

    def __call__(self, *args, **kwargs):
        # Inspector needs to generate a list of arguments of the passed function and print them in *correct* order

        # now how to generate a list of arguments using data from both ''args' and 'kwargs'?
        # the user might keep default argument values, in which case both will be None,
        # he might only use args, in which case it is easy,
        # but he might also use kwargs, in which case I don't see how to generate a list with correct order of arguments
        # and he might use all 3 from above together

        # I found this solution for when only default arguments are used
        if args == () and kwargs == {}: args = self.passedFunc.__defaults__

        print args  

@Inspector
def exampleFunc(value=0, otherValue=3):
    pass

exampleFunc()

How to generate a correct order args list for all scenarios?

Это было полезно?

Решение

This is how you can build the actual parameters list in the decorator:

import inspect

class Inspector:
    def __init__(self, passedFunc):
        self.passedFunc = passedFunc

    def __call__(self, *args, **kwargs):

        spec = inspect.getargspec(self.passedFunc)
        params = dict(zip(spec.args, args))
        defaults = dict(zip(spec.args[-len(spec.defaults):], spec.defaults))

        for k, v in kwargs.items():
            if k not in spec.args:
                raise TypeError('unexpected argument', k)
            if k in params:
                raise TypeError('mulitple values for argument', k)
            params[k] = v

        for k in spec.args:
            if k not in params:
                if k in defaults:
                    params[k] = defaults[k]
                else:
                    raise TypeError('missing argument', k)

        args_in_order = [params[x] for x in spec.args]

        print args_in_order

Example:

@Inspector
def exampleFunc(value=0, otherValue=3):
    pass

exampleFunc()  # 0,3
exampleFunc('foo')  # foo,3
exampleFunc(otherValue='foo', value=555) # 555,foo

Другие советы

In [244]: def myinspector(func):
     ...:     def inner(*args,**kwargs):
     ...:         myrs1=[list(x) for x in zip(func.func_code.co_varnames[-len(func.func_defaults):],func.func_defaults)]
     ...:         if kwargs:
     ...:             for x in myrs1:
     ...:                 if x[0] in kwargs: x[1]=kwargs.get(x[0])
     ...:             for x in kwargs:
     ...:                 if x not in func.func_code.co_varnames: myrs1.append([x,kwargs.get(x)])
     ...:         if args:myrs1=list(args)+ myrs1
     ...:         print myrs1
     ...:     return inner

In [245]: @myinspector
     ...: def exampleFunc(value=0,othervalue=3):
     ...:     pass

In [246]: exampleFunc()
[['value', 0], ['othervalue', 3]]

In [247]: exampleFunc(1,4,5,value=9,name=5)
[1, 4, 5, ['value', 9], ['othervalue', 3], ['name', 5]]

In [248]: exampleFunc(name=5, othervalue=6)
[['value', 0], ['othervalue', 6], ['name', 5]]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top