簡體   English   中英

從python中的類變量調用class / static方法

[英]calling class/static method from class variable in python

我正在嘗試使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的最后答案

“模塊可以包含可執行語句和函數定義。這些語句用於初始化模塊。它們僅在模塊第一次導入時才執行”

至於靜態類,我將放棄類並只創建一個模塊級變量。

回答剛才更新的問題,你在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預先概念進行協調。

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

更新的類級變量是一件壞事,壞事。 我們的默認期望是對象實例是有狀態的,而類是無狀態的。

在這種情況下,我們試圖“神奇地”將一個集合初始化為一個類變量,這是一個非常糟糕的主意。 集合只是一個具有簡單實例級屬性的對象。

神奇的Tile Table不應該是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

沒有任何靜態。 獨立單位。 更容易測試。 沒有奇怪的依賴。 沒有魔法。

您是否有使用靜態方法的設計原因? 如果是這樣,因為你沒有重載類初始化,你需要在方法定義之后聲明變量。

但是,如果你這樣做,你會得到一個新的錯誤:

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方法
在回應我關於可能需要類方法的評論時,這里有一個例子涵蓋了這個:

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仍然可以從類對象中獲得,而不需要實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM