首次调用时计算可选实例变量的 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
。我也不喜欢每个计算派生变量的函数开头的冗长检查。
是否有 better/more pythonic 方式?
理想情况下,我想跳过 None
的初始化并能够将 get_complicated_thing()
定义为:
def get_complicated_thing(self):
self.complicated_thing = self.temperature * self.magnetometer
return self.complicated_thing
其中,如果 self.temperature
或 self.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
。有些装饰器允许为 托管属性 :
定义 getters
、setters
和“析构函数”
在你的情况下,你只需要吸气剂:
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
现在你说calculations/loading操作繁重。可以很容易地缓存您的计算值,如下所示:
from functools import cache
...
@property
@cache
def myproperty(self):
return 42
...
但是请注意,cache
是在 3.9 中引入的,Python 3.8 中有一个 cached_property
,您可以将其用作链接装饰器的替代项。或者,您可以按照 this thread.
的方式编写自己的缓存
补充说明:在__init__
中将属性设置为None
原则上没有错。
我正在写一个 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
。我也不喜欢每个计算派生变量的函数开头的冗长检查。
是否有 better/more pythonic 方式?
理想情况下,我想跳过 None
的初始化并能够将 get_complicated_thing()
定义为:
def get_complicated_thing(self):
self.complicated_thing = self.temperature * self.magnetometer
return self.complicated_thing
其中,如果 self.temperature
或 self.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
。有些装饰器允许为 托管属性 :
getters
、setters
和“析构函数”
在你的情况下,你只需要吸气剂:
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
现在你说calculations/loading操作繁重。可以很容易地缓存您的计算值,如下所示:
from functools import cache
...
@property
@cache
def myproperty(self):
return 42
...
但是请注意,cache
是在 3.9 中引入的,Python 3.8 中有一个 cached_property
,您可以将其用作链接装饰器的替代项。或者,您可以按照 this thread.
补充说明:在__init__
中将属性设置为None
原则上没有错。