Reputation: 1736
When I look at the code for Graph.nodes() here: https://github.com/networkx/networkx/blob/main/networkx/classes/graph.py#L658 it doesn't take in any parameters. So how is it that I am able to pass something like data=True (e.g., Graph.nodes(data=True))? Ideally, I would get a "got an unexpected keyword argument 'data'" error.
It is also decorated as a property, but I am able to call it as a function. This is probably a basic python question, but this is the first time I am encountering this.
Upvotes: 2
Views: 271
Reputation: 7083
Keeping networkx
aside. Take this code snippet.
class CallableIterable:
def __init__(self, val):
self.val = val[:]
def __call__(self, arg1=True):
print('acting as a callable')
return f'You called this with {arg1}'
def __contains__(self, arg):
print('acting as an iterable')
return arg in self.val
class Graph:
@property
def nodes(self):
return CallableIterable([1, 2, 3, 4, 5])
You can see that there are two classes CallableIterable
and Graph
. Graph
has a property nodes
that returns an instance of CallableIterable
when called.
Create an instance of Graph
g
.
g = Graph()
Now you can use the property g.nodes
in two ways.
As an iterable
print(1 in g.nodes)
This gives
acting as an iterable
True
This is because in
triggers the __contains__
method of the CallableIterable
class (in this example).
As a callable
print(g.nodes('some random value'))
This gives
acting as a callable
You called this with some random value
This is because it triggers the __call__
method of the CallableIterable
class.
The arguments passed in ()
, in this case, 'some random value'
of g.nodes('some random value')
or in your case, data=True
of Graph().nodes(data=True)
are passed to the __call__
of the return value of the property (which is g.nodes)
, NOT TO the property decorated function Graph.nodes
.
Internally this is g.nodes.__call__('some random value')
.
With this understanding apply the same principle to networkx
, where NodeView
is the type of object returned instead of the CallableIterable
as seen in this example, the working is the same.
nodes = NodeView(self)
is an instance of the NodeView
class.__call__
and a __contains__
method.Graph().nodes(data=True))
) and as an iterable ('something' in Graph().nodes
).The NodeView
class has other functions than just __call__
and __contains__
, each of which will get called appropriately.
This is essentially what the docstrings mean with the following
Can be used as `G.nodes` for data lookup and for set-like operations. Can also be used as `G.nodes(data='color', default=None)` to return a NodeDataView which reports specific node data but no set operations
Upvotes: 3