2016-11-30 74 views
3

我有一个类与许多实例变量与默认值,可以选择可以在实例化(注意:没有可变的默认参数)重写。Python:程序类实例变量初始化与本地人()

因为编写self.x = x等很多次都是相当多余的,所以我以编程方式初始化变量。

为了说明,考虑本实施例中(其具有,为了简洁起见,仅5中省略实例变量和任何方法):

实施例:

# The "painful" way 
class A: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.a = a 
     self.b = b 
     self.c = c 
     self.d = d 
     self.e = e 

# The "lazy" way 
class B: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.__dict__.update({k: v for k, v in locals().items() if k!='self'}) 

# The "better lazy" way suggested 
class C: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
      for k, v in locals().items(): 
       if k != 'self': 
        setattr(self, k, v) 

x = A(1, c=7) 
y = B(1, c=7) 
z = C(1, c=7) 

print(x.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(y.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(z.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 

因此,为了使我的生活更容易,我使用B类中所示的成语,其结果与A相同。

这是不好的做法吗?有没有什么陷阱?

附录: 另一个理由使用这个成语是为了节省一些空间 - 我打算MicroPython使用它。 无论出于何种原因Because locals work differently there,只有类A中显示的方式工作。

+1

是的。这是不好的做法。为什么不使用'dict()'?他们必须是班级属性吗? –

+4

相关:http://stackoverflow.com/q/1389180/3001761。 – jonrsharpe

+2

我想不出任何明显的缺陷,但我确实发现它很糟糕。 – wim

回答

3

我实际上会建议使用class A中显示的代码。你有什么是重复代码,不是冗余代码,重复不是总是不好。你只需要编写__init__一次,并保持每个实例变量的一个赋值就是你的类期望的实例变量的良好文档(明确和清晰)。

但有一点要记住的是,许多变量,您可以初始化为不同的参数可能是您的类需要重新设计的迹象。将某些单独的参数更合理地分组到单独的列表,字典或甚至其他类中吗?

+1

Alex Martelli说了一些[应该在stdlib](http://stackoverflow.com/questions/1389180/python-automatically-initialize-instance-variables#comment1230512_1389224)到避免这种重复。然而,7年后,什么也没有。所以......¯\\ _(ツ)_ /¯....在这里,有一个+1。 – wim

1

尝试一个更Python的方法:

class C: 
    def __init__(self,a,b=2,c=3,d=4.5,e=5): 
    for k,v in locals().iteritems(): 
     setattr(self,k,v) 
c = C(1) 
print c.a, c.b 
1 2 

这种方法可能是一两行更长的时间,但线路长度短,你的意图少令人费解。另外,任何可能试图重用代码的人都可以按照预期访问对象的属性。

希望这会有所帮助。

编辑:删除第二种方法使用kwargs bc它没有解决默认变量的要求。

的重要外卖这里是你的代码的用户将无法访问您的对象的属性如预期,如果做喜欢你的例子B类节目。

+0

'kwargs'在这种情况下没有用处:它不保证所有需要的变量都被传入,并且不需要的变量可以作为实例变量传入并存储。 – phoibos

+3

你的第二种方法不允许默认值,这在问题中显然是需要的。在你的第一种方法中,从迭代中排除'self' – donkopotamus

+0

好点,如果需要默认值,则使用第一种方法。 @donkopotamus:setattr需要3个参数。第一个需要是对象的一个​​实例。如果在类定义中操作,则此实例必须是自己的。 –