从其他实例属性派生的类实例属性

     2023-02-23     54

关键词:

【中文标题】从其他实例属性派生的类实例属性【英文标题】:Class instance attributes derived from other instance attributes 【发布时间】:2020-03-28 14:11:39 【问题描述】:

如果标题含糊不清,我深表歉意,我想不出用一句话来描述我的问题。我正在 python2.7 中构建一些代码,如下所述。

最小的工作示例

我的代码有一个Parameter 类,它实现了namevalue 等属性,看起来像这样。

class Parameter(object):
    def __init__(self, name, value=None, error=None, dist=None, prior=None):
        self.name   = name
        self._value = value # given value for parameter, this is going to be changed very often in an MCMC sampler
        self.error  = error # initial estimate of error for the parameter, will only be set once
        self._dist  = dist # a distribution for the parameter, will only be set once
        self.prior  = prior

    @property
    def value(self):
        return self._value

    @property
    def dist(self):
        return self._dist

如果给定分布,该类还有几个属性可以返回Parameter.dist 的平均值、中位数等。

我还有一门课,例如ParameterSample,它创建了一组不同的 Parameter 对象。其中一些Parameter 对象的属性(例如valueerror)使用Parameter.set_parameter() 函数设置,但其他一些Parameter 对象没有显式设置,但它们的valuedist 属性依赖设置的其他一些Parameter对象:

class ParameterSample(object):
    def __init__(self):
        varied_parameters  = ('a', 'b') # parameter names whose `value` attribute is varied
        derived_parameters = ('c',) # parameter names whose `value` attribute is varied, but depends on `a.value` and `b.value`
        parameter_names    = varied_parameters + derived_parameters
        
        # create `Parameter` objects for each parameter name
        for name in parameter_names:
            setattr(self, name, Parameter(name))

    def set_parameter(self, name, **kwargs):
        for key, val in kwargs.items():
            if key == 'value':
                key = '_'.join(['', key]) # add underscore to set `Parameter._value`
            setattr(getattr(self, name), key, val) # basically does e.g. `self.a.value = 1`

我现在可以创建一个ParameterSample 并像这样使用它们:

parobj = ParameterSample()
parobj.set_parameter('a', value=1, error=0.1)
parobj.set_parameter('b', value=2, error=0.5)

parobj.a.value
>>> 1
parobj.b.error
>>> 0.5

parobj.set_parameter('b', value=3)
parobj.b.value
>>> 3
parobj.b.error
>>> 0.5

我想要什么

我最终想要的是以同样的方式使用Parameter.c。例如:

parobj.c.value
>>> 4 # returns parobj.a.value + parobj.b.value
parobj.c.dist
>>> None # returns a.dist + b.dist, but since they are not currently set it is None

c 因此需要是一个Parameter 对象,具有与ab 相同的属性,但是它的valuedist 根据a 的当前属性进行更新和b

但是,我还应该提到,我希望能够为参数 c 设置允许的先验范围,例如parobj.set_parameter('c', prior=(0,10)) 在对其值进行任何调用之前 -- 因此 c 需要在创建 ParameterSample 对象时是已定义的 Parameter 对象。

如何在我的 ParameterSample 类中实现这一点?

我尝试过的

我尝试过制作自己的装饰器,但我不确定这是否可行,因为我不完全了解如何使用它们。

我还考虑将@property 添加到c,每次调用它都会创建一个新的Parameter 对象,但我觉得这不是可行的方法,因为它可能会减慢代码速度。

我还应该注意,上面的ParameterSample 类将在不同的类中继承,所以无论解决方案是什么,它都应该能够在此设置中使用:

class Companion(ParameterSample)
    def __init__(self, name):
        self.name = name
        super(Companion, self).__init__()

comp = Companion(name='Earth')
comp.set_parameter('a', value=1)
comp.set_parameter('b', value=3)
comp.c.value
>>> 4

【问题讨论】:

仅作记录。你真的应该尽快切换到 python 3,因为 python 2 将不被支持。 @Error-SyntacticalRemorse 同意,但我必须稍后再做,因为我目前没有能力将我的代码移植到 python 3。 c 怎么知道引用ab?有什么d 如果有d怎么办?* 如果我理解你的问题,cParameterSample 的一个属性,与ab 相同,所以它的任何属性都可以在ParameterSample 中访问如self.a.value 等。 【参考方案1】:

我无法让它在 Python 2 中工作 - setattr 调用似乎从未将属性传播到子类(Companion 将没有 c 属性)。

不过,我使用 Python 3 更成功。由于您有两种参数类型(变量与派生),因此 IMO 有两个类来实现行为是有意义的,而不是将它们全部视为一个。

我添加了一个DerivedParameter 类,继承自Parameter,它采用dependents 参数(连同其父类的args/kwargs),但重新定义valuedist 以提供依赖行为:

class DerivedParameter(Parameter):
    def __init__(self, name, dependents, **kwargs):
        self._dependents = dependents
        super().__init__(name, **kwargs)

    @property
    def value(self):
        try:
            return sum(x._value for x in self._dependents if x is not None)
        except TypeError:
            return None

    @property
    def dist(self):
        try:
            return sum(x._dist for x in self._dependents if x is not None)
        except TypeError:
            return None

然后我调整了你的参数对象的添加方式:

class ParameterSample:
    def __init__(self):
        # Store as instance attributes to reference later
        self.varied_params  = ('a', 'b') # parameter names whose `value` attribute is varied
        self.derived_params = ('c',) # parameter names whose `value` attribute is varied, but depends on `a.value` and `b.value`
        # No more combined names

        # create `Parameter` objects for each varied parameter name
        for name in self.varied_params:
            setattr(self, name, Parameter(name))

        # Create `DerivedParameter` objects for each derived parameter
        # Derived parameters depend on all `Parameter` objects. It wasn't
        # clear if this was the desired behavior though.
        params = [v for _, v in self.__dict__.items() if isinstance(v, Parameter)]
        for name in self.derived_params:
            setattr(self, name, DerivedParameter(name, params))

    def set_parameter(self, name, **kwargs):
        for key, val in kwargs.items():
            if key == 'value':
                key = '_'.join(['', key]) # add underscore to set `Parameter._value`
            setattr(getattr(self, name), key, val) # basically does e.g. `self.a.value = 1`

据此,我可以复制您给定的示例所需的行为:

>>> comp = Companion(name='Earth')
>>> comp.set_parameter('a', value=1)
>>> comp.set_parameter('b', value=3)
>>> print(comp.c.value)
>>> print(comp.c.dist)
4
None
>>> comp.set_parameter('c', prior=(0,10))
>>> print(comp.c.prior)
(0, 10)

正如我在 cmets 中指出的那样,上述设计最终导致所有派生参数都使用 all 变化的参数作为它们的依赖项 - 有效地使 c 和潜在的 d 相同。您应该能够通过一些参数/条件相当轻松地解决此问题。

总的来说,我不得不同意@Error - 虽然语法上的悔恨。这是设计类的一种相当复杂的方法,并且最多会使维护变得混乱。我强烈建议您重新考虑您的设计,并尝试找到一个不涉及动态创建此类属性的适应性通用解决方案。

【讨论】:

引用泛型类型的类属性

...性在从抽象类继承的具体派生类中被覆盖。具体派生类与其他几个被类型注释为泛型的类一起使用,其中类型参数具有必须从抽象类派生的类型约束。我希望这些其他类(泛型)引用具体类的类属性(嵌套类型)。 查看详情

python中的类属性和实例属性

Python中的类属性和实例属性引发的一个坑-续简单理解:实例属性和类属性一开始保存的是同一个地址,当采用赋值时,实例属性指向的地址就发生了改变。 查看详情

拥有所有从同一个基类派生的类实例集合的最佳方法是啥?

】拥有所有从同一个基类派生的类实例集合的最佳方法是啥?【英文标题】:What\'sthebestwaytohaveacollectionofinstancesofclassesallderivedfromthesamebaseclass?拥有所有从同一个基类派生的类实例集合的最佳方法是什么?【发布时间】:2012-03-130... 查看详情

基于实例属性值的类属性类型保护

】基于实例属性值的类属性类型保护【英文标题】:Classpropertytypeguardbasedoninstancepropertyvalue【发布时间】:2021-10-0719:12:56【问题描述】:如何制作类示例以根据animalType实例值检查推断config类型:enumAnimalBIRD=\'bird\',DOG=\'dog\',typeBase=... 查看详情

如何在swift中使用其他属性将实例作为属性传递

】如何在swift中使用其他属性将实例作为属性传递【英文标题】:Howtopassaninstanceasapropertyusingotherpropertiesinswift【发布时间】:2020-06-1300:56:31【问题描述】:我是swift的新手,我正在尝试传递一个类(CP)的实例作为swiftUI的ContentView结... 查看详情

在 Python 中,为啥属性优先于实例属性?

...为数据描述符的类属性(最常见的是属性)实例属性任何其他类 查看详情

我可以根据抽象基类中定义的某个属性创建派生类的实例吗?

】我可以根据抽象基类中定义的某个属性创建派生类的实例吗?【英文标题】:CanIcreateaninstanceofaderivedclassbasedonacertainpropertydefinedinmyabstractbaseclass?【发布时间】:2019-03-1215:59:16【问题描述】:基本上我有一个抽象类,我们会说两... 查看详情

派生类的类/元类方法装饰器

...性,该属性对于每个子类应该是唯一的,但在每个子类的实例之间共享。classMetaValidator(type):def__new__(cls,name,bases,dct):new_cls=super()._ 查看详情

学习pytbon第十七篇,面向对象编程

...这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。继承:即一个派生类(derivedclass)继承基类(baseclass)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一... 查看详情

实现具有自动递增实例属性的类的最 Pythonic 方式是啥?

】实现具有自动递增实例属性的类的最Pythonic方式是啥?【英文标题】:WhatisthemostPythonicwayofimplementingclasseswithauto-incrementinginstanceattributes?实现具有自动递增实例属性的类的最Pythonic方式是什么?【发布时间】:2013-06-1815:40:11【问... 查看详情

从实例属性动态继承所有 Python 魔术方法

...alue属性下存储一个值。ValueContainer拥有自定义功能,保留其他元数 查看详情

设置 AVAudioPlayer 实例的委托

】设置AVAudioPlayer实例的委托【英文标题】:SettingTheDelegateofanAVAudioPlayerInstance【发布时间】:2012-03-1205:04:13【问题描述】:对不起,如果这是一个愚蠢的问题,但我在属性时遇到了一个问题。在我的程序中,我创建了4个AVAudioPlaye... 查看详情

依赖于类成员属性的类实例成员

】依赖于类成员属性的类实例成员【英文标题】:Classinstancememberthatdependsonclassmemberattribute【发布时间】:2020-05-1720:55:45【问题描述】:我的教师为我提供了一个代表二叉树的类,我们必须将它用于分配。所以我正在做一个名为cl... 查看详情

类属性实例属性

属性分为实例属性与类属性方法分为普通方法,类方法,静态方法一:属性:  尽量把需要用户传入的属性作为实例属性,而把同类都一样的属性作为类属性。实例属性在每创造一个类是都会初始化一遍,不同的实例的实例属... 查看详情

如何通过图访问作为图节点的类实例的属性?

】如何通过图访问作为图节点的类实例的属性?【英文标题】:Howtoaccessattributesofaclassinstancewhichisagraphnodeviathegraph?【发布时间】:2020-07-2403:13:31【问题描述】:类定义:classBlah:def__init__(self,x):self.x=xmain()的一部分:(导入的network... 查看详情

使用 @dataclass 创建的类中的 Python 实例属性分配

】使用@dataclass创建的类中的Python实例属性分配【英文标题】:Pythoninstanceattributeassignmentinclasscreatedusing@dataclass【发布时间】:2021-01-1302:40:14【问题描述】:我刚刚开始使用@dataclass装饰器。这是我没有数据类的实现classMyclass:def__in... 查看详情

基础知识回顾:属性

...属性可能来自类定义或类继承,这叫类属性,也可能来自实例对象的属性,这叫实例属性。不同实例的实例属性可能不同,不同实例的类属性都相同。所以一般把需要用户传入的属性作为实例属性,而把同类都一样的属性作为类... 查看详情

typescript派生类和抽象类

​派生类实例化派生类时,我们需要初始化基类的属性,然后调用基类的构造函数,再进行初始化派生类的属性,最后调用类派生类的构造函数。ts中的类仅仅支持单继承,extends只能指定一个基类,不支持多继承。当接口继承一... 查看详情