有没有理由不发送super().__ init __()一个字典,而不是** kwds? [英] Is there a reason not to send super().__init__() a dictionary instead of **kwds?

查看:111
本文介绍了有没有理由不发送super().__ init __()一个字典,而不是** kwds?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始构建一个基于文本的游戏,作为学习Python的一个练习(我使用3.3)。我说基于文本的游戏,但我的意思是更多的MUD,而不是选择自己的冒险。无论如何,当我想到如何处理使用 super()的继承和多重继承时,我真的很激动,但是我发现参数传递真的是混乱了代码,并且需要玩杂耍很多很小的变量。另外,创建保存文件似乎很噩梦。

I just started building a text based game yesterday as an exercise in learning Python (I'm using 3.3). I say "text based game," but I mean more of a MUD than a choose-your-own adventure. Anyway, I was really excited when I figured out how to handle inheritance and multiple inheritance using super() yesterday, but I found that the argument-passing really cluttered up the code, and required juggling lots of little loose variables. Also, creating save files seemed pretty nightmarish.

所以,我想到,如果某些类层次结构只采用一个参数,一个字典,只是将字典传回来? 为了给你一个例子,这里有两个修剪到它们的init方法的类:

So, I thought, "What if certain class hierarchies just took one argument, a dictionary, and just passed the dictionary back?" To give you an example, here are two classes trimmed down to their init methods:

class Actor:
    def __init__(self, in_dict,**kwds):
        super().__init__(**kwds)
        self._everything = in_dict
        self._name = in_dict["name"]
        self._size = in_dict["size"]
        self._location = in_dict["location"]
        self._triggers = in_dict["triggers"]
        self._effects = in_dict["effects"]
        self._goals = in_dict["goals"]
        self._action_list = in_dict["action list"] 
        self._last_action = ''
        self._current_action = '' # both ._last_action and ._current_action get updated by .update_action()

class Item(Actor):
    def __init__(self,in_dict,**kwds)
        super().__init__(in_dict,**kwds)
        self._can_contain = in_dict("can contain") #boolean entry
        self._inventory = in_dict("can contain") #either a list or dict entry

class Player(Actor):
    def __init__(self, in_dict,**kwds):
        super().__init__(in_dict,**kwds)
        self._inventory = in_dict["inventory"] #entry should be a Container object
        self._stats = in_dict["stats"]

将被传递的示例dict:

Example dict that would be passed:

playerdict = {'name' : '', 'size' : '0', 'location' : '', 'triggers' : None, 'effects' : None, 'goals' : None, 'action list' = None, 'inventory' : Container(), 'stats' : None,}

将被 {} 取代。)

所以,in_dict被传递到上一班,而不是** kwds的巨大有效载荷。
我喜欢这样,因为:

So, in_dict gets passed to the previous class instead of a huge payload of **kwds. I like this because:


  1. 它使我的代码更加整洁,更易于管理。

  2. 只要该命令至少有一个名为密钥的条目,则不会中断该代码。另外,如果一个给定的参数永远不会被使用,这并不重要。

  3. 看起来文件IO已经变得容易了很多(作为dict存储的玩家数据的字典,存储的项目数据的字典作为dicts等)

我得到的点 ** kwds (编辑:显然我没有),传递较少的论据似乎并不麻烦。这只是 ,以便在每个实例的创建时都能够处理需要大量属性的一种舒适的方式。

I get the point of **kwds ( apparently I didn't), and it hasn't seemed cumbersome when passing fewer arguments. This just appears to be a comfortable way of dealing with a need for a large number of attributes at the the creation of each instance.

说,我还是一个主要的python noob。所以,我的问题是这样的:是否有一个潜在的原因,通过super()反复通过相同的dict到基类将是一个更糟糕的想法,而不是强硬它与恶心(大而凌乱)** kwds通过?(例如,解释者的问题,我的级别的人将会无知。)

That said, I'm still a major python noob. So, my question is this: Is there an underlying reason why passing the same dict repeatedly through super() to the base class would be a worse idea than just toughing it out with nasty (big and cluttered) **kwds passes? (e.g. issues with the interpreter that someone at my level would be ignorant of.)

编辑:

以前,创建一个新的Player可能看起来像这样,每个属性都有一个参数传递。

Previously, creating a new Player might have looked like this, with an argument passed for each attribute.

bob = Player('bob', Location = 'here', ... etc.)   

需要的参数数量有所增加,我只包括真正需要存在的属性,不会从Engine对象中断方法调用。

The number of arguments needed blew up, and I only included the attributes that really needed to be present to not break method calls from the Engine object.

是我从迄今为止的答案和评论中得到的印象:

This is the impression I'm getting from the answers and comments thus far:

发送相同的字典没有什么错,只要没有有机会修改它的内容(Kirk Strauser)和字典总是有它应有的(goncalopp)。真正的答案是,问题是不幸,使用 in_dict 而不是 ** kwds 是多余的。

There's nothing "wrong" with sending the same dictionary along, as long as nothing has the opportunity to modify its contents (Kirk Strauser) and the dictionary always has what it's supposed to have (goncalopp). The real answer is that the question was amiss, and using in_dict instead of **kwds is redundant.

这是否正确? (另外,感谢各种各样的反馈!)

Would this be correct? (Also, thanks for the great and varied feedback!)

推荐答案

我不知道我完全理解你的问题,因为我在使用in_dict进行更改之前,请不要看看代码如何查看。听起来你已经列出了几十个关键字在调用超级(这是可以理解的不是你想要的),但这不是必要的。如果您的小孩类有所有这些信息的字母,当您使用 ** in_dict kwargs C $ C>。所以:

I'm not sure I understand your question exactly, because I don't see how the code looked before you made the change to use in_dict. It sounds like you have been listing out dozens of keywords in the call to super (which is understandably not what you want), but this is not necessary. If your child class has a dict with all of this information, it can be turned into kwargs when you make the call with **in_dict. So:

class Actor:
    def __init__(self, **kwds):

class Item(Actor):
    def __init__(self, **kwds)
        self._everything = kwds
        super().__init__(**kwds)

我没有看到为此添加另一个dict的理由,因为您只能操纵并传递为<$ c创建的dict $ c> kwds 无论如何

I don't see a reason to add another dict for this, since you can just manipulate and pass the dict created for kwds anyway

编辑:

至于使用**扩展的效率,而不是明确列出参数,我用这段代码做了非常不科学的计时测试:

As for the question of the efficiency of using the ** expansion of the dict versus listing the arguments explicitly, I did a very unscientific timing test with this code:

import time

def some_func(**kwargs):
    for k,v in kwargs.items():
        pass

def main():
    name = 'felix'
    location = 'here'
    user_type = 'player'

    kwds = {'name': name,
            'location': location,
            'user_type': user_type}

    start = time.time()
    for i in range(10000000):
        some_func(**kwds)

    end = time.time()
    print 'Time using expansion:\t{0}s'.format(start - end)
    start = time.time()
    for i in range(10000000):
        some_func(name=name, location=location, user_type=user_type)

    end = time.time()
    print 'Time without expansion:\t{0}s'.format(start - end)


if __name__ == '__main__':
    main()

运行这10,000,000次给出了一个轻微的(可能是统计上无意义的)优势,绕过一个dict并使用**。

Running this 10,000,000 times gives a slight (and probably statistically meaningless) advantage passing around a dict and using **.

Time using expansion:   -7.9877269268s
Time without expansion: -8.06108212471s

如果我们打印dict对象的ID(kwds outside和kwargs在函数内),你会看到python为这个函数创建一个新的dict来使用,但实际上是fu只能永远得到一个字典。在函数的初始定义(kwargs dict的创建之后),所有后续调用只是更新属于该函数的该dict的值,无论您如何调用它。 (另见这个启发了一个关于如何可变默认参数的问题在python中处理,这有点相关)

If we print the IDs of the dict objects (kwds outside and kwargs inside the function), you will see that python creates a new dict for the function to use in either case, but in fact the function only gets one dict forever. After the initial definition of the function (where the kwargs dict is created) all subsequent calls are just updating the values of that dict belonging to the function, no matter how you call it. (See also this enlightening SO question about how mutable default parameters are handled in python, which is somewhat related)

所以从性能的角度来看,你可以选择对你有意义的。它不应该有意义地影响python如何在幕后操作。

So from a performance perspective, you can pick whichever makes sense to you. It should not meaningfully impact how python operates behind the scenes.

这篇关于有没有理由不发送super().__ init __()一个字典,而不是** kwds?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆