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

时间:2018-04-02 02:12:29

标签: python class variables instance static-methods

我知道之前已经问过这个问题,但我发现自己遇到了静态方法最合适的情况,但是还需要在这个类中引用一个实例变量。举个例子,假设我有以下类:

> mydf
   name     col1      col1
1     A 1.373546        NA
2     B 2.183643 8.0235623
3     C 1.164371        NA
4     D 3.595281 5.7796865
5     E 2.329508 3.7575188
6     F 1.179532        NA
7     G 2.487429 0.5706002
8     H 2.738325 7.2498618
9     I 2.575781        NA
10    J 1.694612 4.9101328

现在假设我有一些ExampleClass(E1,E2,E3)的实例,其中不同的文件名传递到__init__,但是希望保留使用未初始化的类的能力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文件的方法,它通过为每个类实例提供一个rlock,我可以将其用作上下文管理器,以防止任何其他尝试在文件使用时访问该文件。每个类实例都拥有它自己获得的rlock,并在完成所需的任何操作时释放。我还使用@staticmethod来执行一个例程,然后生成一个文件,该文件被传递给它自己的 init (),并且对每个类实例都是唯一的。当时看起来很聪明,但我后悔了。我还认为我完全不确定@staticmethods何时适合并且可能使它与@classmethods混淆,但是类变量将不再使我的类实例独有的rlock和文件成为可能。我想我应该更多地考虑设计与试图证明使用类定义的合理性,我并没有真正理解它以防止它被设计的方式。

4 个答案:

答案 0 :(得分:3)

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

staticmethod无法直接访问实例变量。没有班级的实例,或数千;您可以从哪个访问变量?

您尝试做的是创建一个新实例,只是为了访问其实例变量。这可能偶尔会有用 - 虽然它通常是一个好兆头,你首先不需要上课。 (并且,当它有用时,它通常非常不合适,通常让调用者写 mydf$col2 <- NA mydf$col2[match(names(a), rownames(mydf))] <- a 而不是ExampleClass().doSomethingWithFiles。)

这是合法的,但你只需要调用类,而不是调用它的ExampleClass.doSomethingWithFiles方法。 __init__永远不会返回任何东西;它接收已经创建的__init__并修改它。如果你真的想要,你可以调用它的self方法,但这实际上只是意味着调用类。 (在他们与之不同的次要方式中,它会调用你想要的课程。)

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

所以:

obj.__dict__[name]

那么,你该怎么做呢?

好吧,看看你的设计。 file_1 = __class__().file_name 实例唯一做的是保存文件名,该文件名具有默认值。你不需要一个对象,只需要传入一个普通的旧字符串变量,或者存储为全局变量。 (你可能听说全局变量很糟糕 - 但伪装的全局变量同样糟糕,并且还有其他问题,他们会变相伪装。这基本上就是你设计的。有时,全局变量是正确的答案。)

答案 1 :(得分:0)

也许我误解了你的意图,但我认为你误用了默认参数。 您似乎正在尝试使用'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

但是,一般情况下,如果要在静态方法中访问实例变量,则可能错误地将问题建模。

答案 2 :(得分:0)

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

 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()

答案 3 :(得分:0)

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

您似乎需要具有类属性和类方法。您可以使用classmethod装饰器定义一个。

class ExampleClass(object):
    file_name = 'foo'

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