我在我的代碼中有難聞的氣味。也許我只需要讓它散發一點點,但現在它正在擾亂我。Python:結構化數據的習慣屬性?
我需要創建三個不同的輸入文件來運行三個輻射傳輸建模(RTM)應用程序,以便我可以比較它們的輸出。這個過程將重複數千組輸入,所以我使用python腳本自動化它。
我想將輸入參數存儲爲一個通用python對象,我可以將其傳遞給另外三個函數,每個函數都會將該通用對象轉換爲運行他們負責的RTM軟件所需的特定參數。我認爲這是有道理的,但隨時可以批評我的方法。
每個RTM軟件都有許多可能的輸入參數。其中許多重疊。他們中的大多數都保持合理的默認值,但應該很容易改變。
我開始用一個簡單的dict
config = {
day_of_year: 138,
time_of_day: 36000, #seconds
solar_azimuth_angle: 73, #degrees
solar_zenith_angle: 17, #degrees
...
}
有很多的參數,並且它們可以清晰地分爲組,所以我想用dict
內dict
S的:
config = {
day_of_year: 138,
time_of_day: 36000, #seconds
solar: {
azimuth_angle: 73, #degrees
zenith_angle: 17, #degrees
...
},
...
}
我喜歡那樣。但是有很多冗餘屬性。例如,如果另一個是已知的,可以找到太陽的方位角和天頂角,那麼爲什麼要硬編碼呢?所以我開始研究python的內置版本property
。這讓我做時髦的東西與數據,如果我保存它作爲對象屬性:
class Configuration(object):
day_of_year = 138,
time_of_day = 36000, #seconds
solar_azimuth_angle = 73, #degrees
@property
def solar_zenith_angle(self):
return 90 - self.solar_azimuth_angle
...
config = Configuration()
但現在我已經失去了我的結構從第二dict
例子了。
請注意,某些屬性不如我的solar_zenith_angle
示例微不足道,並且可能需要訪問屬於該屬性組之外的其他屬性。例如,如果我知道一年中的某一天,一天中的時間,緯度和經度,我可以計算solar_azimuth_angle
。
我正在尋找:
一個簡單的方法來存儲其值都可以用統一的方式進行訪問,是很好的結構,並可能存在無論是作爲屬性(實際值)或配置數據屬性(從其他屬性計算)。
這是一種無聊的一種可能性:
存儲所有類型的字典的字典我前面所述,以及具有其它功能碾過物體,並計算可計算的價值?這聽起來不好玩。或乾淨。對我來說,這聽起來很混亂和令人沮喪。
難看的作品:
後很長一段時間嘗試不同的策略,且大多沒有得到哪裏,我想出了,似乎工作一個可能的解決方案:
我的班: (聞起來有點FUNC-Y,呃,質樸DEF-initely。)
class SubConfig(object):
"""
Store logical groupings of object attributes and properties.
The parent object must be passed to the constructor so that we can still
access the parent object's other attributes and properties. Useful if we
want to use them to compute a property in here.
"""
def __init__(self, parent, *args, **kwargs):
super(SubConfig, self).__init__(*args, **kwargs)
self.parent = parent
class Configuration(object):
"""
Some object which holds many attributes and properties.
Related configurations settings are grouped in SubConfig objects.
"""
def __init__(self, *args, **kwargs):
super(Configuration, self).__init__(*args, **kwargs)
self.root_config = 2
class _AConfigGroup(SubConfig):
sub_config = 3
@property
def sub_property(self):
return self.sub_config * self.parent.root_config
self.group = _AConfigGroup(self) # Stinky?!
如何可以使用它們:(作品因爲我想)
config = Configuration()
# Inspect the state of the attributes and properties.
print("\nInitial configuration state:")
print("config.rootconfig: %s" % config.root_config)
print("config.group.sub_config: %s" % config.group.sub_config)
print("config.group.sub_property: %s (calculated)" % config.group.sub_property)
# Inspect whether the properties compute the correct value after we alter
# some attributes.
config.root_config = 4
config.group.sub_config = 5
print("\nState after modifications:")
print("config.rootconfig: %s" % config.root_config)
print("config.group.sub_config: %s" % config.group.sub_config)
print("config.group.sub_property: %s (calculated)" % config.group.sub_property)
行爲:(以上所有代碼的執行的輸出,如預期)
Initial configuration state:
config.rootconfig: 2
config.group.sub_config: 3
config.group.sub_property: 6 (calculated)
State after modifications:
config.rootconfig: 4
config.group.sub_config: 5
config.group.sub_property: 20 (calculated)
爲什麼我不喜歡它:
將配置數據存儲在主對象__init__()
內部的類定義中並不舒服。尤其是在像這樣定義之後立即實例化它們。啊。我可以對父類進行處理,但可以在構造函數中處理...
在主對象Configuration
之外存儲相同的類也不會覺得優雅,因爲內部類中的屬性可能取決於Configuration
(或其內部的兄弟姐妹)的屬性。
我可以處理定義功能所需的一切之外,所以有裏面的東西一樣
@property
def solar_zenith_angle(self):
return calculate_zenith(self.solar_azimuth_angle)
,但我無法弄清楚如何做類似
@property
def solar.zenith_angle(self):
return calculate_zenith(self.solar.azimuth_angle)
(當我嘗試要聰明一點,我總是碰到<property object at 0xXXXXX>
)
那麼對此有什麼正確的方法呢?我錯過了一些基本的東西,或者採取了非常錯誤的方法?有誰知道一個聰明的解決方案?
幫助!我的Python代碼並不漂亮!我一定做錯了什麼!
我有種感覺,我可能不得不深入探索一些這些神奇的方法。我打算玩一下你的代碼建議,但乍看起來我很擔心'property(lambda ...'。我的一些屬性計算不適合'lambda',這就是我開始嘗試運行'def self.group.a():',雖然我現在有一些新的想法,但是謝謝! – Phil
@Phil然後嘗試元類方法,它不需要你使用lambda – LaC