【问题标题】:Initialize Python variable from possible missing dict value从可能缺少的 dict 值初始化 Python 变量
【发布时间】:2011-05-30 23:16:26
【问题描述】:

Pythonic 的方法是什么?

value = (mydict.has_key('index') and mydict['index']) or 1024

从字典的值初始化,如果存在,否则使用默认值。

在 LBYL 和 EAFP 上得到了一些答案,但代码太冗长:p

我想要一些单行初始化。

PS:仅限 python-2.4(运行 CentOS5)

【问题讨论】:

  • 实际上你的代码是这样做的:“从一个dict的值初始化,如果存在并且不被认为是一个布尔False值,否则使用默认值。”
  • 对!忘了说“索引”永远不是布尔值(代码约束)对不起。
  • 它们是否实际上是布尔类型并不重要,因为在 Python 中有很多东西,例如 None()[]''{}、@如果在逻辑表达式中使用 987654328@ 和 0.0,则将其视为 False - 有些人称之为它们的内在“truthiness”。

标签: python dictionary initialization indexing


【解决方案1】:
value = mydict.get('index', 1024)

(请注意,这并不完全等同于您的代码,因为它只会在不存在键 index 时使用 1024,而当键对应的值 index 时,您的代码也会使用 1024是假的。从你的解释我推断前者是你真正想要的。)

【讨论】:

  • 请务必注意,由于 python 是一种非惰性语言,因此无论您是否最终使用它,都会评估“默认值”表达式。 (与不会评估它的if 语句相反。)
  • @ninjagecko 是正确的 - 如果默认值的构建成本很高,并且您关心性能,您将希望避免使用 get/setdefault。在这种情况下,我经常使用try: ... except KeyError: 成语,特别是如果我希望关键的“未命中”很少见。
  • @ninjagecko,Whatang:value = mydict['index'] if 'index' in mydict else 1234 是懒惰的单行者。我只是想明确一点,这里并不重要,因为创建 1234 非常便宜。
  • 如果默认值很昂贵并且 dict 中的值是非假的,那么您可以使用 value = mydict.get('index') or doexpensiveoperation() 这不是很好但仍然很短。
  • @lambackc:如果index 在字典中,但它的赋值是假的,这将产生意想不到的结果。
【解决方案2】:

也可以使用setdefault() - 类似于get(),但它会在返回值之前插入键:

value = mydict.setdefault('index', 1024)

【讨论】:

  • 请务必注意,由于 python 是一种非惰性语言,因此无论您是否最终使用它,都会评估“默认值”表达式。 (与不会评估它的if 语句相反。)
【解决方案3】:

getsetdefault 方法很重要,它们应该在任何 Python 程序员的工具箱中。

另一个重要的方法是使用collections.defaultdict,因为这样你就可以在一个地方定义你的“默认值”,而不必将它分散到你的代码中任何使用字典的地方,即不要重复你自己。然后,如果您更改默认值,则无需通过代码查找所有这些获取和设置默认值。例如

>>> import collections
>>> myDict = collections.defaultdict
>>> myDict = collections.defaultdict(lambda : 1024)
>>> myDict[0] += 1
>>> print myDict[0], myDict[100]
1025 1024

因为你可以设置函数调用,你可以为你的默认值做任何你喜欢的事情。为每个新键分配一个 1 到 10 之间的随机值怎么样?

>>> import collections
>>> import random
>>> myDict = collections.defaultdict(lambda : random.randint(1,10))
>>> print myDict[0], myDict[100]
1 5
>>> print myDict[0], myDict[100], myDict[2]
1 5 6

好的,这个例子有点做作,但我相信你能想到更好的用途。假设您要构建一个昂贵的类 - 仅当密钥实际上不存在时才会创建实例,这与调用 getsetdefault 时不同,例如

>>> class ExpensiveClass(object):
>>>     numObjects = 0
>>>     def __init__(self):
>>>         ExpensiveClass.numObjects += 1
>>> 
>>> print ExpensiveClass.numObjects
0
>>> x = {}
>>> x[0] = ExpensiveClass()
>>> print ExpensiveClass.numObjects
1
>>> print x.get(0, ExpensiveClass())
<__main__.ExpensiveClass object at 0x025665B0>
>>> print ExpensiveClass.numObjects
2
>>> ExpensiveClass.numObjects = 0
>>> z = collections.defaultdict(ExpensiveClass)
>>> print ExpensiveClass.numObjects
0
>>> print z[0]
>>> <__main__.ExpensiveClass object at 0x02566510>
>>> print ExpensiveClass.numObjects
1

请注意,对x.get 的调用构造了一个新的ExpensiveClass 实例,即使我们从未使用过该实例,因为x[0] 已经存在。如果您确实在尝试计算 ExpensiveClass 对象的数量,或者它们的创建速度非常慢,这可能会导致问题。 collections.defaultdict 不会出现这些问题。

【讨论】:

  • 还值得注意的是setdefault()defaultdict 都有向字典中添加任何缺失键的副作用。此外,在使用defaultdict 时,如果您希望默认值根据键而有所不同,您可能需要的不仅仅是一个简单的 default_factory 函数(因为工厂函数未传递正在查找的键) .
  • 另外一件事,defaultdict 直到 Python 2.5 才被添加(并且 OP 使用的是 2.4)。
  • defaultdict 看起来很神奇,因为它是惰性的,所以除非需要,否则不会评估 lambda;希望我能投票更多
  • @martineua 哎呀,抱歉错过了 Python 2.4。是的,当然,有时defaultdict 可能会有点限制,因为您无法指定工厂函数的密钥。
【解决方案4】:

collections 模块 defaultdict 类可能会有所帮助。不幸的是,直到 Python 2.5 才引入它,并且它并没有完全完成您的代码所做的事情。以下是一些不同之处:

  • 它仅在缺少键时提供值,而不是在键存在时提供值,但具有被视为 False 的值。
  • 如果查找的键丢失,它将使用默认值将其添加到字典中并返回默认值。
  • 所有缺失值都获得相同的默认值。

如果没问题,您可以在旧版 Python 中模仿其本质,如下所示:

try:
    from collections import defaultdict
except ImportError:
    class defaultdict(dict):
        def __init__(self, default_factory=None, *a, **kw):
            dict.__init__(self, *a, **kw)
            self.default_factory = default_factory

        def __getitem__(self, key):
            try:
                return dict.__getitem__(self, key)
            except KeyError:
                return self.__missing__(key)

        def __missing__(self, key):
            self[key] = value = self.default_factory()
            return value

ActiveState 上提供了更完整模拟的方法。即使您有 Python 2.5+,您也可能希望派生自己的类来自定义以具有您想要的确切行为。除了检查“假”真值并且可能不向字典中添加任何缺失值之外,您还可以为它提供一个单独的字典,其中包含对应于不同键的多个默认值,而不是“一刀切”。有关执行此操作的方法,请参阅Is there a way to set multiple defaults on a Python dict using another dict?

【讨论】:

    猜你喜欢
    • 2015-03-22
    • 2016-02-24
    • 2012-03-25
    • 2015-07-04
    • 1970-01-01
    相关资源
    最近更新 更多