我正在尝试让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的最后答案
“模块可以包含可执行文件 陈述和功能 定义。这些陈述是 旨在初始化模块。 它们仅在第一次执行 模块导入到某个地方“
对于静态类,我将放弃类并只创建一个模块级变量。
答案 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
仍然可以从类对象中获得,而不需要实例。