【问题标题】:Calling type(dict) functions within classes on class variables (Python 3.4)在类变量的类中调用 type(dict) 函数(Python 3.4)
【发布时间】:2015-01-16 01:33:41
【问题描述】:

我正在创建一个类并尝试定义与在另一个类变量上调用的 .keys() 或 .values() 等函数相对应的类变量。 例如:

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

这似乎不起作用,因为当我创建类的实例时

foo = DATA(0,{"a":1,"b":2})

然后要求:

print(foo.addresses)
>>> []

它返回一个空列表。

注意:

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

谁能帮我解决这个问题?

【问题讨论】:

  • @Brandon Gomes:当你说“然后要求”时——实际上中间有一些步骤吗?你真的是从 foo = DATA(0, {}) 开始,然后再更改 DATA.database 吗?

标签: python function class dictionary


【解决方案1】:

我不确定这是否是问题所在,但使用诸如 {} 之类的可变参数作为默认参数通常会导致错误。见:"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()

【讨论】:

  • 谢谢霍肯。我避免使用条件,因为我希望代码更紧凑并且可能更快。如果我使用您的建议,那么我会收到“NoneType 没有关键属性”错误。我想如果我一起摆脱可变参数,它可能会起作用,因为我永远不会使用字典以外的数据库。
  • 我认为这不能解释它。我认为您在定义foo 和检查删除内容的地址之间做了一些事情。但是以这种方式编写代码仍然是一个更好的主意。
  • 如果您担心 if 块会使您的代码变慢,那么您需要记住 Donald Knuth 的这句话。 “程序员浪费大量时间去思考或担心他们程序中非关键部分的速度,而在考虑调试和维护时,这些效率上的尝试实际上会产生强烈的负面影响。我们应该忘记小的效率,说97% 的时间:过早的优化是万恶之源。但我们不应该放弃关键的 3% 的机会。”
【解决方案2】:

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

现在,根据您班级的要求,您可以通过几种不同的方式来做到这一点。

如果您不介意公开更改调用代码,您可以使其非常简单,只需使用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 视为一个属性。如果您在其他代码(例如foo.database = {"foo":"bar"})中完全替换database 对象,它也将正常工作。不过它可能会慢一些,因为会有一个其他方法不需要的额外函数调用。

【讨论】:

    猜你喜欢
    • 2014-08-20
    • 2022-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    • 2020-08-03
    相关资源
    最近更新 更多