簡體   English   中英

首次調用時計算可選實例變量的 Pythonic 方式

[英]Pythonic way of computing optional instance variables when first called

我正在編寫一個 class 來表示來自航天器的一些數據,這些數據可以提供許多不同的數據產品,可用於計算其他變量。 加載每個變量的原始數據需要幾秒鍾的時間,因此每個變量只應在需要時加載,因為並非總是需要所有變量。

這是我的意思的最小工作示例:

class Spacecraft:
    def __init__(self, time_range, configuration='default'):
        self.time_range = time_range

        # Initialise all possible variables to None
        self.magnetometer = None
        self.temperature = None
        self.complicated_thing = None
        # There are 30+ of these

    def get_magnetometer(self):
        self.magnetometer = self.load_data('magnetometer')
        return self.magnetometer

    def get_temperature(self):
        self.temperature = self.load_data('temperature')
        return self.temperature

    def get_complicated_thing(self):
        # Check each variable has a value
        if self.temperature is None:
            get_temperature()
        if self.magnetometer is None:
            get_magnetometer()
        
        self.complicated_thing = self.temperature * self.magnetometer
        return self.complicated_thing


    # Plus more get_ functions for each instance variable

    def load_data(self, product_name):
        """Loads raw 'product_name' data as np array.
        """
        pass


# Use case 1: Only need limited number of parameters
only_need_magnetometer = Spacecraft('10:30-10:45')
plot(only_need_magnetometer.get_magnetometer())


# Use case 2: Need a different set of parameters
complicated_analysis = Spacecraft('10:45-11:00')
result = analysis(complicated_analysis.get_complicated_thing())

我不確定在__init__()中將每個變量初始化為None 我也不喜歡計算派生變量的每個 function 開頭的冗長檢查。

有更好/更蟒蛇的方式嗎?

理想情況下,我想跳過初始化為None並能夠將get_complicated_thing()定義為:

def get_complicated_thing(self):
    self.complicated_thing = self.temperature * self.magnetometer
    return self.complicated_thing

如果self.temperatureself.magnetometer尚不存在,則會自動調用 getter,例如get_magnetometer() 然后可以將用例簡化為:

# Use case 1: Only need limited number of parameters
only_need_magnetometer = Spacecraft('10:30-10:45')
plot(only_need_magnetometer.magnetometer)


# Use case 2: Need a different set of parameters
complicated_analysis = Spacecraft('10:45-11:00')
result = analysis(complicated_analysis.complicated_thing)

至少對我來說,這更容易閱讀。

確實有一個可以使用的構造:property 有一些裝飾器允許為托管屬性定義getterssetters和“析構函數”:

在您的情況下,您只需要吸氣劑:

class MyClass:
    def __init__(self, *args, **kwargs):
        # do stuff

    @property
    def magnometer(self):
        # do heavy calculation/loading
        return result


    @property
    def complicated_thing(self):
        # we can access self.mangometer here (it will just run the magnometer bound function)
        return self.magnometer*2

現在您說計算/加載操作很繁重。 可以很容易地緩存您的計算值,如下所示:

from functools import cache
...
    @property
    @cache
    def myproperty(self):
        return 42
...

但是請注意, cache是在 3.9 中引入的,在 Python 3.8 中有一個cached_property ,您可以將其用作鏈式裝飾器的替代品。 或者,您可以按照該線程的內容編寫自己的緩存。

附加說明:在__init__中將屬性設置為None原則上沒有任何問題。

暫無
暫無

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

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