Python 用于直接传递**kwargs到super()的关键字。\uu init__
是否有一个“神奇的关键字”(显然只有在没有指定Python 用于直接传递**kwargs到super()的关键字。\uu init__,python,class,Python,Class,是否有一个“神奇的关键字”(显然只有在没有指定**kwargs的情况下才有效)以便\uuuu init\uuuuu(*args,***pass\u through\ukwargs)使所有意外的kwargs直接传递到super()?(在后台,在用户不知情的情况下)这将使可读性更容易,并且可以安全地被自动完成和自动文档忽略 在下图中,鼠标仅用名称实例化。为了使超级-调用行工作,我必须添加**kwargs(指定奶酪的孔数),并手动移交。我能不能告诉鼠标和动物“不管你不知道什么:直接传给super()”
**kwargs
的情况下才有效)以便\uuuu init\uuuuu(*args,***pass\u through\ukwargs)
使所有意外的kwargs
直接传递到super()?(在后台,在用户不知情的情况下)这将使可读性更容易,并且可以安全地被自动完成和自动文档忽略
在下图中,鼠标
仅用名称
实例化。为了使超级
-调用行工作,我必须添加**kwargs
(指定奶酪的孔数
),并手动移交。我能不能告诉鼠标
和动物
“不管你不知道什么:直接传给super()
”?
当然,您可能想考虑冲突,但我认为这可能会极大地提高代码的可读性更新问题的答案
这确实是可能的。在提供一些代码进行演示之前,让我先做几点说明:
- 这种自动逻辑属性访问方式非常糟糕。您不能记录它,它会让人们误用/忽略封装概念
- 这根本不是自明的;您不能使用duck类型,因为突然之间每个对象都可以具有任意属性
- 您真正想要做的是在对象之间创建一致且可理解的设计,这些对象具有清晰的焦点并带来相应的功能
但是,如果您仍然想要测试它,您可以使用**kwargs
并将其传递给超级构造函数;它始终包含未在方法签名中显式设置的所有关键字参数:
def testme(color='red', **kwargs):
print(kwargs)
testme(width=3)
# See that 'color' is not in kwargs dict if running this code:
>>> {'width': 3}
这种情况是这样的,因为显式设置的关键字参数被分配给函数签名中给定的变量名;其余部分在kwargs
中捕获
此行为允许您实际筛选每个\uuuuuu init\uuuu
中预期的关键字参数,并将其余的向上传递给超类“\uuuuuuu init\uuu
:
class Animal(object):
def __init__(self, num_legs, **kwargs):
self.num_legs = num_legs
for key, value in kwargs.iteritems():
if not hasattr(self, key):
print(
'Generic attribute assignment: {:s} = {:s}'
.format(key, str(value)))
setattr(self, key, value)
def __str__(self):
res = '<Animal ({:s}):\n'.format(self.__class__.__name__)
for key in dir(self):
if key.startswith('__'):
continue
res += ' {:s} = {:s}\n'.format(key, str(getattr(self, key)))
res += '>'
return res
class Mouse(Animal):
def __init__(self, color='gray', **kwargs):
super(Mouse, self).__init__(4, **kwargs)
self.color = color
class MickeyMouse(Mouse):
def __init__(self, **kwargs):
super(MickeyMouse, self).__init__(color='black', **kwargs)
if __name__ == '__main__':
mm = MickeyMouse(dog='Pluto')
print(mm)
像这样使用它:
cheddar = Cheese()
gouda = Cheese(num_holes=3)
owned_cheddar = Cheese(name='MickeyMouse')
cheddar = Cheese(0, None, None)
owned_cheddar = Cheese.with_owner('MickeyMouse')
(2) 使用静态构造函数方法
class Cheese(object):
def __init__(self, num_holes, weight, name):
# Default construct using all args
pass
@staticmethod
with_owner(name):
return Cheese(0, None, name)
像这样使用它:
cheddar = Cheese()
gouda = Cheese(num_holes=3)
owned_cheddar = Cheese(name='MickeyMouse')
cheddar = Cheese(0, None, None)
owned_cheddar = Cheese.with_owner('MickeyMouse')
请注意,对于您的应用程序来说,使用静态方法有点不灵活;当从不同的数据结构构造对象时,例如。从_dict(…)
,。从_csv(…)
,等等,最好使用它。回答更新的问题
这确实是可能的。在提供一些代码进行演示之前,让我先做几点说明:
- 这种自动逻辑属性访问方式非常糟糕。您不能记录它,它会让人们误用/忽略封装概念
- 这根本不是自明的;您不能使用duck类型,因为突然之间每个对象都可以具有任意属性
- 您真正想要做的是在对象之间创建一致且可理解的设计,这些对象具有清晰的焦点并带来相应的功能
但是,如果您仍然想要测试它,您可以使用**kwargs
并将其传递给超级构造函数;它始终包含未在方法签名中显式设置的所有关键字参数:
def testme(color='red', **kwargs):
print(kwargs)
testme(width=3)
# See that 'color' is not in kwargs dict if running this code:
>>> {'width': 3}
这种情况是这样的,因为显式设置的关键字参数被分配给函数签名中给定的变量名;其余部分在kwargs
中捕获
此行为允许您实际筛选每个\uuuuuu init\uuuu
中预期的关键字参数,并将其余的向上传递给超类“\uuuuuuu init\uuu
:
class Animal(object):
def __init__(self, num_legs, **kwargs):
self.num_legs = num_legs
for key, value in kwargs.iteritems():
if not hasattr(self, key):
print(
'Generic attribute assignment: {:s} = {:s}'
.format(key, str(value)))
setattr(self, key, value)
def __str__(self):
res = '<Animal ({:s}):\n'.format(self.__class__.__name__)
for key in dir(self):
if key.startswith('__'):
continue
res += ' {:s} = {:s}\n'.format(key, str(getattr(self, key)))
res += '>'
return res
class Mouse(Animal):
def __init__(self, color='gray', **kwargs):
super(Mouse, self).__init__(4, **kwargs)
self.color = color
class MickeyMouse(Mouse):
def __init__(self, **kwargs):
super(MickeyMouse, self).__init__(color='black', **kwargs)
if __name__ == '__main__':
mm = MickeyMouse(dog='Pluto')
print(mm)
像这样使用它:
cheddar = Cheese()
gouda = Cheese(num_holes=3)
owned_cheddar = Cheese(name='MickeyMouse')
cheddar = Cheese(0, None, None)
owned_cheddar = Cheese.with_owner('MickeyMouse')
(2) 使用静态构造函数方法
class Cheese(object):
def __init__(self, num_holes, weight, name):
# Default construct using all args
pass
@staticmethod
with_owner(name):
return Cheese(0, None, name)
像这样使用它:
cheddar = Cheese()
gouda = Cheese(num_holes=3)
owned_cheddar = Cheese(name='MickeyMouse')
cheddar = Cheese(0, None, None)
owned_cheddar = Cheese.with_owner('MickeyMouse')
请注意,对于您的应用程序来说,使用静态方法有点不灵活;当从不同的数据结构构造对象时,例如。从_dict(…)
,。从_csv(…)
,可以更好地使用它,等等。为什么要隐藏它?@MegaIng,因为用户不需要在Cheese
的init中包含任何kwargs
,因此在实例化它时可能会感到困惑。你能详细说明你的类deps吗?我不明白为什么您要在另一个类的init中调用不同类的两个init方法,而不仅仅将它们添加为属性。@jbndlr我的类MickeyMouse
需要调用Cheese
和Mouse
的init。(这就是我们目前正在做的事情)。相反,我只想调用super()。\uuu init\uu
,让MRO处理它。因此,super(Cheese,self)。\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?我不明白为什么您要在另一个类的init中调用不同类的两个init方法,而不仅仅将它们添加为属性。@jbndlr我的类MickeyMouse
需要调用Cheese
和Mouse
的init。(这就是我们目前正在做的事情)。相反,我只想调用super()。\uuu init\uu
,让MRO处理它。因此,super(Cheese,self)。\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu!我想我想要的现在是不可能的,所以我重新问了这个问题,也许可以在pythonThank you的未来版本中对这些例子进行修改!我认为我想要的现在是不可能的,所以我重新问了这个问题,希望在python的未来版本中有所改变