2016-01-13 68 views
0

我想自动解包初始化变量一劳永逸。我的思考过程是解压所有,并使用setattr作为属性名称作为变量的名称。如何在python类的init中自动设置自我属性?

class BaseObject(object): 
    def __init__(self, *args): 
     for arg in args: 
      setattr(self, argname, arg) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__(args*) 

那么你应该能够做到:

In [3]: mysubclass = Sub('hi', 'stack', 'overflow', 'peeps') 

In [4]: mysubclass.argtwo 
Out[4]: 'stack' 

基于帕拉姆的 '堆' 已被命名为argtwo

这样就可以自动获得,但你仍然可以覆盖象下面这样:

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__(arglist) 
     clean_arg_three = process_arg_somehow(argthree) 
     self.argthree = clean_arg_three 

显然我卡在如何传递参数(argone,argtwo等)的实际名称为一个字符串setattr,以及如何正确地传递ARGS到super init(该argssuper(Sub, self).__init__(args*)的)

谢谢

回答

1

BaseObject.__init__()需要以某种方式找到的参数的名称Sub.__init__()。明确的做法是按照Uri Shalit的建议,将参数字典传递给BaseObject.__init__()。或者,你可以使用inspect模块来神奇地完成这个任务,在你的子类中没有额外的代码。这与魔法的通常缺点(“怎么会发生?”)有关。

import inspect 

class BaseObject(object): 
    def __init__(self): 
     frame = inspect.stack()[1][0] 
     args, _, _, values = inspect.getargvalues(frame) 
     for key in args: 
      setattr(self, key, values[key]) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__() 

书面这工作得很好,但如果你没有定义Sub.__init__(),这会抢了争论从错误的地方(即,从那里调用sub()的函数来创建一个对象)。您可能可以使用inspect来重新检查调用者是BaseObject的子类的__init__()函数。或者,您可以将此代码移至单独的方法,例如,set_attributes_from_my_arguments(),并在需要此行为时从您的子类'__init__()方法中调用该方法。

+0

那是冷血的,没想到它会变得更好。我会尽量不要如此快速地选择答案 – codyc4321

+0

你怎么知道使用那部分堆栈?你只需使用ipdb并检查inspect.stack()? – codyc4321

+1

几个月前,我编写了一个函数来将新变量转储到调用者的名称空间中,我想到了这一点。我想我是通过https://docs.python.org/2/library/inspect.html上的文档提示进行了试验和错误。最有用的信息是:(1)“[stack()返回]调用者堆栈的帧记录列表。返回列表中的第一个条目表示调用者;最后一个条目表示堆栈中最外面的调用。因此stack()[1]。(2)“当[stack()返回]'帧记录时,'每个记录是一个包含六个元素的元组:帧对象,...”。因此stack()[1] [0]。 –

1

使用kwargs代替ARGS

class BaseObject(object): 
    def __init__(self, **kwargs): 
     for argname, arg in kwargs.iteritems(): 
      setattr(self, argname, arg) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__(argone=argone, argtwo=argtwo, argthree=argthree) 

然后,你可以这样做:

s = Sub('a', 'b', 'c') 
+0

很干净,很有意思。谢谢 – codyc4321

1
import inspect 

class BaseObject(object): 
    def __init__(self, args): 
     del args['self'] 
     self.__dict__.update(args) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     args = inspect.getargvalues(inspect.currentframe()).locals 
     super(Sub, self).__init__(args) 

s = Sub(1, 2, 3, 4) 
+0

这也很有趣。为什么删除args ['self'],我认为这只是一个占位符,它知道它是实例方法? – codyc4321

+1

否则'自己'将被分配。它不会破坏任何东西,但它不是特别有用。尝试删除'del args ['self']',你会看到's和'self'会指向同一个对象。 –

+1

'args'条件下的'如果'自我'是不必要的,我将它移除了 –

相关问题