从python中的类变量调用class / static方法

时间:2011-02-15 14:25:08

标签: python class

我正在尝试让ImageLoader类处理像这样的图像资源的加载和处理:

class ImageLoader:
    TileTable = __loadTileTable('image path', some other variable)

    @staticmethod
    def _loadTileTable(arg1, arg2):
        blah blah

然而,在编译时我得到:NameError: name '_loadTileTable' is not defined

如果我用TileTable = ImageLoader.__loadTileTable('image path', some other variable)替换第二行,那么我得到NameError: name 'ImageLoader' is not defined

当我从C#转到Python时,使用静态方法的静态类就是我用来实现它的。但是,我对如何在python中执行此操作持开放态度(即,仅通过其功能将调用静态库函数组合在一起)。

更新 在阅读了这两个答案之后,我得到的照片是我正在尝试做的事情可能不对。 我将如何使用ImageLoader以便我可以执行此操作:

假设tile表返回了一个数组

module1.py

aTile = ImageLoader.TileTable[1]

module2.py

anotherTile = ImageLoader.TileTable[2]

理想情况下,我只会填充一次TileTable。

更新

感谢所有答案,我发现我在python模块doco中只填充一次TileTable的最后答案

  

“模块可以包含可执行文件   陈述和功能   定义。这些陈述是   旨在初始化模块。   它们仅在第一次执行   模块导入到某个地方“

对于静态类,我将放弃类并只创建一个模块级变量。

4 个答案:

答案 0 :(得分:5)

回答刚才更新的问题,你在Python中做的是在名为TileTable的模块中将tile_table变成一个名为imageloader的变量。完全没有理由将其中的任何内容放入课堂中。

那么你得到:

<强> module1.py

import imageloader
aTile = imageloader.tile_table[1]

<强> module2.py

import imageloader
anotherTile = imageloader.tile_table[2]

imageload.py 类似于:

def _loadTileTable(arg1, arg2):
    pass # blah blah
tile_table = _loadTileTable('image path', other_var)

将Python模块视为其他语言中的单例实例(实际上它是这样),并且您将能够将其与从其他语言继承的任何OO预先概念进行协调。

答案 1 :(得分:3)

在Python中,首先执行类块中的代码,然后将生成的命名空间传递给类初始化程序。你写的代码也可以写成:

TileTable = _loadTileTable(arg1, arg2)
@staticmethod
def _loadTileTable(arg1, arg2):
    pass # blah blah
ImageLoader = type('ImageLoader', (), {'TileTable': TileTable, '_loadTileTable': _loadTileTable})
del TileTable
del _loadTileTable

如您所见,_loadTileTable的调用出现在它的定义之前。在您的示例中,在类定义中,对_loadTileTable的调用必须在_loadTileTable的定义之后。

一种可能的解决方法是简单地重新安排类定义。

class ImageLoader:
    def _loadTileTable(arg1, arg2):
        pass # blah, blah

    TileTable = _loadTileTable('image path', other_var)

请注意,我删除了'staticmethod',因为在调用_loadTileTable时,它被称为函数而不是方法。如果你真的希望它在类初始化后可用,你可以在事后将它定义为静态方法。

class ImageLoader:
    def _loadTileTable(arg1, arg2):
        pass # blah, blah

    TileTable = _loadTileTable('image path', other_var)

    _loadTileTable = staticmethod(_loadTileTable)

答案 2 :(得分:3)

更新的类级变量是一件坏事,坏事。我们的默认期望是对象实例是有状态的,而类是无状态的。

在这种情况下,我们试图“神奇地”将一个集合初始化为一个类变量,这是一个非常糟糕的主意。集合只是一个具有简单实例级属性的对象。

神奇的平铺表不应该是ImageLoader的隐藏静态部分。没有可能的原因。如果您想避免多次加载它,它应该是ImageLoader的参数。

将它们分开可提高可测试性。这不是武断的。这就是单元测试的完成方式。

你想要的是这个。

class ImageLoader( object ):
    def __init__( self, theTileTable ):
        self.tile_table= theTileTable

class TileTable( object ):
    def __init__( self, path, some_other_arg ):
         self.tileTable= self._loadTileTable( path, some_other_arg )
    def _loadTileTable(arg1, arg2):
         blah blah

没有任何静态。独立单位。更容易测试。没有奇怪的依赖。没有魔法。

答案 3 :(得分:2)

您是否有使用静态方法的设计原因?如果是这样,因为你没有重载类初始化,你需要在方法定义之后声明变量

但是,如果你这样做,你会得到一个新的错误:

NameError: name 'arg1' is not defined

这样做的原因是因为您在类甚至实例化之前正在类中执行该方法,因此您永远不会有机会将参数传递给该方法。

因此,正确的方法是重载__init__()方法,以便只有在构造类时才会分配给TileTable

class ImageLoader(object):
    def __init__(self, arg1, arg2):
        self.TileTable = self._loadTileTable(arg1, arg2)

    @staticmethod
    def _loadTileTable(arg1, arg2):
        print arg1, arg2

这使您能够在没有实例的情况下调用ImageLoader._loadTileTable(),但是它还允许您在创建实例时创建TileTable实例变量。

使用班级方法
在回应我关于可能需要类方法的评论时,这里有一个例子来说明这一点:

class ImageLoader:
    @classmethod
    def _loadTileTable(cls, arg1, arg2):
        return arg1, arg2

# We're creating the class variable outside of the class definition. If you're doing 
# this in a module, no one will ever notice.
ImageLoader.TileTable = ImageLoader._loadTileTable('foo', 'bar')

我不知道可能有更好的方法来做到这一点。但我认为这涵盖了您所寻找的内容:

>>> i = ImageLoader()
>>> i
<__main__.ImageLoader instance at 0x100488f80>
>>> ImageLoader.TileTable
('foo', 'bar')
>>> i.TileTable
('foo', 'bar')

你有一个实例i可以访问类变量,但是ImageLoader.TileTable仍然可以从类对象中获得,而不需要实例。