Python 使用描述符协议更改基础数据表示
假设我有一个现有的类,例如做一些数学方面的事情:Python 使用描述符协议更改基础数据表示,python,Python,假设我有一个现有的类,例如做一些数学方面的事情: class Vector: def __init__(self, x, y): self.x = y self.y = y def norm(self): return math.sqrt(math.pow(self.x, 2) + math.pow(self.y, 2)) 现在,出于某种原因,我希望Python不像任何变量那样存储成员x和y。我更希望Python在内部将它们存
class Vector:
def __init__(self, x, y):
self.x = y
self.y = y
def norm(self):
return math.sqrt(math.pow(self.x, 2) + math.pow(self.y, 2))
现在,出于某种原因,我希望Python不像任何变量那样存储成员x
和y
。我更希望Python在内部将它们存储为字符串。或者它将它们存储到一个专用的缓冲区中,可能是为了与某些C代码的互操作性。因此(对于字符串情况),我构建了以下描述符:
我将现有的vector类包装在一个新类中,其中成员x
和y
变成MyStringMemory
:
class StringVector(Vector):
def __init__(self, x, y):
self.x = x
self.y = y
x = MyStringMemory(float)
y = MyStringMemory(float)
最后,一些驱动代码:
v = StringVector(1, 2)
print(v.norm())
v.x, v.y = 10, 20
print(v.norm())
毕竟,我将x
和y
的内部表示替换为字符串,而没有对原始类进行任何更改,但仍然具有其全部功能
我只是想知道:这个概念会普遍适用吗?还是我会遇到严重的陷阱?正如我所说,主要思想是将数据存储到一个特定的缓冲区位置,稍后由C代码访问
编辑:我的意图如下。目前,我有一个运行良好的程序,其中一些物理对象,所有类型都是
MyPhysicalObj
相互交互。对象中的代码使用Numpy进行矢量化。现在我还想在所有对象上矢量化一些代码。例如,每个对象都有一个能量
,该能量由每个对象的复杂矢量化代码计算。现在我想总结一下所有的能量。我可以迭代所有对象并求和,但这太慢了。因此,我更希望将每个对象的属性能量
自动存储到全局预定义的缓冲区中,我可以在该缓冲区上使用numpy.sum
。如果您像以前一样需要通用转换器(“convert”),这是一种方法
当您需要创建大量实例时,最大的缺点将是性能(我假设您可能会这样做,因为类名为Vector
)。这将很慢,因为python类启动很慢
在这种情况下,您可以考虑使用,您可以看到文档具有与您类似的场景。
作为旁注:如果可能的话,为什么不在init方法上创建一个以x和y为字符串表示的dict呢?然后继续使用x和y作为普通变量,而不进行所有转换关于python描述符有一个陷阱 使用代码,您将引用分别存储在StringVector.x.prop和StringVector.y.prop中的相同值:
v1 = StringVector(1, 2)
print('current StringVector "x": ', StringVector.__dict__['x'].prop)
v2 = StringVector(3, 4)
print('current StringVector "x": ', StringVector.__dict__['x'].prop)
print(v1.x)
print(v2.x)
将具有以下输出:
Write
Write
current StringVector "x": 1
Write
Write
current StringVector "x": 3
Read
3.0
Read
3.0
我想这不是你想要的。要在对象内部存储每个对象的唯一值,请进行以下更改:
class MyNewStringMemory(object):
def __init__(self, convert, name):
self.convert = convert
self.name = '_' + name
def __get__(self, obj, objtype):
print('Read')
return self.convert(getattr(obj, self.name))
def __set__(self, obj, val):
print('Write')
setattr(obj, self.name, str(val))
def __delete__(self, obj):
print('Delete')
class StringVector(Vector):
def __init__(self, x, y):
self.x = x
self.y = y
x = MyNewStringMemory(float, 'x')
y = MyNewStringMemory(float, 'y')
v1 = StringVector(1, 2)
v2 = StringVector(3, 4)
print(v1.x, type(v1.x))
print(v1._x, type(v1._x))
print(v2.x, type(v2.x))
print(v2._x, type(v2._x))
输出:
Write
Write
Write
Write
Read
Read
1.0 <class 'float'>
1 <class 'str'>
Read
Read
3.0 <class 'float'>
3 <class 'str'>
写入
写
写
写
阅读
阅读
1
1.
阅读
阅读
3
3.
此外,您肯定可以使用描述符的\uuuuu set\uuu
方法将数据保存在集中式存储中
请参阅本文档:如果您希望与C代码实现互操作性,请查看Numpy和Cython。您可以通过cython向C/C++发送Numpy缓冲区。我不会把数字转换成字符串,这是一个非常不完善的表示法。哦,太感谢了,我没想到。。。所以在一般的OOP术语中,描述符是类的静态成员?是的。同样在Python中,它们不是静态的(=),可以添加到类中,并在运行时与它们的子对象一起使用。
Write
Write
Write
Write
Read
Read
1.0 <class 'float'>
1 <class 'str'>
Read
Read
3.0 <class 'float'>
3 <class 'str'>