3

我目前正在创建这样的对象:

class Obj(object):
    def __init__(self,**kwargs):
        params = ['val1','val2','val3','val4',...]
        for p in params:
            setattr(self,p,kwargs.get(p,None))

我正在这样做,所以我不必这样做:

class Obj(object):
    def __init__(self,val1=None,val2=None,val3=None,val4=None,...):
        self.val1=val1
        self.val2=val2
        self.val3=val3
        self.val4=val4
        ...

我的问题是,你能把两者混合起来吗?我可以在哪里定义预期的参数,但仍然循环参数来设置属性?我喜欢定义预期参数的想法,因为它是自我记录的,其他开发人员不必搜索使用了哪些 kwargs。

我知道这看起来很琐碎,但我正在从一些 XML 创建一个对象,所以我将传递许多参数,它只会使代码混乱并让我感到困惑。

我用谷歌搜索了这个但找不到任何东西,可能是因为字典和 kwargs 一起指向 kwarg 示例。

更新:更具体地说,是否可以获得传入参数的字典,所以我根本不必使用 kwargs

须藤代码:

class Obj(object):
    def __init__(self,val1=None,val2=None,val3=None,val4=None,...):
        for k,v in dictionary_of_paramters.iteritems():
            setattr(self,k,v)
4

6 回答 6

2

您可以使用该inspect模块:

import inspect

def myargs(val1, val2, val3=None, val4=5):
        print inspect.currentframe().f_locals

它显示了当前堆栈帧上所有可用的局部变量。

myargs('a','b')
==>  {'val3': None, 'val2': 'b', 'val1': 'a', 'val4': 5}

(注意:不保证在所有 Python 解释器上都实现)

编辑:我同意这不是一个很好的解决方案。我会做的更像是:

def _yourargs(*names):
        "returns a dict with your named local vars"
        alllocs = inspect.stack()[1][0].f_locals
        return {n:alllocs[n] for n in names}

def askformine(val1, val2, val3=None, val4=5):
        "example to show just those args i'm interested in"
        print _yourargs('val1','val2','val3','val4')

class Obj(object):
        "example inserting some named args as instance attributes"
        def __init__(self, arg1, arg2=4):
                 self.__dict__.update(_yourargs('arg1','arg2'))

edit2稍微好一点:

def pickdict(d,*names):
    "picks some values from a dict"
    return {n:d[n] for n in names}

class Obj(object):
    "example inserting some named args as instance attributes"
    def __init__(self, arg1, arg2=4):
        self.__dict__.update(pickdict(locals(),'arg1','arg2'))
于 2012-12-27T16:28:49.290 回答
1

没有很好的方法来获取函数所有参数的字典。该**kwargs语法只收集额外的关键字参数,而不是与函数定义中的显式参数匹配的那些。

于 2012-12-27T16:27:03.657 回答
1

尽管不使用 kwargs 或检查模块(请参阅其他答案),您将无法获取参数,但您可以执行以下操作...

class Obj(object):
    def __init__(self, **kwargs):
        self.__dict__.update(**kwargs)

每个对象都有一个存储所有属性的字典,您可以通过self.__dict__. 然后,您只需使用update来设置该对象的内部字典中的所有属性。

有关此方法的一些讨论,请参阅此问题。

于 2012-12-27T16:29:46.333 回答
1

如果要在方法的最顶部获取 args dict,则在定义任何本地之前,这很简单:

class Obj(object):
    def __init__(self,val1=None,val2=None,val3=None,val4=None):
       kwargs = dict(locals())

稍后要阅读此字典,需要一些自省魔法:

class Obj(object):
    def __init__(self,val1=None,val2=None,val3=None,val4=None):

       # feel free to add more locals

       loc = dict(locals())
       fun = sys._getframe().f_code
       kwargs = {x:loc[x] for x in fun.co_varnames[:fun.co_argcount]}

您还可以通过添加如下函数使后者可重用:

def getargs():
    f = sys._getframe(1)
    return {x:f.f_locals[x] for x in f.f_code.co_varnames[:f.f_code.co_argcount]}

接着:

class Obj(object):
    def __init__(self,val1=None,val2=None,val3=None,val4=None):

       # feel free to add more locals

       kwargs = getargs()

我猜这是特定于 cpython 的。

于 2012-12-27T16:38:56.333 回答
0

一种丑陋的解决方法:将额外的参数注入 kwargs 并在要循环所有关键字参数的地方使用它(PS 这是检查模块的示例用法,但建议用于生产使用):

#!/usr/bin/env python

import inspect

def inject_defaults(func):
    """ injects '__defaults' key into into kwargs, 
        so it can be merged with kwargs in the decorated method """

    args, varargs, varkwargs, defaults = inspect.getargspec(func)
    have_defaults = args[-len(defaults):]
    defaults_dict = dict(zip(have_defaults, defaults))

    def fun(*args, **kwargs):
        kwargs['__defaults'] = defaults_dict
        return func(*args, **kwargs)

    return fun

@inject_defaults
def f1(a,b,c, x=1, **kwargs):
    kwargs.update(kwargs['__defaults'])
    del kwargs['__defaults']

    for k, v in kwargs.items():
        # here, x, y and z will appear
        print(k, v)

f1(1, 2, 3, y=3, z=2)
# prints
# ('y', 3)
# ('x', 1)
# ('z', 2)
于 2012-12-27T16:51:50.250 回答
0

是的,您可以将两者混合使用。见下文:

def method(a, b=1, *args, **kwargs):
    '''some code'''

这是有效的。这里:

'a' is a required argument
'b' is a default argument
'args' will have all the non-keyword arguments and
'kwargs' will have all the keyword arguments.

例子:

method(1,2,3,4,5,test=6,test1=7)

此调用将具有:

a=1
b=2
args=(3,4,5)
kwargs={'test':6,'test1':7}
于 2012-12-27T16:24:37.863 回答