Python 从_init中的列表/属性在类中创建属性__

Python 从_init中的列表/属性在类中创建属性__,python,properties,setter,getter,setattribute,Python,Properties,Setter,Getter,Setattribute,我有一个硬件,我写了一个类,它有多个输入。每个输入(通道)都有一个名称,因此我创建了一个列表: CHANNELS = {"T0": 0, "Tend": 1, "A": 2, "B": 3, "C" : 4, "D" : 5, "E" : 6, "F" : 7, "G" : 8, "H" : 9} 现在,我想创建一个属性来访问每个通道的值: @property def readT0(self) return self._query("REQUEST STRING 0")

我有一个硬件,我写了一个类,它有多个输入。每个输入(通道)都有一个名称,因此我创建了一个列表:

CHANNELS = {"T0": 0, "Tend": 1, "A": 2, "B": 3, "C" : 4, "D" : 5,
    "E" : 6, "F" : 7, "G" : 8, "H" : 9}
现在,我想创建一个属性来访问每个通道的值:

@property
def readT0(self)
    return self._query("REQUEST STRING 0")
    # the request string expects a number, instead of the real name T0

@property
def readTend(self)
    return self._query("REQUEST STRING 1")
等等

我宁愿做这样的事情(少一些源代码):

并使用某种转换来创建属性:

def __init__ bla bla:
    bla bla

    for x in CHANNELS:
        setattr(self, "read" + str(x), self.read(CHANNELS[x])
所以

这样,如果硬件使用更多通道,我可以添加到
通道
字典中。还是有更好的办法

因为我只想读取值,所以就到此为止。但是,有没有一种方法可以将这与二传手结合起来呢

编辑:

我必须澄清:我不想在运行时更改字典或访问字典的值,我想在创建类时使用字典为硬件创建多个属性来读取硬件值

硬件是带通道的ADC。我可以读取每个通道的ADC值

someclass._query("REQUEST STRING i")
# i is the channel number and returns the ADC value (e.g. 10.45 V)
我想这就是你想要的:

class Something(object):

    CHANNELS = {"T0": 0, "Tend": 1, "A": 2, "B": 3, "C": 4, "D": 5,
                "E": 6, "F": 7, "G": 8, "H": 9}

    def __getattr__(self, name):
        """Handle missing attributes."""
        if name.startswith('read') and name[4:] in self.CHANNELS:
            return self.CHANNELS[name[4:]]
        return super(Something, self).__getattribute__(name)
使用中:

>>> thing = Something()
>>> thing.readA
2
>>> thing.readT0
0
>>> thing.garbage
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'Something' object has no attribute 'garbage'
>>thing=Something()
>>>读物
2.
>>>读
0
>>>垃圾
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第8行,在__
AttributeError:“某物”对象没有“垃圾”属性

然后,您可以根据需要在对
\u查询的调用中使用这些频道属性。如果您也希望分配给字典,则需要实现。

如果您确实希望动态创建函数并使其成为类实例的成员,则可以使用
lambda

CHANNELS = {"T0": 0, "Tend": 1, "A": 2, "B": 3, "C" : 4, "D" : 5,
    "E" : 6, "F" : 7, "G" : 8, "H" : 9}

class Foo(object):
    def __init__(self):
        for x in CHANNELS:
            setattr(self, "read{}".format(x), lambda x=x: self.read(CHANNELS[x]))

    def read(self, channel):
        return self._query("REQUEST STRING {}".format(channel))

    def _query(self, q):
        print "query {}".format(q)


f = Foo()
f.readT0()
f.readTend()
f.readA()
f.readB()
f.readC()
它可以工作,但也有一些缺点:

  • 它为每个和任何实例创建相同的函数集(在这种情况下没有任何原因,因为所有实例都基于相同的
    通道
    定义)
  • 这些函数没有文档记录,不会出现在
    dir(Foo)
    help(Foo)
jonsharpe的
\uuu getattr\uuuu
解决方案解决了第一点,但没有解决第二点。这里最简单的解决方案是使用类装饰器,在类本身上添加getter(作为方法或属性,由您决定),即(属性版本):


现在您可以使用
dir(Baaz)
help(Baaz)
或任何其他自省机制

你为什么要
?难道
class.A0
不会更整洁吗?
\u query
如何与字典相对应?嗨,
class.T0
class.A
确实会更整洁,但通道有不同的属性,因此
read
可能会改为
class.delayT0
class.offset0
。。。不知道你所说的对应是什么意思:
\u query()
是一个从硬件读取的com函数。不要对有副作用的东西使用属性,这太糟糕了,用方法代替。记住:显式比隐式好。属性用于隐藏属性上的小操作,而不是在简单属性中隐藏代价高昂的方法。为什么我的示例会产生副作用?我有一个属性,我将在其他更复杂的方法中使用它。但是在这里我只想读取并可能更改值(可以从硬件更改为),我可能想对其执行一个小操作…您说过_query是一个从硬件读取的函数,这是一个副作用,而且成本很高,应该是显式的。嗨,我不想从字典中读取,而是从ADC输入中读取。通道只能从
A
转换为2,因为硬件使用数字作为通道标识符。@Wolf82是的,这只是向您展示了如何使用
\uuuuu getattr\uuuuu
来处理缺少的属性并从字典中获取相关的通道号。将其集成到您的代码库中是您的工作!
>>> thing = Something()
>>> thing.readA
2
>>> thing.readT0
0
>>> thing.garbage
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __getattr__
AttributeError: 'Something' object has no attribute 'garbage'
CHANNELS = {"T0": 0, "Tend": 1, "A": 2, "B": 3, "C" : 4, "D" : 5,
    "E" : 6, "F" : 7, "G" : 8, "H" : 9}

class Foo(object):
    def __init__(self):
        for x in CHANNELS:
            setattr(self, "read{}".format(x), lambda x=x: self.read(CHANNELS[x]))

    def read(self, channel):
        return self._query("REQUEST STRING {}".format(channel))

    def _query(self, q):
        print "query {}".format(q)


f = Foo()
f.readT0()
f.readTend()
f.readA()
f.readB()
f.readC()
def with_channel_props(cls):
    for x in cls.CHANNELS:
        getter = lambda self, x=x: self.read(self.CHANNELS[x])
        setattr(cls, "{}".format(x), property(getter))
    return cls


@with_channel_props
class Baaz(object):
    CHANNELS = {
        "T0": 0, "Tend": 1, "A": 2, "B": 3, "C" : 4, "D" : 5,
        "E" : 6, "F" : 7, "G" : 8, "H" : 9
        }

    def read(self, channel):
        return self._query("REQUEST STRING {}".format(channel))

    def _query(self, q):
        return "query {}".format(q)

b = Baaz()
print b.T0
print b.Tend
print b.A
print b.B
print b.C