【问题标题】:How to switch between two sets of attribute values, depending on an internal state?如何根据内部状态在两组属性值之间切换?
【发布时间】:2021-04-07 09:30:56
【问题描述】:

我有一个班级持有一些科学数据。根据内部状态,此类的值可以显示为规范化(即无单位)或非规范化。这些值始终按规范化存储,但如果对象设置为非规范化状态,用户可访问的属性(和方法)将给出非规范化值。这样类就显示为非规范化,而无需复制存储的值。

现在我使用 getter 实现了这一点。虽然它有效,但它提供了很多重复结构,我想知道是否有一种更 Pythonic 的方式来管理它而不会使事情过于复杂。

我这样做对吗?有没有更优雅的方式以相似的方式在两组数据之间切换?

class CoolPhysicsData(object):
    def __init__(self, lambda0, *args, normed=False):
        self.lambda0 = lambda0     # some normalization factor (wavelength of some wave)
        self.normalized = normed      # user can change this state as he pleases
        self._normed_tmin, self._normed_tmax, self._normed_r = self.calculate_stuffs(*args)
        ...

    @property
    def tmin(self):
        if self.normalized:
            return self._normed_tmin
        else:
            return denormalize(self.lambda0, self._normed_tmin, unit_type="time")

    @property
    def tmax(self):
        if self.normalized:
            return self._normed_tmax
        else:
            return denormalize(self.lambda0, self._normed_tmax, unit_type="time")

    @property
    def r(self):
        if self.normalized:
            return self._normed_r
        else:
            return denormalize(self.lambda0, self._normed_r, unit_type="len")

    ...  # about 15 getters alike these

【问题讨论】:

    标签: python-3.x class properties state getter


    【解决方案1】:

    一种方法是避免使用属性,并实现__getattr____setattr____delattr__。由于您需要知道要反规范化的数量,因此实际上无法逃避定义:这些必须在某处手动编码。我会这样做:

    class CoolPhysicsData:
        def _get_normalization_params(self, value):
            # set up how individual properties should be denormalized..
            params = {
                # 'property_name' : (norm_factor, norm_value, 'unit_type')
                'tmin': (self.lambda0, self._normed_tmin, 'time'),
                'tmax': (self.lambda0,  self._normed_tmax, 'time'),
                'r': (self.lambda0, self._normed_r, 'len'),
            }
            return params[value]
    

    我会像这样实现__getattr__

    ...
        def __getattr__(self, value):
            # extract the parameters needed
            norm_factor, normed_value, unit_type = self._get_normalization_params(f'{value}')
            if self.normed:
                return normed_value
            else:
                return self.denormalize(norm_factor, normed_value, unit_type)
    ...
    

    请注意,您可能还想写 __setattr____delattr__


    一点补充:dataclasses 可能对您有用。我不确定您的 __init__ 函数中的 *args 是否是确切的签名,或者您只是为了示例而简化了。如果您知道参数(没有可变参数),则可以轻松地将其转换为 dataclass

    from dataclasses import dataclass, field
    
    @dataclass
    class CoolPhysicsData:
        lambda0: float
        normed: bool = field(default=False)
        
        def __post_init__(self):
            # set up some test values for simplicity
            # of course you can run custom calculations here..
            self._normed_tmin = 1
            self._normed_tmax = 2
            self._normed_r = 3
    
        def __getattr__(self, value):
            norm_factor, normed_value, unit_type = self._get_normalization_params(f'{value}')
            if self.normed:
                return normed_value
            else:
                return self.denormalize(norm_factor, normed_value, unit_type)
    
    #     you may want to implement the following methods too:
    
    #     def __setattr__(self, name, value):
    #         # your custom logic here
    #         ...
            
    #     def __delattr__(self, name):
    #         # your custom logic here
    #         ...
      
        def denormalize(self, v1, v2, v3):
            # just for simplicity
            return 5
            
        def _get_normalization_params(self, value):
            # setup how individual properties should be denormalized..
            params = {
                # 'property_name' : (norm_factor, norm_value, 'unit_type')
                'tmin': (self.lambda0, self._normed_tmin, 'time'),
                'tmax': (self.lambda0,  self._normed_tmax, 'time'),
                'r': (self.lambda0, self._normed_r, 'len'),
            }
            return params[value]
    

    它更pythonic吗?由您决定。它肯定会消除一些重复,但你会引入更多的复杂性,而且 - 在我看来 - 它更容易出现错误。

    【讨论】:

    • 很好的答案!对我来说效果不佳,因为实际的课程要复杂得多 - 但这是解决我在问题中提出的问题的好方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 2021-09-13
    • 1970-01-01
    • 2023-03-17
    • 2016-10-13
    • 2019-12-07
    • 1970-01-01
    相关资源
    最近更新 更多