在 classes 中对 class 变量调用 type(dict) 函数 (Python 3.4)

Calling type(dict) functions within classes on class variables (Python 3.4)

我正在创建一个 class 并尝试定义 class 变量,这些变量对应于在另一个 class 变量上调用的函数,例如 .keys() 或 .values() . 例如:

class DATA(object):
    def __init__(self, id, database = {}):
        self.id = id
        self.database = database
        self.addresses = database.keys()
        self.data = database.values()

这似乎不起作用,因为当我创建 class

的实例时
foo = DATA(0,{"a":1,"b":2})

然后要求:

print(foo.addresses)
>>> []

它返回一个空列表。

注:

在我的实际程序中,我从任何 class 实例的空字典开始,然后我使用一个函数添加到字典中。在这种情况下,调用“.database”仍然有效,但“.addresses”无效。

谁能帮我解决这个问题?

我不确定这是不是问题所在,但使用 {} 等可变变量作为默认参数通常会导致错误。参见:"Least Astonishment" and the Mutable Default Argument

这样更安全:

def __init__(self, id, database=None):
    if database is None:
        self.database = {}
    else: 
        self.database = database

我不明白 DATA.addresses 和 DATA.data 的目的。您可以使用带有 属性 装饰器的函数来避免冗余吗?

@property:
def addresses(self):
    return self.database.keys()

@property:
def data(self):
    return self.database.values()

问题是您在 __init__ 方法中调用 keys 并保存结果。您要做的是仅在您想要访问它时才调用 keys

现在,根据您 class 的要求,您可以通过几种不同的方式完成此操作。

如果您不介意公开更改调用代码,您可以使其变得非常简单,只需使用 foo.database.keys() 而不是 foo.addresses。后者不需要存在,因为它包含的所有信息都可以通过 databases 属性的方法获得。

另一种方法是将绑定的实例方法 database.keys 保存到 DATA 对象的实例变量中(不调用它):

class DATA(object)
    def __init__(self, database=None):
        if database is None:
            database = {}
        self.database = database
        self.addresses = database.keys    # don't call keys here!

在调用代码中,您将使用 foo.addresses() 而不是 foo.addresses(函数调用,而不仅仅是属性查找)。这看起来像是对 DATA 实例的方法调用,但实际上并非如此。它在数据库字典上调用已经绑定的方法。如果其他代码可能会完全替换 database 字典(而不是就地改变它),这可能会中断。

最后一种方法是在用户尝试访问 DATA 实例的 addresses 属性时,使用 property 从数据库字典中请求 keys :

class DATA(object)
    def __init__(self, database=None):
        if database is None:
            database = {}
        self.database = database
        # don't save anything as "addresses" here

    @property
    def addresses(self):
        return self.database.keys()

这可能是最好的,因为它让调用代码将 addresses 视为一个属性。如果您将 database 对象完全替换为其他代码(例如 foo.database = {"foo":"bar"}),它也可以正常工作。不过它可能会慢一点,因为会有一个其他方法不需要的额外函数调用。