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的未来版本中有所改变