【问题标题】:Python: add attribute to instance, have it appear in classPython:向实例添加属性,让它出现在类中
【发布时间】:2019-02-08 22:40:52
【问题描述】:

为了在 Python 中创建与 Matlab 的结构等效的东西,我想创建一个类,该类的设计使得当它的实例被赋予一个整个类还没有的新属性时,该类被自动声明为具有该名称的属性(但动态值)。

例如,如果我以这种方式定义了 color 类,但没有开始的属性,那么我可以执行以下操作:

>> red = color()
>> blue = color()
>> blue.temperature
   AttributeError: type object 'color' has no attribute 'temperature'
>> red.temperature = 'hot'
>> blue.temperature
   blue.temperature = ''
>> blue.temperature = 'cool'

有没有办法破解添加另一个属性的过程并向其添加类似cls.x = '' 的命令,其中x 是添加到实例的属性名称的变量?

【问题讨论】:

  • 实例属性和类属性是两个不同的东西。
  • 不要尝试。它不适合 python oop 模型。
  • @juanpa.arrivillaga,我误读了这个问题。他想模拟 MATLAB structscipy.io.loadmatstruct 转换为 numpy 结构化/记录数组,其中 dtype 字段对应于 MATLAB 中的每个属性(或字段)。在 MATLAB 中,只需为一条记录定义一个值,即可为所有“记录”添加一个属性。
  • 您可以将struct 建模为一个字典列表,然后编写一小组实用函数来确保当一个键被添加到列表中的一个字典时,该键将一些默认值添加到所有其他字典中。一旦这些工作令您满意,您可以将其打包为 Python 类。
  • 可以在进行过程中向类添加方法和类变量。但是实例变量保存在自己的 .__dict__ 字典中,不与类或其他实例共享。

标签: python python-3.x class attributes


【解决方案1】:

setattr 方法

x = "temperature"
setattr(red,x,"HOT")

我想这就是你想要的

但也许您想要重载颜色类的 __setattr____getattr__ 方法

class color:
     attrs = {}
     def __getattr__(self,item):
         if item in self.attrs:
            return self.attrs[item]
         return ""
     def __setattr__(self,attr,value):
         self.attrs[attr] = value

c = color()
print(repr(c.hello))
c.hello = 5
print(repr(c.hello))
print(repr(c.temperature))
x = 'temperature'
setattr(c,x,"HOT")
print(repr(c.temperature))

【讨论】:

  • 这确实为所有实例提供了新属性,但我希望有一个像 1 这样的事件序列。为之前在类中不存在的属性分配一个值,对于单个该类的实例 2. 为整个类创建该属性,使用默认值 3. 将该属性设置为所处理实例的指定值
  • 我修改了代码,使得有两个字典,clsAttrs(和你的attrs一样,属于类)和insAttrs(属于实例)。但是现在 getattr 需要检查实例属性字典中是否有东西,如果不调用自身 getattr,这似乎是不可能的。我在网上搜索,找到了getattribute,但这似乎没有什么区别。我应该开始另一个问题吗?
【解决方案2】:

以 Octave https://octave.org/doc/v4.4.1/Structure-Arrays.html 为例

制作结构数组:

>> x(1).a = "string1";
>> x(2).a = "string2";
>> x(1).b = 1;
>> x(2).b = 2;
>>
>> x
x =

  1x2 struct array containing the fields:

    a
    b

如果我将一个字段添加到一个条目,则会为另一个条目添加或定义一个默认值:

>> x(1).c = 'red'
x =

  1x2 struct array containing the fields:

    a
    b
    c

>> x(2)
ans =

  scalar structure containing the fields:

    a = string2
    b =  2
    c = [](0x0)

>> save -7 struct1.mat x

在 numpy 中

In [549]: dat = io.loadmat('struct1.mat')
In [550]: dat
Out[550]: 
{'__header__': b'MATLAB 5.0 MAT-file, written by Octave 4.2.2, 2019-02-09 18:42:35 UTC',
 '__version__': '1.0',
 '__globals__': [],
 'x': ...

In [551]: dat['x']
Out[551]: 
array([[(array(['string1'], dtype='<U7'), array([[1.]]), array(['red'], dtype='<U3')),
        (array(['string2'], dtype='<U7'), array([[2.]]), array([], shape=(0, 0), dtype=float64))]],
      dtype=[('a', 'O'), ('b', 'O'), ('c', 'O')])
In [552]: _.shape
Out[552]: (1, 2)

该结构已被转换为结构化的 numpy 数组,其 shape 与 Octave size(x) 相同。每个 struct 字段都是dat 中的一个对象 dtype 字段。

与 Octave/MATLAB 相比,我们无法就地向 dat['x'] 添加字段。我认为import numpy.lib.recfunctions as rf 中有一个函数可以添加一个字段,具有各种形式的屏蔽或未定义值的默认值,但这将创建一个新数组。通过一些工作,我可以从头开始。

In [560]: x1 = rf.append_fields(x, 'd', [10.0])
In [561]: x1
Out[561]: 
masked_array(data=[(array(['string1'], dtype='<U7'), array([[1.]]), array(['red'], dtype='<U3'), 10.0),
                   (array(['string2'], dtype='<U7'), array([[2.]]), array([], shape=(0, 0), dtype=float64), --)],
             mask=[(False, False, False, False),
                   (False, False, False,  True)],
       fill_value=('?', '?', '?', 1.e+20),
            dtype=[('a', 'O'), ('b', 'O'), ('c', 'O'), ('d', '<f8')])
In [562]: x1['d']
Out[562]: 
masked_array(data=[10.0, --],
             mask=[False,  True],
       fill_value=1e+20)

这种动作不太适合 Python 类系统。一个类通常不会跟踪它的实例。并且一旦定义一个类通常不会被修改。可以维护一个实例列表,也可以向现有类添加方法,但这不是常见的做法。

【讨论】:

    猜你喜欢
    • 2016-01-02
    • 2015-02-22
    • 2023-03-14
    • 2021-07-26
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 2011-11-24
    相关资源
    最近更新 更多