任何人都可以告诉我为什么当我按下测试按钮时,__get__
没有被调用?我尝试了很多东西,但我无法达到预期的行为:
当访问
lt
或gt
属性时,如果选中复选框,则必须返回相应QlineEdit
的值
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QVBoxLayout, QRadioButton, QGroupBox, QLineEdit, QCheckBox, QGridLayout, QLabel, QFrame, QPushButton
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIntValidator
from PyQt5.QtWidgets import QMainWindow
class LineDescriptor:
def __init__(self, row=1, label=None):
self.label = label
self.row = row
self.__name = None
def __get__(self, instance, owner=None):
print('get_called')
if instance is None:
print('is none')
return self
else:
private_name = '_{0}__{1}'.format(type(instance).__name__,
self.__name)
check_name = '_{0}__{1}'.format(type(instance).__name__,
self.__name)
if getattr(instance, check_name).isChecked():
return getattr(instance, private_name).text()
else:
return None
class CheckSelector(QGroupBox):
def __init__(self, name):
self.__dictionary = []
super(CheckSelector, self).__init__()
layout = QGridLayout()
layout.setAlignment(Qt.AlignTop)
name = QLabel(name)
layout.addWidget(name, 0, 0, 1, 1)
self.__check = QCheckBox()
layout.addWidget(self.__check, 0, 1, 1, 1)
self.setLayout(layout)
for name, attribute in type(self).__dict__.items():
if isinstance(attribute, LineDescriptor):
row = attribute.row
if attribute.label is not None:
label = QLabel(attribute.label)
self.layout().addWidget(label, row, 0, 1, 1)
int_validator = QIntValidator()
field = QLineEdit()
field.setValidator(int_validator)
layout.addWidget(field, row, 1, 1, 1)
private_name = '_{0}__{1}'.format(type(self).__name__, name)
setattr(attribute, '_LineDescriptor__name', name)
setattr(self, name, attribute)
setattr(self, private_name, field)
print(attribute)
print(attribute.__dict__)
class GtCheck(CheckSelector):
gt = LineDescriptor(1, '>')
class BothCheck(CheckSelector):
gt = LineDescriptor(1, '>')
lt = LineDescriptor(2, '<')
def checker():
print(test.lt)
app = QApplication(sys.argv)
win = QMainWindow()
wid = QFrame()
lay = QVBoxLayout()
test = BothCheck(name='слов')
lay.addWidget(test)
but = QPushButton()
but.clicked.connect(checker)
lay.addWidget(but)
wid.setLayout(lay)
win.setCentralWidget(wid)
win.show()
sys.exit(app.exec_())
答案 0 :(得分:0)
这是违规行:
setattr(self, name, attribute)
您的描述符是非数据描述符(它不实现__set__()
)。因此,这会在self.__dict__
中设置属性,从而创建实例属性。实例属性优先于非数据描述符。如果您在下一行立即执行此操作:
getattr(self, name)
...然后不会调用描述符;它只会从attribute
中取回self.__dict__
并直接返回。由于foo.bar
与getattr(foo, "bar")
完全相同,因此foo.bar
语法也不会调用描述符。
数据描述符(实现__set__()
的描述符)优先于实例属性。如果您更改LineDescriptor
以实施__set__()
以及__get__()
,则不会出现此行为。但是你必须弄清楚如何实现__set__()
。该实现将取决于您要完成的任务:
AttributeError
以指示描述符是只读的。然后你必须删除setattr()
调用,因为你不能设置只读描述符。__set__()
来执行与__get__()
相反的操作。鉴于__get__()
方法的复杂性,我不完全确定如何做到这一点。它还会改变setattr()
来电的效果。如果您不想更改或删除setattr()
电话,您可以随时手动设置实例属性:
self.__dict__[name] = attribute
这会绕过数据描述符,并完全执行setattr()
调用当前正在执行的操作。但是,该属性可能与__get__()
的返回值不匹配。在我看来,这是糟糕的设计,但并不严格错误。