I have a recursive method problem with python, the code is this:
class NodeTree(object):
def __init__(self, name, children):
self.name = name
self.children = children
def count(self):
# 1 + i children's nodes
count = 1
for c in self.children:
count += c.count()
return count
def create_tree(d):
N = NodeTree(d['name'], d['children'])
print N.count()
d1 = {'name':'musica', 'children':[{'name':'rock', 'children':[{'name':'origini','children':[]},
{'name':'rock&roll','children':[]},
{'name':'hard rock', 'children':[]}]},
{'name':'jazz', 'children':[{'name':'origini', 'children':[{'name':'1900', 'children':[]}]},
{'name':'ragtime', 'children':[]}, {'name':'swing', 'children':[]}]}]}
tree = create_tree(d1)
The error is this:
count += c.count()
AttributeError: 'dict' object has no attribute 'count'
I tried anything but it doesn't work.
Anyway, any suggestions? Thanks!
That's because Python dictionaries do not have a count
method.
It'll help if we go over line by line what your code is actually doing.
def count(self): # 1 + i children's nodes count = 1 for c in self.children: ## self.children is a list of dictionaries, so each c is a dictionary count += c.count() ## We are getting .count() of c--which is a dictionary return count
This is because we passed d1['children'] as self.children, which is a list of dictionaries: [<dict>, <dict>, <dict>, ... ]
.
Rather than count()
, what you should do is call len
on the dictionary, to get the number of keys it has, thus becoming:
for c in self.children:
count += len(c)
d['children']
is a list of dict
, as you can see in d1
dict.
Now, when you iterate over your children
, in NodeTree
, which is essentially d['children']
only, you will get dictionary
as each element: -
for c in self.children: // c is a `dict` type here
count += c.count() // there is not attribute as `count` for a `dict`.
And hence you got that error.
Well, for once, the create_tree
function does not build the tree recursively. So you just add a Node on zero level and the the children are just dictionaries.
The following (modified) code (although quickly typed and sloppy) should do a recursive build of the tree. Didn't check your count
code, but assuming it is correct, it should work.
class NodeTree(object):
def __init__(self, name, children):
self.name = name
self.children = children
def count(self):
# 1 + i children's nodes
count = 1
for c in self.children:
count += c.count()
return count
def deep_create_tree(d):
if len(d["children"]) > 0:
chlds = []
for i in d["children"]:
chlds.append(deep_create_tree(i))
else:
chlds = []
n = NodeTree(d["name"], chlds)
return n
d1 = {'name':'musica', 'children':[{'name':'rock', 'children':[{'name':'origini','children':[]},{'name':'rock&roll','children':[]},{'name':'hard rock', 'children':[]}]},{'name':'jazz', 'children':[{'name':'origini', 'children':[{'name':'1900', 'children':[]}]},{'name':'ragtime', 'children':[]}, {'name':'swing', 'children':[]}]}]}
def scan_tree(tr):
print tr.name, tr.count()
for i in tr.children:
scan_tree(i)
tr = deep_create_tree(d1)
scan_tree(tr)
The best (and the only desirable) way is to have a recursive creation of your node tree. This can be done in two different ways, either make your NodeTree.__init__()
recursively init all of the children (which again recursively init all of their children, etc) or you can make your create_tree()
function recursive.
I'd personally use recursive __init__()
, but it's your call.
Recursive __init__()
for creating tree structure:
def __init__(self, name, children=[]):
self.name = name
self.children = []
for c in children:
self.children.append(
self.__class__(c['name'], c['children']))
This way self.children
will contain other NodeTree
s instead of dict
s. Also you no longer need to declare empty children list, instead of:
d2 = {'name':'sterile', 'children':[]}
do
d2 = {'name':'sterile'}
And the initializer will automatically set children to []
If you want to use a recursive create_tree()
function, it's also possible, and not a bad idea either. However you will still have to edit the __init__()
-method, it no longer takes children as parameter. Or as I did here, it does, but you hardly ever use it.
# NodeTree
def __init__(self, name, children=None):
self.name = name
if children:
self.children = children
def create_tree(d):
N = NodeTree(d['name'])
for c in d['children']:
N.children.append(create_tree(c))
return N
This will have basically the same results.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.