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))
没有此代码段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?
答案 0 :(得分:6)
您的__iter__
是可变的:它将对象的n
属性设置为0
。这是代码中n
的 only 初始化。如果未调用__iter__
,则__next__
在寻找时将找不到n
。
可变__iter__
方法不是一个好主意。您应该在__init__
中执行初始化。
答案 1 :(得分:1)
Python对象可以分配给多个名称。所有这些名称将引用相同的实际对象。例如:
a = [1, 2, 3]
b = a
a
和b
都引用相同的对象。设置b[0] = 0
也将影响a
,因为它是同一对象。这会给初学者带来很多痛苦。
要将对象绑定到名称,可以对其进行分配。作业有多种形式。例如,def
和class
分别将函数和类对象分配给名称。这些名称并不特殊,您可以随意重新绑定它们:
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)
时,会发生以下情况:
iter
的呼叫等同于PowTwo.__iter__(a)
a
的对象已绑定到self
中的参数__iter__
self
中的对象__iter__
通过返回调用绑定到b
现在a
和b
引用相同的对象。此后调用next(a)
或next(b)
会将相同的对象传递给next
,因为两个名称都绑定到该对象。
如果您分配了a = iter(a)
,则将a
与其自身重新绑定。虽然从技术上讲不是禁忌,但它等效于仅调用iter(a)
并丢弃冗余返回值。