2014-02-19 98 views
11

我有一個Python模塊,它包含許多類,每個類都代表具有其屬性(例如密度,比熱)的特定物理材料。一些屬性只是該類的成員float,但許多屬性取決於某個參數,例如溫度。我實現了這個通過@staticmethod S,即,所有的類看起來像只有靜態方法的類模塊

class Copper(object): 
    magnetic_permeability = 1.0 

    @staticmethod 
    def density(T): 
     return 1.0/(-3.033e-9 + 68.85e-12*T - 6.72e-15*T**2 + 8.56e-18*T**3) 

    @staticmethod 
    def electric_conductivity(T, p): 
     return 1.0141 * T**2 * p 

    @staticmethod 
    def specific heat(T): 
     return ... 


class Silver(object): 
    ... 

class Argon(object): 
    ... 

... 

Class ES因此僅僅作爲所有數據的容器,和@staticmethod S中的丰度有我懷疑有可能是一個更適合這種用例的設計模式。

任何提示?

+0

如果它是靜態的......這意味着它基本上是固定值。如果是這樣,這實際上是數據,並可能更好地處理爲更傳統的數據結構。字典,如果你想創建它的話,如xml/yaml,如果你想從磁盤加載。我甚至曾經寫過一組類,它會加載一個XML並將其作爲屬性公開,所以即使從XML中加載了「metals」,仍然可以執行諸如「metals.copper.magnetic_permeability * 4」之類的操作。像這樣的東西可能會給你兩全其美的... –

+1

但屬性取決於溫度等 –

+0

staticmethod實際上似乎很合適。 –

回答

3

你可以命名你的模塊copper並創建所有這些作爲模塊級功能,然後import copper; copper.density(0)

但是,如果有人做from copper import density,並且還呼籲cobalt模塊和另一個叫carbon和另一個叫chlorine等,都用自己的density功能?呃哦。

由於we're all consenting adults here,你可以記錄這一點,並希望你的用戶知道足夠好,只導入模塊。或者你可以採取你的方法;在這種情況下,我會考慮將所有元素放在一個名爲elements的模塊中,然後用戶可以使用from elements import Copper。靜態方法將是適當的。

+0

其實,'__all__'模塊級變量不能幫助用戶不正確導入東西? –

+0

@CédricVanRompay我不認爲我會看到'__all__'如何防止人們在導入時隱藏東西。你能詳細說明嗎? – 2rs2ts

1

這實在是一個「味道季節」的問題。你可以像你做的那樣做 - 在一個類上的方法或者你可以完全消除這個類,然後使用模塊級的函數。一般來說,我更喜歡讀取/理解保持的更簡單的文件。

嚴格基於您分享的有限範例 - 我傾向於模塊級功能。但是,當然,更加充實的例子可能會改變這種觀點。

+0

代碼示例現在應該更全面地瞭解文件內容。 –

1

定義靜態方法實際上總是一個錯誤。 Python有函數,所以你總是定義一個模塊級函數。 (你必須copper.py和它裏面有一個普通的老def density(T):,而不是使用靜態方法。)

也就是說,copper.py看起來像

magnetic_permeability = 1.0 

def density(T): 
    return 1.0/(-3.033e-9 + 68.85e-12*T - 6.72e-15*T**2 + 8.56e-18*T**3) 

def electric_conductivity(T, p): 
    return 1.0141 * T**2 * p 

def specific heat(T): 
    return ... 

在這種特殊情況下,你真的有多種材料嗎?如果是這樣,那麼你可能希望他們成爲實例,而不是類或模塊。如果你不希望它們都具有與熱密度相關的相同的有理立方形式,那麼你可以創建一個子類並擁有一個實例,或者你可以創建一個接受函數作爲參數的類。

class Material(object): 
    def __init__(self, density, electric conductivity): 
     self.density = density 
     self.electric_conductivity = electric_conductivity 

copper = Material(
    density=lambda T: 1.0/(-3.033e-9 + 68.85e-12*T - 
          6.72e-15*T**2 + 8.56e-18*T**3), 
    electric_conductivity=lambda T, p: 1.0141 * T**2 * p 
) 

如果你想保持一個聲明風格,你也可以創建一個元類。


順便說

class Copper(): 
    def __init__(self): 
     self.magnetic_permeability = 1.0 
    ... 

可能不會做你想做什麼。這使得magnetic_permeability只能在copper實例中訪問。我不建議使用類,而不是實例或模塊爲這個,但如果你沒有,你需要做的

class Copper(object): 
    magnetic_permeability = 1.0 
    ... 

能夠做到Copper.magnetic_permeability


注意我繼承了對象,以便我們使用Python 2「新風格類」。這些變化是微妙的,但如果你確保你永遠不會遇到它們,那就更好了。

+0

感謝關於'object'的提示。我相應地修正了問題中的例子。 –

1

如何使變量屬性函數將所有必需的值作爲參數?

def density(T): 
    <some function of T> 

def electrical_conductivity(T, p): 
    <some function of T and p> 

def some_other_property(T, magnetic_permeability): 
    <some function of T and magnetic permeability> 

然後,固定的屬性可以通過字典來定義。

copper_fixed_properties = {'magnetic_permeability': 1, ...} 

你會以下列方式使用:

copper_some_other_property = some_other_property(T, copper.magnetic_permeability) 
4

我懷疑,更貼合的結構將有一個Material類,它需要是函數或係數作爲參數,例如

class Material(object): 

    def __init__(self, mag_perm, density_coeffs, ...): 
     self.mag_perm = mag_perm 
     self._density_coeffs = density_coeffs 
     ... 

    def density(self, T): 
     x0, x1, x2, x3 = self._density_coeffs 
     return 1.0/(x0 + (x1 * T) + (x2 * (T ** 2)) + (x3 * (T ** 3))) 

每種材料則提供它自己的係數計算出的各參數:

copper = Material(1.0, (-3.033e-9, 68.85e-12, 6.72e-15, 8.56e-18), ...) 
copper.density(300) 

如果您需要更復雜的關係(例如,不同的計算),你可以使用Material子類和過載的適當的計算。

+0

良好 - 在這個抽象中升級是適當的。 – wim

+0

當你將一個稱爲'density'的變量傳遞給'__init__'時(這實際上是一些在密度計算中使用的係數元組),有一種叫做'density'的方法,雖然是一種瘋狂的界面! – wim

+0

好點,我將重命名參數 – jonrsharpe

相關問題