假设我有以下示例:
class foo:
...
def bar(self, w, x, y, z, ...):
self.w = w
self.x = x
self.y = y
self.z = z
...
我希望通过参数将bar()
中的n个属性赋值行减少到使用setattr()
循环的一个赋值行集。为此目的,有没有一种好方法可以循环使用这些参数?
我希望保留已定义的参数名称,以便限制传递给函数的参数数量以及传递它们的顺序。我也理解functions can be handled like objects;那么有可能获得一个已定义参数的列表作为函数的属性并迭代它吗?
答案 0 :(得分:1)
使用locals()
,您可以获取所有参数(以及任何其他局部变量):
class foo:
def bar(self, w, x, y, z):
argdict = {arg: locals()[arg] for arg in ('w', 'x', 'y', 'z')}
for key, value in argdict.iteritems():
setattr(self, key, value)
...
可能更有效率地做到这一点,如果你更喜欢可读性的线条或者发现它更具可读性,你可以内联argdict。
答案 1 :(得分:0)
因此,您不必明确地使用参数命名:
class foo:
def __init__(self, w, x, y, z):
args = locals()# gets a dictionary of all local parameters
for argName in args:
if argName!='self':
setattr(self, argName, args[argName])
答案 2 :(得分:-1)
__setattr__
属性一次只分配一个属性,如果要分配多个属性,可以在函数头中使用**kwargs
并限制参数数量,只需检查一下函数中kwargs
的长度。并逐个为每个参数调用__setattr__
。这个方法的一个很好的理由是,由于很多原因,基本上将属性分配给对象而不考虑任何东西不是正确和理想的工作。因此,您必须通过考虑所有必需条件,一次分配一个属性。
您也可以通过更新实例字典手动执行此操作,但您也应该处理异常。
In [80]: class foo:
def bar(self, **kwargs):
if len(kwargs) != 4:
raise Exception("Please enter 4 keyword argument")
for k, v in kwargs.items():
foo.__setattr__(self, k, v)
....:
In [81]: f = foo()
In [82]: f.bar(w=1, x=2, y=3, z=4)
In [83]: f.w
Out[83]: 1
In [84]: f.bar(w=1, x=2, y=3, z=4, r=5)
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-84-758f669d08e0> in <module>()
----> 1 f.bar(w=1, x=2, y=3, z=4, r=5)
<ipython-input-80-9e46a6a78787> in bar(self, **kwargs)
2 def bar(self, **kwargs):
3 if len(kwargs) != 4:
----> 4 raise Exception("Please enter 4 keyword argument")
5 for k, v in kwargs.items():
6 foo.__setattr__(self, k, v)
Exception: Please enter 4 keyword argument
使用__setatter__
它会自动处理异常:
In [70]: f.bar(1, 2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-70-07d1f3c9e27f> in <module>()
----> 1 f.bar(1, 2)
<ipython-input-65-1049e26120c1> in bar(self, *args)
2 def bar(self, *args):
3 for item in args:
----> 4 foo.__setattr__(self, item, item)
5
TypeError: attribute name must be string, not 'int'