Python 为什么我的类的行为像一个静态类?

Python 为什么我的类的行为像一个静态类?,python,Python,我有一个模块,一个.py文件,实际上,有一个名为HashedDir的类 当我导入文件并实例化该类的2个实例时,当我检查对象的字段时,它们总是相同的,即使这两个对象应该不同 例如: 有什么想法吗 这是一节课: from os import walk from os import path from hashlib import md5 import re class HashedDir: """ A list of files with associated md5 hashe

我有一个模块,一个.py文件,实际上,有一个名为HashedDir的类

当我导入文件并实例化该类的2个实例时,当我检查对象的字段时,它们总是相同的,即使这两个对象应该不同

例如:

有什么想法吗

这是一节课:

from os  import walk
from os import path
from hashlib import md5
import re

class HashedDir:
    """
    A list of files with associated md5 hashes generated retrieving thou
    a recursive walk in the directory tree starting from a provided root
    directory. Also stores the dirs in each dir
    """

    #  {'files': [
    #    ('/path/to/file1', '52bc309e11259af15e4623c7a0abc28c'),
    #    ('/path/to/file2', '52bc309e11259af15e4623c7a0abc28c'),
    #    ('/path/to/dir/file3', '52bc309e11259af15e4623c7a0abc28c')
    #   ],
    #   'dirs': ['/path/to/dir1', '/path/to/dir2']
    #  }
    fileList = {'files': [], 'dirs': []}
    ignoreList = []

    def __init__(self, rootDir, ignoreList=[]):
        """
        ignoreList is a list of regular expressions. If a file or a dir matches
        that regular expression, don't count it
        """
        self.ignoreList = ignoreList

        for dirpath, dirnames, filenames in walk(rootDir):
            for fileName in filenames:
                completeName = path.join(dirpath,fileName)
                hash = md5(open(completeName).read()).hexdigest()
                relativePath = self._relativePath(completeName, rootDir)
                if not self._toBeIgnored(relativePath):
                    self.fileList['files'].append((relativePath, hash))
            for dirName in dirnames:
                completeName = path.join(dirpath, dirName)
                relativePath = self._relativePath(completeName, rootDir)
                if not self._toBeIgnored(relativePath):
                    self.fileList['dirs'].append(relativePath)

    def _relativePath(self, path, base):
        return path.replace(base, '')

    def _toBeIgnored(self, path):
        for regex in self.ignoreList:
            if re.compile(regex).search(path) != None:
                return True
        return False

    def getList(self):
        return self.fileList

提前谢谢

你说的是文件列表吗?将其作为类变量,要使其成为实例变量,需要执行以下操作:

self.fileList = {'files': [], 'dirs': []}

如果在类方法外部、类主体内部声明变量,这些变量将成为“类变量”,并对所有类实例通用。要获取实例变量,请在init函数中声明它们,并将它们绑定到“self”,即当前实例的处理程序。

如果您可以发布一个完整的工作或失败消息,这可能会很有用!例如

如果我做了我认为必要的事情,例如,将其包装在类HashedDirobject:中,并在init中设置self.fileList={'files':[],'dirs':[]),那么它似乎确实可以工作


您将哪些项目称为自我价值?根据sykora之前的文章,您需要区分在init中为每个实例运行的代码和所有实例通用的代码。

一个类中有两种变量:

类变量,在类级别定义,对所有实例通用

实例变量,在类方法中定义,通常为_uinit_uuu,并由实例自身限定

范例

class SomeClass( object ):
    classVariable = 0
    def __init__( self ):
        self.instanceVariable= 0
名为classVariable的变量是类的一部分,对所有实例都是通用的。由于Python的搜索方式,它可以作为self.classVariable和SomeClass.classVariable的成员使用

名为instanceVariable的变量是实例自身的一部分。并且对每个实例都是唯一的

注意。还有第三种类型,全局,但这不是您要问的。

类块中声明的内容是类属性,类属性也可以通过实例访问。事实上,这个原则就是方法的绑定方式。不仅如此,函数的默认参数仅在定义函数时才进行计算。因此,举一个例子来说明这两点:

class C(object):
    list_a = []
    def __init__(self, list_b=[]):
        self.list_b = list_b

    def __str__(self):
        return '%r %r' % (self.list_a, self.list_b)

c1 = C()
c2 = C()
c2.list_a = []
c3 = C([])

c1.list_a.append(1)
c1.list_b.append(2)
print c1
print c2
print c3
其输出为:

[1] [2]
[] [2]
[1] []

c1和c3共享同一个列表,因为它是类属性;它不像c2上那样被实例属性遮挡。c1和c2共享同一个列表,因为在uuu init_uuuu中只有一个默认列表;并非每次调用函数时都会创建一个新的列表,但传入您自己的新列表是有效的。

正如其他人指出的,您的问题是fileList是一个类变量,您正在对其进行变异

但是,值得注意的是,代码中的另一个潜在陷阱可能会导致类似的问题,尽管在您的特定示例中没有:

def __init__(self, rootDir, ignoreList=[]):
注意将可变参数(如此列表)作为默认参数传递。当您定义_init__函数时,该列表只创建一次。这意味着使用默认值构造的类的所有实例将使用相同的列表

在您的示例中,列表从未被修改,因此这不会产生任何影响,但如果像对fileList所做的那样附加到self.ignoreList,则这将影响所有此类实例,从而导致与您看到的问题类似的问题

这是一个非常常见的初学者问题-为了避免它,最好编写如下代码:

def __init__(self, rootDir, ignoreList=None):
    if ignoreList is None:
        ignoreList = []  # This will create a new empty list for every instance.

你应该发布类的代码。你的代码写得没有意义。您已经导入/重命名了os.walk、os.path和md5.md5,但没有提到这一点。更正后,我们发现HashedDir的实例没有.attirbute值,正如上面的代码所显示的那样。>>>a=HashedDir/home/smithma/tmp;打印a.value回溯最近一次调用last:File,第1行,在AttributeError:HashedDir实例中没有属性'value',嗨,代码现在已更正…h。。所以在“class”之后声明它并在init中操作它是不够的?不,Python允许您将类变量引用为实例。classvariable@pistacchio:没有声明。将变量名分配给对象,如字典或list.self。不完全限定变量为实例成员。classVariable和instanceVariable通常都以self作为前缀。引用时。
def __init__(self, rootDir, ignoreList=None):
    if ignoreList is None:
        ignoreList = []  # This will create a new empty list for every instance.