我正在尝试创建一个可迭代的python类来表示有线元素模型中的线段。我的算法采用LineSegment实例列表,然后构建数值模型。我希望能够遍历该类的原因是我可以使用PyQt QTableView来显示和修改LineSegment实例。到目前为止,这完美无缺。可以在QTableView中显示和修改所有内容。
但是,我最近的任务是处理物理单位(我使用了很棒的Pint库进行单元处理)。我想实现getter和setter来帮助解决这个问题。
我最初尝试使用属性,但发现它们未添加到__dict__
。然后我尝试了描述符,虽然可以将它们添加到__dict__
,但我发现在遍历类时,get和set方法被忽略。
我继承的基类如下。这创建了一个类似于Python字典的类。
from collections import MutableMapping
class DictLikeBaseClass(MutableMapping):
def __init__(self, *args, **kwargs):
self.__dict__.update(*args, **kwargs)
def __setitem__(self, key, value):
self.__dict__[key] = value
def __getitem__(self, key):
return self.__dict__[key]
def __delitem__(self, key):
del self.__dict__[key]
def __iter__(self):
return iter(self.__dict__)
def __len__(self):
return len(self.__dict__)
我的描述符类如下所示。
from pint import UnitRegistry
ur = UnitRegistry()
class LineProperty:
def __init__(self, name, unit):
self.name = name
self.unit = unit
self.value = None
def __set__(self, instance, value):
# DO STUFF
# Set a new value with the given unit
new_value = value * ur[self.unit]
print('setting {} to {}'.format(self.name, new_value))
instance.__dict__[self.name] = new_value
def __get__(self, instance, owner):
# DO STUFF
print('getting {}'.format(instance.__dict__[self.name]))
return instance.__dict__[self.name]
最后,我提供了一个非常简化的LineSegment类版本。
class LineSegment(DictLikeBaseClass):
unit_weight = LineProperty('unit_weight', 'pound/foot')
length = LineProperty('length', 'foot')
diameter = LineProperty('diameter', 'inch')
def __init__(self, unit_weight, length, diameter):
super().__init__()
self.unit_weight = unit_weight
self.length = length
self.diameter = diameter
如果通过点查找属性,则此方法有效。但是,如果迭代了属性,它们似乎直接从__dict__
抓取,并且忽略了描述符中的__get__
和__set__
方法。
用法:
>>> myLine = LineSegment(unit_weight=2, length=10, diameter=3.0)
setting unit_weight to 2.0 lb/ft
setting length to 10 ft
setting diameter to 3.0 in
通过点查找获取和设置属性,这意味着使用描述符中的__get__
和__set__
方法。
>>> myLine.length
getting length
<Quantity(10, 'foot')>
>>> myLine.length = 15
setting length to 15 ft
使用类似查找的dict获取和设置属性会忽略描述符中的__get__
和__set__
方法
>>> myLine['length'] = 20
>>> myLine['length']
20
因为迭代通过类也忽略了描述符中的__get__
和__set__
方法。由于QTableView需要可迭代类型,所以这一切都崩溃了。
>>> for k, v in myLine.items():
... print(k, v)
...
diameter 3.0 in
length 20
unit_weight 2.0 lb/ft
修改
寻找支持。我不认为我明确了QTableView / QTableModel如何遍历类来填充表格。
在QAbstractTableModel中,您必须实现一个方法,该方法基于具有列和行迭代器的索引对象返回值。所以填充表的方法看起来像这样。
def data(self, index):
keys = ['diameter', 'length', 'unit_weight']
return self._lineSegments[index.column()][keys[index.row()]]
其中_lineSegments
是LineSegment实例列表
以下是用于实验目的的方法的合适代理。
myLine = [LineSegment(unit_weight=2, length=10, diameter=3.0), LineSegment(unit_weight=5, length=15, diameter=2.0)]
keys = ['diameter', 'length', 'unit_weight']
for i, _ in enumerate(myLine):
for j, _ in enumerate(keys):
print(myLine[i][keys[j]])
我想我真正想要的是一种通过LineSegment类中的键查找来调用描述符中的getter和setter的方法,而不是点查找。我不确定这在Python中是否可行......