1

I have the following code which I use to modify the node that is passed into the function recursively (the node is wrapped in an array so that the modification is persistent after the function returns):

Is there a better or cleaner way to modify the argument?

`

class node(object):
    def __init__(self, value, next=None):
        self._value = value
        self._next = next

    def __repr__(self):
        return "node({0})".format(self._value)


    @property
    def next(self):
        return self._next



def foo(a, b):
    if b == 0:
        print "setting to next node",
        a[0] = a[0].next
        print a
        return

    print a
    foo(a, b-1)
    print a

n = node(5, node(8))
foo([n], 2)

`

Question was answered in: How do I pass a variable by reference?

Community
  • 1
  • 1
Mark W
  • 37
  • 5
  • You're not modifying the object; you're just replacing the object stored in the anonymous array. – chepner Dec 03 '15 at 03:08
  • What is the actual and suspected output of `foo`? I suspect that all you need to do is make the recursive call `foo(a.next, b-1)`. – chepner Dec 03 '15 at 03:11
  • I'm really trying to emulate void foo(node **obj) { *obj = (*obj)->next; } (C++) – Mark W Dec 03 '15 at 05:23
  • Actually http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference answered my question – Mark W Dec 03 '15 at 05:26

2 Answers2

0

To modify something, that thing has to be mutable. Your node instances are mutable:

n = node(3)
assert n.value == 3
n.value = 5
assert n.value == 5  # it was modified!

Also, your function fails to return any values. In your case it may be a wrong approach. Also, I frankly don't see why you would use number (0, n - 1) where the .next value is referenced. These must be node instances, not numbers.

Apparently you're making a linked list implementation, and your foo function tries to remove n-th node by traversing a list. (Please take care to name your functions descriptively; it helps both you and people answering your question.)

That's how I'd do it:

class Node(object):  # class names are usually TitleCase
    def __init__(self, value, next=None):
        self.value = value
        self.next = next  # no properties for simplicity

    def __repr__(self):
        return "node({0})".format(self.value)


def asList(node):  # nice for printing
    if not node:
        return []
    return [node.value] + asList(node.next)


def removeNodeAt(head_node, index):
  """Removes a node from a list. Returns the (new) head node of the list."""
  if index == 0:  # changing head
    return head_node.next
  i = 1  # we have handled the index == 0 above 
  scan_node = head_node
  while i < index and scan_node.next:
    scan_node = scan_node.next
    i += 1
  # here scan_node.next is the node we want removed, or None
  if scan_node.next:
    scan_node.next = scan_node.next.next  # jump over the removed node
  return head_node

It works:

>>> n3 = Node(0, Node(1, Node(2)))
>>> asList(removeNodeAt(n3, 2))
[0, 1]

>>> n3 = Node(0, Node(1, Node(2)))
>>> asList(removeNodeAt(n3, 1))
[0, 2]
9000
  • 39,899
  • 9
  • 66
  • 104
-1

Because the parameter your are operating is object. You could use __dict__ to change the whole property of the object. It is equivalent to change every property of the project. You could try the following code:

class node(object):
    def __init__(self, value, next=None):
        self._value = value
        self._next = next

    def __repr__(self):
        return "node({0})".format(self._value)


    @property
    def next(self):
        return self._next



def foo(a):
    print "setting to next node\n",
    a.__dict__ = getattr(a.next, '__dict__', None)
    return

n = node(5, node(8, node(7)))

print n._value, '->' ,n._next._value
foo(n)
print n._value, '->' ,n._next._value

Hope this could help you.

Xiaoqi Chu
  • 1,497
  • 11
  • 6
  • 1
    While this is ingenious, this just makes the two objects share the `__dict__`, so changes in one object are reflected in another. Manupulating `__dict__` directly is discouraged; allowing it to be `None` (see your `getattr` call) can be catastrophic. – 9000 Dec 03 '15 at 04:13
  • @9000 Upvoted. You are correct. Maybe use deepcopy to duplicate the `__dict__` could improve a little bit. As for the None issue, code should be modified depends on their case. – Xiaoqi Chu Dec 03 '15 at 04:18