In Python with a nested dictionary, should I check the type? What other approach can I use?

Disclaimer: hello to all the masters and fans of Python. I would like to thank everyone for their caring support and expensive advice that helped me a lot. I'm a Python newbie who is trying to learn and grow, given the importance of best practices. Here is a question in which I am looking for a quick way to avoid type checking, as if there is one thing I found out here that this is not good, and there must be another way to do this.

I am creating a data object to represent a site map. I want this in memory, so I can quickly match the URLs before querying the DB.

Each node must have 2 elements. name (section of the site) and ID (its identifier in the database) (usually from 4 to 8 digits, but only one digit is presented here).

If this node has children (on the page), it has a name, identifier, and another dictionary representing the children .

I decided to use the following for performance, convenience of iterations and memory considerations: I have only tried the [name, id, [name, id, ..]] lists, dictionaries in the past, and I think this is not so bad.

sitemap = {'section_one': 0, 'section_two': [1, {'c_sect_2_1': 10, 'c_sect_2_2': [11, {'c_sect_2_2_1': 110, 'c_sect_2_2_2': 111, 'c_sect_2_2_3': 112}], 'c_sect_2_3': 12, 'c_sect_2_4': 13}], 'section_three': 2, 'section_four': 3, 'section_five': 4} 

I chose lists because I might need to modify them (therefore, there are no tuples) I use hashables and I can easily check if they contain a section.

Using this data set, using the following function, I map the URL (e.g. / section_two / c_sect_2_2 / c_sect_2_2_3) and see if it exists or not to retrieve data from the database. My function for this:

 def map_url(url): #url here is a list eg ['section_two', 'c_sect_2_2', 'c_sect_2_2_3'] sm = sitemap for e in url: if e in sm: if isinstance(sm[e], int): return sm[e] #e = where it stops matching due to no children sm = sm[e][1] #if not INT it a list. list[1] has another dict to go-through return False #the URL could not be matched-mapped 

My questions:

  • Instead of checking if the value of an element in the dictionary is an integer to find out if it has children or not, what should I do? What can I do?
  • What could be an alternative to all this? (a method of constructing a data structure and / or iteration through it)

I need this way of displaying URLs, since my site can have many sub-sections, and I don't want to query the database many times to find out if it exists.

Finally, I thank you all for your precious times and advice.

+4
source share
3 answers

Instead of checking if the value of an element in the dictionary is integer to find out if it has children or not, what should I do? What can I do?

The problem is that you use different views for sections with children and for sections without children. A section without children should simply be a section with an empty list of children:

 sitemap = {'section_one': [0, {}], 'section_two': [1, {'c_sect_2_1': [10, {}], 'c_sect_2_2': [11, {'c_sect_2_2_1': [110, {}], 'c_sect_2_2_2': [111, {}], 'c_sect_2_2_3': [112, {}]}], 'c_sect_2_3': [12, {}], 'c_sect_2_4': [13, {}]}], 'section_three': [2, {}], 'section_four': [3, {}], 'section_five': [4, {}]} 

Your code should now be a little easier.

What could be an alternative to all this? (a method of constructing a data structure and / or iteration through it)

You can convert a sitemap into a flat dictionary at the beginning of your program so that it becomes something like

 flat_sitemap = { 'section_one': 0, 'section_two': 1, 'section_two/c_sect_2_1': 10, # ... 'section_two/c_sect_2_2/c_sect_2_2_1': 110 # ... } 

This way your queries will work in the expected O(1) time due to higher space utilization.

As for handling the original structure differently, you can use recursion. It is often easier for me to recursively formulate an algorithm on a tree structure, but it depends a little on your thinking. Here is an example (I accept the sitemap format, which is shown in my first example):

 def map_url(url, sm=[None, sitemap]): if not url: return sm[0] if url[0] not in sm[1]: return False return map_url(url[1:], sm[1][url[0]]) print map_url(['section_two', 'c_sect_2_2', 'c_sect_2_2_3']) # => 112 print map_url(['section_two', 'c_sect_2_2']) # => 10 print map_url(['section_two', 'notexisting']) # => False print map_url([]) # => None 

As you can see, this makes the special case explicit when you pass an empty URL. You should definitely think about what should happen in this particular case.

You can even leave the second line of the function. In this case, a KeyError will be KeyError if the URL cannot be matched (which also seems reasonable).

+6
source

A more consistent approach would be to always use a combination of id and dict, but use an empty dict if there are no children.

 sitemap = {'section_one': [0, {}], 'section_two': [1, {'c_sect_2_1': [10,{}], 'c_sect_2_2': [11, {'c_sect_2_2_1': [110,{}], 'c_sect_2_2_2': [111,{}], 'c_sect_2_2_3': [112,{}]}], 'c_sect_2_3': [12,{}], 'c_sect_2_4': [0,{}]}], 'section_three':[2,{}], 'section_four': [3,{}], 'section_five': [4,{}]} 

This way you can always check if the rest of the url is in the child dict.

+4
source

For your first question: a pythonic way of not checking type, but trying to catch an exception:

 sm = sitemap for e in url: if e in sm: try: sm = sm[e][1] except TypeError: return sm[e] return False 

Here, if sm[e] is an integer, it cannot be indexed, and a TypeError exception TypeError : you can return your element. If sm[e] can be indexed, you will update your sm . If indexing fails (for example, because there is only one element), another exception will be thrown, which you can also catch.

0
source

All Articles