【问题标题】:Why is the variable a is changed in this code?为什么在这段代码中变量 a 发生了变化?
【发布时间】:2020-07-09 20:15:37
【问题描述】:
class PowTwo:
    """Class to implement an iterator
    of powers of two"""

    def __init__(self, max=0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.max:
            result = 2 ** self.n
            self.n += 1
            return result
        else:
            raise StopIteration
a = PowTwo(3)
b = iter(a)
print(next(a))

没有这个sn-p b = iter(a),输出是

Traceback (most recent call last):
  File "/Users/Mark/test2.py", line 20, in <module>
    print(next(a))
  File "/Users/Mark/test2.py", line 13, in __next__
    if self.n <= self.max:
AttributeError: 'PowTwo' object has no attribute 'n'

我的问题:

b = iter(a)我没有使用a = iter(a)。变量a怎么在这里变了?

【问题讨论】:

  • __iter__ 返回self。我不确定是什么绊倒了你。请澄清。
  • @MadPhysicist,我不明白的是我将 iter() 函数应用于变量 a 并将其分配给变量 b。但是,变量 a 在这个过程中也获得了这个 self.n 属性。我希望它保持不变。
  • 您可以将同一个对象分配给多个名称。它仍然是同一个对象。
  • @MadPhysicist,因此,iter(a) 只是将 self.n 属性添加到对象和对象 ID 保持不变?
  • 是的。我会立即添加一个答案

标签: python python-3.x scope


【解决方案1】:

您的__iter__ 是可变的:它将对象的n 属性设置为0。这是代码中n唯一 初始化。如果__iter__没有被调用,__next__在查找时将找不到n

可变的__iter__ 方法是个坏主意。您应该在__init__ 中执行初始化。

【讨论】:

  • 这是我今天看到的第二个问题。我想知道这是不是每个人都在关注的蹩脚的流行教程
  • 非常感谢!您的回答也消除了一些疑问!但是,系统只让我选择一个。 :(
【解决方案2】:

Python 对象可以分配给多个名称。所有这些名称都将指代同一个实际对象。例如:

a = [1, 2, 3]
b = a

ab 都指向同一个对象。设置b[0] = 0 也会影响a,因为它是同一个对象。这给初学者带来了很大的痛苦。

要将对象绑定到名称,请分配它。作业有多种形式。例如,defclass 分别将函数和类对象分配给名称。这些名字并不特殊,可以随意重新绑定:

def a():
    print('Hi')

b = a   # b now refers to a function object
a = 1   # a is now an integer, while b is the original function

当您将参数传递给函数时,会发生另一种类型的赋值。您传入的对象绑定到参数列表中的本地名称。函数本地名称指的是您传入的完全相同的对象,而不是副本:

a = 1
def f(x):
    print(x is a)
f(a)  # True

返回值的工作方式类似,但相反。函数中的对象被分配给外部范围内的名称。

现在假设您有一个对象a = PowTwo(3)。当你在上面调用b = iter(a) 时,会发生以下事情:

  1. iter的调用相当于PowTwo.__iter__(a)
  2. 在全局范围内分配给a 的对象绑定到__iter__ 中的参数self
  3. __iter__ 中的对象self 通过返回调用绑定到b

现在ab 指的是同一个对象。之后调用next(a)next(b) 会将同一个对象传递给next,因为这两个名称都绑定到它。

如果您分配了a = iter(a),您将重新绑定a 到它自己。虽然从技术上讲不是无操作,但它相当于只调用 iter(a) 并丢弃多余的返回值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 2016-06-09
    • 2016-01-27
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多