2
class _Edges(defaultdict):

    def __missing__(self, vertex):
        self.setdefault(vertex, True)

    def __delitem__(self, dst):
        self[dst] = False

    def del_vertex(self, dst):
        super().__delitem__(dst)

class Graph(defaultdict):

    def __init__(self):
        super().__init__(_Edges)
    
    def copy(self):
        return super().__copy__()

I'm trying to write a class that makes a graph but when I try to call the copy function I get the error. Should I write my own __copy__? I thought that I could use defaultdict's copy to copy the graph.

The copy class is supposed to create an exact copy of the graph by calling graph.copy() ex.

g = Graph() 
g['a']['b'] = 5
x = g.copy()

This would make an exact copy but i get the error stated above instead

wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • For starters, your `__missing__` implementation is wrong... it always returns `None` which is probably not what you want. – juanpa.arrivillaga May 09 '21 at 00:21
  • 1
    Please provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – a_guest May 09 '21 at 00:23
  • it might be better ?? to call `super().copy()` rather than call the magic method directly. – Tony Suffolk 66 May 09 '21 at 00:23
  • I made that so if i tried to make an unweighted edge it would come out with a value of true. Just to indicate that the edge exists but it doesn't have weight, – DivinusMessor May 09 '21 at 00:25
  • I tried the super.copy() and i got the same error return super().copy() TypeError: __init__() takes 1 positional argument but 3 were given – DivinusMessor May 09 '21 at 00:27
  • You need to look at where `Graph` is instantiated; is it created with 1 argument as you've defined it to expect? 2? Or 3 as the error is telling you? – msbit May 09 '21 at 00:53

1 Answers1

1

Based on testing, I'm fairly sure that the __copy__ implementation of defaultdict will call __init__ on Graph with at least two arguments:

To address that, you could modify your Graph class to be:

class Graph(defaultdict):
  def __init__(self, *args):
    if len(args) == 0:
      super().__init__(_Edges)
    else:
      super().__init__(*args)

so if it is being called as part of a copying operation (when args contains a value), all the values are simply passed along to the defaultdict implementation; but if args is empty, the defaultdict implementation is called with only the default_factory argument. With this implementation, you may not need to provide a copy or __copy__, as defaulting to the one provided by defaultdict is sufficient.

msbit
  • 4,152
  • 2
  • 9
  • 22