Python - 使用 defaultdict 制作自定义对象的字典

问题描述 投票:0回答:3

我创建了以下课程。包、网站和评论都是字符串,distroDict 是一个(字符串,列表)字典。

class TableEntry(object):

    def __init__(self, package, website, distroDict, comments):
        self.package = package
        self.website = website
        self.distroDict = distroDict
        self.comments = comments

我想使用 defaultdict(TableEntry) 制作一个 (string, TableEntry) 自定义字典。

tableDict = defaultdict(TableEntry)
entry = TableEntry(package, website, distroDict, comments)
tableDict[package].append(entry)

我希望包是键,入口对象是值。我可以使用条目对象中的值,但如果我尝试将其附加到 tableDict,我会收到以下错误。

Traceback (most recent call last):
  File "wiki.py", line 151, in <module>
    printMetaData(lines, f)
  File "wiki.py", line 73, in printMetaData
    tableDict[package].append(entry)
TypeError: __init__() takes exactly 5 arguments (1 given)

我还尝试过以下方法:

tableDict[package].append(TableEntry(package, website, distroDict, comments))

并且本质上收到相同的错误:

Traceback (most recent call last):
  File "wiki.py", line 150, in <module>
    printMetaData(lines, f)
  File "wiki.py", line 73, in printMetaData
    tableDict[package].append(TableEntry(package, website, distroDict, comments))
TypeError: __init__() takes exactly 5 arguments (1 given)
python dictionary defaultdict
3个回答
8
投票

当您尝试从 defaultdict 获取某些内容时,它会返回您实例化它的

default_factory
的实例,在您的情况下是
TableEntry
,没有方法
append
。但这实际上不是您收到错误的原因。发生这种情况是因为当返回一个实例时,它也会被评估,并且由于
TableEntry
没有它需要的参数,Python 解释器会抱怨。但即使在
TableEntry
调用中给定了
defaultdict
参数,您也可能会得到
TypeError
,因为
defaultdict
需要使用可调用对象(而不是类的实例)来调用。

总之,你不能用不可调用的实例化 defaultdict 除非你使用子类。相反,你应该做这样的事情:

class TableEntry(object):
    def add(self, package, website, distroDict, comments):
        self.package = package
        self.website = website
        self.distroDict = distroDict
        self.comments = comments

tableDict = defaultdict(TableEntry)
entry = ("package", "website", "distroDict", "comments")
tableDict["package"].add(*entry)

然后你可以这样做

tableDict["package"]["website"]
获取您写入
self.website
的字符串。


1
投票

另一种方法是让

__init__
方法的参数为可选,并将条目对象直接分配给tableDict。

class TableEntry:
    def __init__(self, package=None, website=None, distroDict=None, comments=None):
        self.package = package
        self.website = website
        self.distroDict = distroDict
        self.comments = comments

tableDict = defaultdict(TableEntry)
tableDict["package"] = TableEntry("package", "website", "distroDict", "comments")

0
投票

要使用

defaultdict
,您需要在默认初始化的类中提供实际的默认值。否则,当您尝试访问它时,您将收到运行时错误。如果您立即手动初始化该值,则不需要
defaultdict

要解决问题的

tableDict[package].append(entry)
,您所需要的只是
defaultdict(list)

tableDict = defaultdict(list)
entry = TableEntry(package, website, distroDict, comments)
tableDict[package].append(entry)

但这里有一些实际使用 defaultdicts 的示例,可以让您省去一些初始化检查和代码

dataclasses
:

from dataclasses import dataclass, field
from collections import defaultdict
from typing import Any, Dict, List

@dataclass
class TableEntry:
     package: str = ""
     website: str = ""
     distroDict: Dict[str, Any] = field(default_factory=defaultdict)
     comments: List[str] = field(default_factory=list)

tableDict = defaultdict(TableEntry)
tableDict["mytestexample"]
>>> TableEntry(package='', website='', distroDict='', comments=[])

这可能是 defaultdict 可用性的更完整示例,其中更改了一些名称以更多地与包依赖项列表相关:

from dataclasses import dataclass, field
from collections import defaultdict
from typing import Any, Dict, List

@dataclass
class DependencyEntry:
   package: str
   website: str
   distroDict: Dict[str, Any] = field(default_factory=defaultdict)
   comments: List[str] = field(default_factory=list)

@dataclass
class DependencyGroup:
   dependency_count: int = 0
   dependencies: List[DependencyEntry] = field(default_factory=list)

dependencyTable = defaultdict(DependencyGroup)
dependencyTable["mytestpackage"]
>>> DependencyGroup(dependency_count=0, dependencies=[])

dependencyTable["mytestpackage"].dependencies
>>> []

# add a new instance directly into the dependency list
dependencyTable["mytestpackage"].dependencies.append(
    DependencyEntry("Test", "example.com", {"distroArch": "metadata"}, ["this is a comment"]))

dependencyTable["mytestpackage"].dependencies
>>> [DependencyEntry(package='Test', website='example.com', distroDict={'distroArch': 'metadata'}, comments=['this is a comment'])]
© www.soinside.com 2019 - 2024. All rights reserved.