【问题标题】:Creating instance-vars in a loop returns None objects在循环中创建实例变量返回 None 对象
【发布时间】:2018-02-19 03:20:26
【问题描述】:

我尝试了一个小的trafficlight 实现,得到了以下代码:

def __init__(...):
    ...
    self.redLight = Light(color = "red", master = self.frame)     
    self.redLight.place(x = 10, y = 10)
    self.yellowLight = Light(color = "yellow", master = self.frame)
    self.yellowLight.place(x = 10, y = 40)
    self.greenLight = Light(color = "green", master = self.frame)
    self.greenLight.place(x = 10, y = 70)
    ...

我觉得无聊,试图在循环中定义这个相当多余的代码:

def __init__(...):
    ...
    self.redLight = None
    self.yellowLight = None
    self.greenLight = None

    for l in [[self.redLight, "red", 10],
              [self.yellowLight, "yellow", 40],
              [self.greenLight, "green", 70]]:
        l[0] = Light(color = l[1], master = self.frame)
        l[0].place(x = 10, y = l[2])
    ...

我的理解是,它与第一个代码示例完全相同,但事实证明,它并没有编写实例变量。当我在调试器中查看代码时,l[0] 对象是一个 Light-object...

不是python call-by-reference,所以l[0]应该直接写实例变量?

【问题讨论】:

  • l[0] 是索引 0 处的列表元素,而不是实例变量。
  • 但是如果python引用了它就不是问题了吗?那么l[0] 将是(参考)与self.redLight 相同的对象

标签: python python-3.x class attributes


【解决方案1】:

这就是 setattrgetattr 的用途:

def __init__(self):
    for l in [['redLight', "red", 10],
              ['yellowLight', "yellow", 40],
              ['greenLight', "green", 70]]:
        setattr(self, l[0], Light(color=l[1], master=self.frame))
        getattr(self, l[0]).place(x=10, y=l[2])

因为如 cmets 中所述,分配给 l[0] 只会更改局部变量 l 的内容,而该变量不会设置实例上的属性。

请注意,这归结为:

>>> a = 1
>>> b = a
>>> b = 2  # assigning a new value to "b" doesn't change "a"!
>>> a
1

或:

>>> a = 1
>>> b = [a]
>>> b[0] = 2  # won't change "a".
>>> a
1

因此,虽然您可以通过分配给 self.redLight 来更改属性,但这并不意味着您可以通过为包含对 self.redLight 值的引用的列表分配不同的值来更改属性。

【讨论】:

  • ty,有没有办法像你可以通过指针在 c++ 中那样说 python,这是同一个对象,所以它们会改变(只是好奇问:D)?
  • 不幸的是(或者说幸运的是)不是。在某些情况下,您可以使用可变类型并对其进行变异来获得类似的结果(例如,如果您更改 self__dict__ 属性)。
  • @Steelbean 它不完全像指针,但您也可以使用 functools.partialgetattrsetattr 来“模拟”动态访问。例如rl = partial(getattr, self, 'redLight'),然后您可以访问rl() 以获取self.redLight 的当前值,同样rls = partial(setattr, self, 'redLight')rls(value) 以设置self.redLight。但它仍然需要函数调用,所以我不知道这是否“算作 C++ 之类的指针操作”。如果您愿意,我可以将其添加为答案中的完整示例。
猜你喜欢
  • 2014-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-17
  • 1970-01-01
  • 2018-04-02
  • 1970-01-01
相关资源
最近更新 更多