【问题标题】:Using 'self' in for loop and conditional statements in python在python中的for循环和条件语句中使用'self'
【发布时间】:2023-03-19 23:42:01
【问题描述】:

我正在学习 Python 中的链表。在这个网站上,在其中一种方法中,

    def add_last(self, node):
    if self.head is None:
        self.head = node
        return
    for current_node in self:
        pass
    current_node.next = node

for current_node in self: 这行是什么意思?一个人怎么能遍历self?遍历self是什么意思?

下面是python中链表实现的完整代码

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

    def __repr__(self):
        return self.data

class LinkedList:
    def __init__(self):
        self.head = None
  
    def __init__(self, nodes=None):
        self.head = None
        if nodes is not None:
            node = Node(data=nodes.pop(0))
            self.head = node
        for elem in nodes:
            node.next = Node(data=elem)
            node = node.next
    
    def __repr__(self):
        node = self.head
        nodes = []
        while node is not None:
            nodes.append(node.data)
            node = node.next
        nodes.append("None")
        return " -> ".join(nodes)

【问题讨论】:

  • "for current_node in self" 不能与所示实现一起使用。 “LinkedList”必须提供正确实现的__iter__ 方法才能成为可迭代并支持此“for...”。
  • @MichaelButscher 有一个 iter 方法 def __iter__(self): node = self.head while node is not None: yield node node = node.next
  • 所以“整个代码”不是整个代码?

标签: python python-3.x linked-list


【解决方案1】:

在 python 中,我们可以在 for 循环中使用几种不同的类型/类(即列表、字符串等)。在构建 for 循环时,python 解释器将接受任何 iterable 对象。要使对象成为可迭代,其类必须实现__iter__ 方法。只要类实现了这个方法,python 不关心你是使用self 还是标准变量来引用对象。

这是一个来自可迭代对象的 wiki 页面的示例。请注意,__next__ 方法还有另一层。定义了__next__ 的类称为迭代器迭代器 提供了为 for 循环生成一系列元素的实际逻辑。 iterable 必须返回带有 __iter__iterator 对象。对于更复杂的类型,iterator 可能需要与 >iterable,但在简单的情况下(如以下示例),它们可以是同一个类。

    import random
    
    class RandomIterable:
        def __iter__(self):
            return self
        def __next__(self):
            if random.choice(["go", "go", "stop"]) == "stop":
                raise StopIteration  # signals "the end"
            return 1

https://wiki.python.org/moin/Iterator

【讨论】:

    【解决方案2】:

    在 cmets 中,您解释了 LinkedList 类具有此方法:

    def __iter__(self): 
        node = self.head
        while node is not None:
            yield node
            node = node.next
    

    这使得使用for..in 循环迭代LinkedList 的实例成为可能。其实add_last下面这段代码:

        for current_node in self:
            pass
    

    可以写成这样更详细的方式:

        it = iter(self)
        try:
            while True:
                current_node = next(it)
        except:
            pass
    

    所以add_node 可以这样写:

    def add_last(self, node):
        if self.head is None:
            self.head = node
            return
        it = iter(self)
        try:
            while True:
                current_node = next(it)
        except:
            current_node.next = node
    

    it 表示 for 循环隐式创建的迭代器,但使用此代码更容易跟踪正在发生的事情。

    假设你的列表中有两个节点,值为 1 和 2,那么更详细的add_node 的执行顺序如下:

    add_last __iter__
    self.head is not None
    it = iter(self)
    next(it)
    node = self.head
    node is not None
    yield node (with value 1)
    current_node = (node with value 1)
    next(it)
    node = node.next
    node is not None
    yield node (with value 2)
    current_node = (node with value 2)
    next(it)
    node = node.next
    node is None (!)
    raise StopIteration() (implicit)
    except:
    current_node.next = node

    实际上,current_node 的最后一个值是列表中的最后一个节点,将新节点分配给它的 next 属性正是您希望使用该节点扩展列表时发生的事情。

    其他cmets

    不是您的问题,但您的代码中存在一些问题:

    • LinkedList 中的第二个 __init__ 定义会覆盖第一个。 Python中没有这种重载的概念。但在这种情况下,您也不需要第一个定义,因为第二个版本的第二个参数有一个默认值。

    • for 循环在 __init__ 方法中的缩进是错误的。它应该在if 块内。

    • 调用.pop(0) 对构造函数的调用者来说并不好:它会改变给定的列表,这可能是调用者不希望出现的副作用。

    • ListNode 上的__repr__ 方法假定从Node__repr__ 方法接收到的值是字符串,否则join 将失败。如果您想使用节点来存储整数(例如),此方法将失败。为避免这种情况,请在Node__repr__ 方法中将self.data 转换为字符串。

    【讨论】:

      猜你喜欢
      • 2023-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-01
      • 2011-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多