使用描述符/属性

时间:2017-06-06 16:35:38

标签: python pyqt pyqt5

我正在尝试创建一个可迭代的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
  1. 有没有办法在Python中使用getter和setter创建一个可迭代的类?
  2. 我是否正在尝试做“unpythonic&#39;
  3. ”的事情

    -----------------

    修改

    寻找支持。我不认为我明确了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中是否可行......

0 个答案:

没有答案
相关问题