【问题标题】:Python Module/Class Variable BleedingPython 模块/类变量出血
【发布时间】:2009-04-24 00:57:06
【问题描述】:

好的,我花了一点时间来缩小这个问题的范围,但似乎 python 正在做这个目的。有人可以解释为什么会发生这种情况以及我能做些什么来解决这个问题吗?

文件:库/testModule.py

class testClass:

    myvars = dict()

    def __getattr__(self, k):
        if self.myvars.has_key(k):
            return self.myvars[k]

    def __setattr__(self, k, v):
        self.myvars[k] = v

    def __str__(self):
        l = []
        for k, v in self.myvars.iteritems():
            l.append(str(k) + ":" + str(v))

        return " - ".join(l)

test.py

from library import testModule

#I get the same result if I instantiate both classes one after another
c1 = testClass()
c1.foo = "hello"
c2 = testClass()

print("c1: " + str(c1) + "\n")
print("c2: " + str(c2) + "\n")

输出:

c1: foo:hello
c2: foo:hello

我最好的猜测是因为library 有一个"__init__.py" 文件,所以整个模块像类对象一样被加载,现在它变成了持久对象的一部分。是这样吗?

【问题讨论】:

  • 由于这是类/实例变量的问题,与模块无关,能否修改题名?

标签: python oop class


【解决方案1】:

myvarsclass 的属性,而不是 instance 的属性。这意味着当您从实例c1 将属性插入myvars 时,该属性将与testClass 类相关联,而不是与c1 实例相关联。由于c2是同一个类的实例,所以它也有同样的属性。

你可以通过这样写得到你想要的行为:

class testClass:
    def __init__(self):
        self.myvars = dict()

    def __getattr__(self, k):
        if self.myvars.has_key(k):
            return self.myvars[k]

    def __setattr__(self, k, v):
        self.myvars[k] = v

    def __str__(self):
        l = []
        for k, v in self.myvars.iteritems():
            l.append(str(k) + ":" + str(v))
        return " - ".join(l)

【讨论】:

  • 其实在 init__() 中赋值 self.myvars = dict() 会导致递归错误。嘿,我认为解决方案是放弃 __setattr 并改用 dict var。
  • 哦,是的,我没有考虑递归问题......你可以解决这个问题,但使用内置 var dict 确实会更好。这正是它的用途。
  • 这可能是明智的。但导致递归错误的不是 setattrsetatrr 调用 getattr 在第一行调用它自己。
【解决方案2】:

其他的答案都是正确的并且切中要害。让我谈谈我认为你的误解。

我最好的猜测是,因为库有一个“__init__.py”文件,整个模块就像一个类对象一样被加载,现在它变成了一个持久对象的一部分。是这样的吗?

所有包都有一个__init__.py 文件。有必要制作一个python包。该软件包中可能有也可能没有任何代码。如果确实如此,则保证执行。在一般情况下,这与包中其他模块的执行方式没有任何关系,尽管当然可以在其中放置很多非常酷的技巧来影响它。

至于模块和类的工作方式,将模块视为一个实例化一次的类对象通常是一个非常好的主意。加载器执行文件一次,所有在文件末尾可用的变量、类定义和函数定义都可以作为模块的一部分访问。

类也是如此,主要的例外是在类中声明的函数被转换为方法(一种特殊的方法可以让您实例化类)。所以testModule has-a testClass has-a myvars。所有三个对象都是唯一的:它们中的任何一个都不会有多个实例。无论我们说“模块有一个类对象”还是“类对象有一个类变量”,has-a 关系实际上或多或少是相同的。 (区别在于你不应该关心的实现细节。)

【讨论】:

    【解决方案3】:

    关于如何使用 getattr 和其他类似方法的良好参考,请参考How-To Guide for Descriptors,没有什么比实践更棒的了!

    【讨论】:

      猜你喜欢
      • 2011-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-30
      • 2011-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多