在 Python 中,是否可以从静态方法引用实例变量?

In Python, is referencing an instance variable from a staticmethod possible?

我知道之前有人问过这个问题,但我发现自己遇到了静态方法最合适的情况,但也需要在这个 class 中引用实例变量。例如,假设我有以下 class:

class ExampleClass(object):
    def __init__(self, filename = 'defaultFilename'):
        self.file_name = filename

    @staticmethod
    def doSomethingWithFiles(file_2, file_1 = None):
         #if user didn't supply a file use the instance variable 
         if file_1 is None:
            # no idea how to handle the uninitialized class case to create
            # self.file_name. 
            file_1 = __class__.__init__().__dict__['file_name'] <--- this seems sketchy
         else:
            file_1 = file_1
         with open(file_1, 'r') as f1, open(file_2, 'w') as f2:
            .....you get the idea...

    def moreMethodsThatUseSelf(self):
        pass

现在假设我有几个 ExampleClass 实例(E1、E2、E3)将不同的文件名传递给 __init__,但我想保留使用未初始化的 class ExampleClass.doSomethingWithFiles(file_2 = E1.file_name, file_1 = E2.file_name) 或 E1.doSomethingWithFiles(file_2 = E2.file_name, file_1 = 'some_other_file')视情况而定。

我有什么理由试图找到一种方法来做我想做的事,还是我把事情搞得一团糟?

更新 我认为这些评论很有帮助,而且我也认为这是由于糟糕的设计而遇到的问题。

这个问题最初是为了防止并发访问 HDF5 文件的一种方法,方法是为每个 class 实例提供一个 rlock,我可以将其用作上下文管理器,以防止任何其他尝试访问该文件正在使用。每个 class 实例都有自己的 rlock,它在完成需要做的任何事情后获取和释放。我还使用 @staticmethod 执行一个例程,然后生成一个文件,该文件被传递到它自己的 init() 并且对于每个 class 实例都是唯一的。当时看起来很聪明,但我很后悔。我还认为我完全不确定何时 @staticmethods 是合适的并且可能将它与 @class 方法混淆,但是 class 变量将不再使我的 class 实例可能。我想我应该更多地考虑设计,而不是尝试使用我并不真正理解的 class 定义来证明其旨在防止的方式。

也许我误解了您的意图,但我认为您误用了默认参数。 您似乎正在尝试使用 'defaultFilename' 作为默认参数值。为什么不跳过尴尬

 if file_1 is None:
        # no idea how to handle the uninitialized class case to create
        # self.file_name. 
        file_1 = __class__.__init__().__dict__['file_name'] <--- this seems sketchy

并更改函数如下,

def doSomethingWithFiles(file_2, file_1='defaultFilename'):

如果对该值进行硬编码让您感到不舒服,不妨试试

class ExampleClass(object):
    DEFAULT_FILE_NAME = 'defaultFilename'

    def __init__(self, filename=DEFAULT_FILE_NAME):
        self.file_name = filename

    @staticmethod
    def doSomethingWithFiles(file_2, file_1=DEFAULT_FILE_NAME):
         with open(file_1, 'r') as f1, open(file_2, 'w') as f2:
            # do magic in here

    def moreMethodsThatUseSelf(self):
        pass

不过,一般来说,如果您想在静态方法中访问实例变量,您的问题建模可能是错误的。

如果您认为自己一直遇到静态方法最合适的情况,那您可能错了 — 它们的良好用途非常罕见。如果您的静态方法需要访问实例变量,那么您 肯定是 错误的。

静态方法不能直接访问实例变量。不能有 class 的实例,或者一千个;您将从哪一个访问变量?


您要做的是创建一个新实例,只是为了访问它的实例变量。这有时会很有用——尽管它通常是一个好兆头,您一开始就不需要 class。 (而且,当它有用时,它非常不寻常,通常值得发信号,让调用者写 ExampleClass().doSomethingWithFiles 而不是 ExampleClass.doSomethingWithFiles。)

这是合法的,但您只需调用 class,而不是调用其 __init__ 方法即可。 __init__ 从来没有 returns 任何东西;它收到 already-created self 并对其进行修改。如果你真的想要,你可以调用它的 __new__ 方法,但这实际上与调用 class 的意思相同。 (在它们不同的次要方面,它调用了您想要的 class。)

另外,一旦你有一个实例,你就可以正常使用它;你不需要看它的__dict__。 (即使您只有属性名称作为字符串变量,getattr(obj, name) 几乎总是您想要的,而不是 obj.__dict__[name]。)

所以:

file_1 = __class__().file_name

那么,你应该怎么做呢?

嗯,看看你的设计。 ExampleClass 实例唯一做的就是保存一个文件名,它有一个默认值。为此,您不需要对象,只需传入一个普通的旧字符串变量,或将其存储为全局变量。 (你可能听说过全局变量是不好的——但是伪装的全局变量同样糟糕,而且还有一个额外的问题,那就是它们是伪装的。这基本上就是你设计的。有时,全局变量是正确的答案。)

为什么不将实例作为参数输入静态方法。希望这段代码对您有所帮助。

 class ClassA:
    def __init__(self, fname):
        self.fname = fname

    def print(self):
        print('fname=', self.fname)

    @staticmethod
    def check(f):
        if type(f)==ClassA :
            print('f is exist.')
            f.print()
            print('f.fname=', f.fname)
        else:
            print('f is not exist: new ClassA')
            newa = ClassA(f)
            return newa


a=ClassA('temp')
b=ClassA('test')
ClassA.check(a)
ClassA.check(b)
newa = ClassA.check('hello')
newa.print()

您不能从静态方法中引用实例属性。假设存在多个实例,您会从哪个实例中选择属性?

您似乎需要的是 class 属性和 class 方法。您可以使用 classmethod 装饰器定义一个。

class ExampleClass(object):
    file_name = 'foo'

    @classmethod
    def doSomethingWithFiles(cls, file_2, file_1 = None):
        file_1 = cls.file_name
        # Do stuff