通常__init__
方法似乎与此类似:
def __init__(self, ivar1, ivar2, ivar3):
self.ivar1 = ivar1
self.ivar2 = ivar2
self.ivar3 = ivar3
是否有某种方法可以将参数转换为列表(不使用*args
或**kwargs
),然后使用setattr
设置实例变量,并使用参数名称和这个论点通过了?并且可以对列表进行切片,例如您至少需要将其切片为[1:]
,因为您不想self.self
。
(实际上我想它需要是一个字典来保存名称和值)
像这样:def __init__(self, ivar1, ivar2, ivar3, optional=False):
for k, v in makedict(self.__class__.__init__.__args__): # made up __args__
setattr(self, k, v)
谢谢!
回应Unknown的回答,我发现这个有效:
Class A(object):
def __init__(self, length, width, x):
self.__dict__.update(dict([(k, v) for k, v in locals().iteritems() if k != 'self']))
或
Class A(object):
def __init__(self, length, width, x):
self.__dict__.update(locals())
del self.__dict__['self']
还不错......
答案 0 :(得分:7)
你走了。是的,这是一个丑陋的邪恶黑客。是的,对象需要一个__dict__变量。但是,嘿,它是一个整洁的小衬垫!
def __init__(self):
self.__dict__.update(locals())
构造函数可以使用任何类型的参数。
class test(object):
def __init__(self, a, b, foo, bar=5)...
a = test(1,2,3)
dir(a)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'foo', 'bar', 'self']
它也将包含self,但您可以轻松删除它或创建自己的忽略self的更新功能。
答案 1 :(得分:6)
您可以使用inspect.getargspec并将其封装为装饰器。查找可选和关键字参数有点棘手,但应该这样做:
def inits_args(func):
"""Initializes object attributes by the initializer signature"""
argspec = inspect.getargspec(func)
argnames = argspec.args[1:]
defaults = dict(zip(argnames[-len(argspec.defaults):], argspec.defaults))
@functools.wraps(func)
def __init__(self, *args, **kwargs):
args_it = iter(args)
for key in argnames:
if key in kwargs:
value = kwargs[key]
else:
try:
value = args_it.next()
except StopIteration:
value = defaults[key]
setattr(self, key, value)
func(self, *args, **kwargs)
return __init__
然后您可以像这样使用它:
class Foo(object):
@inits_args
def __init__(self, spam, eggs=4, ham=5):
print "Foo(%r, %r, %r)" % (self.spam, self.eggs, self.ham)
答案 2 :(得分:4)
如果在函数签名中单独指定参数,则没有好的方法可以将参数作为列表获取。你可以用检查或框架黑客做一些事情,但这比简单地拼写出来更加丑陋。
答案 3 :(得分:3)
In [31]: inspect.getargspec(C.__init__)
Out[31]: ArgSpec(args=['self', 'ivar1', 'ivar2', 'ivar3', 'optional'],
varargs=None, keywords=None, defaults=(False,))
答案 4 :(得分:2)
查看集合模块中新的namedtuple(Python 2.6中的新增内容)是否适合您。
答案 5 :(得分:2)
您可以使用参数的内省来完成它,但代码将比您尝试替换的代码更长。特别是如果你正在处理kw,你可能需要这样做。
这个简短的代码适用于大多数情况(从未知的例子中改进):
>>> class Foo:
... def __init__(self, labamba, **kw):
... params = locals().copy()
... del params['self']
... if 'kw' in params:
... params.update(params['kw'])
... del params['kw']
... self.__dict__.update(params)
但这是一个丑陋的黑客攻击,除了懒惰之外没有任何特殊原因使代码可读性降低,所以不要这样做。而且,你真的有多少次拥有超过5-6个init参数的类?
答案 6 :(得分:1)
我喜欢这种形式,不是太长,而且可以复制粘贴和子类:
class DynamicInitClass(object):
__init_defargs=('x',)
def __init__(self,*args,**attrs):
for idx,val in enumerate(args): attrs[self.__init_defargs[idx]]=val
for key,val in attrs.iteritems(): setattr(self,key,val)
答案 7 :(得分:0)
如何从特殊课程中衍生出来?我认为这种方式更明确,更灵活:
class InitMe:
def __init__(self, data):
if 'self' in data:
data = data.copy()
del data['self']
self.__dict__.update(data)
class MyClassA(InitMe):
def __init__(self, ivar1, ivar2, ivar3 = 'default value'):
super().__init__(locals())
class MyClassB(InitMe):
def __init__(self, foo):
super().__init__({'xxx': foo, 'yyy': foo, 'zzz': None})
# or super().__init__(dict(xxx=foo, yyy=foo, zzz=None))
class MyClassC(InitMe):
def __init__(self, foo, **keywords):
super().__init__(keywords)
答案 8 :(得分:0)
如果要从给定的参数动态声明类变量,可以在初始化类时使用一种简短的方法来做到这一点:
class Foo():
def __init__(self, **content):
if isinstance(content, dict):
self.hello = 'world' # normal declaration instance variable
for key, value in content.items():
self.__setattr__(key, value)
test = "test" # class variable
>>> content = {'foo':'bar'}
>>> instance = Foo(**content)
>>> instance.foo
>>> 'bar'