Python中空元组的潜在用途

时间:2014-07-11 19:25:52

标签: python immutability class-variables immutablearray

我正在玩Python中类级变量的风险,我认为列表作为类级变量的风险可以通过元组来解决,例如,一个空元组。

采取:

class BaseClass(object):
    default_sth = []

    def foo(self):
       for sth in self.default_sth:
           pass

这有风险,因为:

class SubClass(BaseClass):
    pass

a = SubClass()
a.default_sth.append(3)

print(BaseClass.default_sth) # [3]

使用None代替空元组(tuple()?)可能会有危险,因为它在迭代时会失败。

由于不变性,我认为这是一个不错的选择,但我认为我没有看到任何人在任何地方谈论这个。你有没有看到这种推理的缺陷?它是pythonic吗?

3 个答案:

答案 0 :(得分:2)

您将类变量与实例变量混淆(这很容易做到,因为在没有初始化的实例变量的情况下,查找会找到类变量)。在这种情况下,您明确表示default_sth是一个类变量,当您的意思是具有实例变量的默认值时。请改用:

class BaseClass(object):
    def __init__(self, sth=None):
        if sth is None:
            sth = []

    def foo(self):
       for sth in self.sth:
           pass

您可能会对“硬编码”默认值略有提及,但您只是通过尝试为默认值设置单独的名称来添加详细程度。只需评论并记录您的__init__方法,以指明sth是什么以及如果不是,则默认值应该是什么 其他值传递。除非你有充分的理由,否则不要试图让默认值自行配置。

就不变性而言,只有元组是不可变的,而不是引用它的名称。没有什么可以阻止某人使用您的原始代码并说

BaseClass.default_sth = []

然后你就回到了你开始的地方,尽管开始使用default_sth元组。

答案 1 :(得分:1)

我认为使用元组而不是列表的问题是人们通常选择使用列表,因为他们实际上需要列表语义;您不能附加到元组,对其进行排序,从中删除项目等。如果您希望您的类级列表属性不与子类共享,则子类可以只创建自己的副本:

from copy import deepcopy

class SubClass(BaseClass):
    default_sth = deepcopy(BaseClass.default_sth)  # now SubClass has its own copy.

然后您的示例将输出[],这是您更喜欢的行为。如果您在BaseClass中使用元组,那么您的示例将抛出AttributeError(因为它尝试在元组上调用append),并且代码需要更改为此才能执行相当于append

a = SubClass()
a.default_sth = tuple(list(a.default_sth) + [3])

由于您正在进行一系列复制以从元组转换,因此写入并且效率不高是非常有效的 - >列表 - >元组。

答案 2 :(得分:0)

可变的默认变量在众所周知的Python中是众所周知的屁。

E.g。

http://eli.thegreenplace.net/2009/01/16/python-insight-beware-of-mutable-default-values-for-arguments/

"Least Astonishment" and the Mutable Default Argument

http://pythonconquerstheuniverse.wordpress.com/2012/02/15/mutable-default-arguments/

解决方案包括

  • 初始化__init__中的所有内容 - 除非你真的是指全局变量,否则不要使用类级变量

  • 传入None并在第一次访问时将其转换为列表