In pursuit of creating something equivalent to the struct of Matlab in Python, I want to create a class that is designed so that when an instance of it is given a new attribute that the class as a whole doesn't yet have, the class is automatically declared to have an attribute of that name (but dynamic value).
For example, if I have defined the class color
in this manner, but having no attributes to start with, then I could do the following:
>> red = color()
>> blue = color()
>> blue.temperature
AttributeError: type object 'color' has no attribute 'temperature'
>> red.temperature = 'hot'
>> blue.temperature
blue.temperature = ''
>> blue.temperature = 'cool'
Is there a way to hack the process of adding another attribute and add to it a command like cls.x = ''
, with x
being a variable for the name of the attribute added to the instance?
the setattr
method
x = "temperature"
setattr(red,x,"HOT")
I think is what you are asking for
but maybe what you want is to overload the __setattr__
and __getattr__
methods of your color class
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))
To take an example from Octave https://octave.org/doc/v4.4.1/Structure-Arrays.html
Make a structure array:
>> 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
If I add a field to one entry, a default value is added or defined for the other:
>> 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
In 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)
The struct has been translated into a structured numpy array, with the same shape
as the Octave size(x)
. Each struct field is an object dtype field in dat
.
In contrast to Octave/MATLAB we can't add a field to dat['x']
in-place. I think there's a function in import numpy.lib.recfunctions as rf
that can add a field, with various forms of masking or default for undefined values, but that will make a new array. With some work I could do that from scratch.
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)
This kind of action does not fit the Python class system well. A class doesn't normally keep track of its instances. And once defined a class is not normally amended. It is possible to maintain a list of instances, and it is possible to add methods to an existing class, but that's not common practice.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.