在这段代码中,类Node的对象正在使用一个变量next,该变量在任何地方都没有定义,代码仍在工作?对象如何使用未在其类中定义的变量
class Node:
def __init__(self, data):
self.data = data
class LinkedList:
# Function to initialize head
def __init__(self):
self.head = None
# Function to reverse the linked list
def reverse(self):
prev = None
current = self.head
while(current is not None):
next = current.next
current.next = prev
prev = current
current = next
self.head = prev
# Function to insert a new node at the beginning
def push(self, new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
# Utility function to print the linked LinkedList
def printList(self):
temp = self.head
while(temp):
print(temp.data)
temp = temp.next
llist = LinkedList()
llist.push(20)
llist.push(4)
llist.push(15)
llist.push(85)
print( "Given Linked List")
llist.printList()
llist.reverse()
print ("nReversed Linked List")
llist.printList()
虽然在大多数强类型语言中这是不可能的,但Python允许在创建实例并运行构造函数之后定义实例属性。只要代码在定义属性之前没有引用该属性,就没有问题。另请参阅:我可以在构造函数方法之外声明Python类字段吗?
在这种特殊情况下,以下代码将产生错误:
node = Node(42)
if node.next: # Attribute error
print("42 is not the last node")
else:
print("42 is the last node")
但是,创建新节点实例的唯一位置是LinkedList
类的push
方法:
def push(self, new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node
如您所见,next
属性是在构造节点后立即定义的。因此,在实践中,链表中的每个节点都将具有next
属性。
最佳实践
这种编码实践是否可取,还有待商榷。例如,Pylint有一个定义attr方法的规则,当属性在__init__
、__new__
、setUp
或__post_init__
之外定义时,默认情况下会引发警告。
备选方案
在这种情况下,我当然更喜欢在构造函数中定义next
属性,并为构造函数提供一个额外的可选参数,用它可以初始化next
:
class Node:
def __init__(self, data, nxt=None):
self.data = data
self.next = nxt
有了这个变化,LinkedList
类的push
方法可以简化为:
class LinkedList:
# ...
def push(self, new_data):
self.head = Node(new_data, self.head)
这看起来要优雅得多。
不相关,但我也会让LinkedList
的构造函数接受任何数量的值来初始化列表:
class LinkedList:
def __init__(self, *values):
self.head = None
for value in reversed(values):
self.push(value)
现在,主代码可以一次创建一个包含4个值的列表:
llist = LinkedList(85, 15, 4, 20)