I have a nested dict which looks like this:
There are multiple nestings within the key children. I would like to capture the key branch whenever the key children is present. Because there are multiple children, I would like to do this for each child. Ofcourse, each child can also have further children. This nesting can go upto 7 levels.
To achieve this, I could either write a boneheaded 7-for loop method or use recursion. So I gave recursion a shot and came up with the following code:
def GatherConcepts(header):
if 'children' in header.keys():
if len(header['children']) > 0:
if 'branch' in header.keys():
concepts.append(header['handle'])
if 'children' in header.keys():
for j in range(0, len(header['children'])):
GatherConcepts(header['children'][j])
else:
for i in range(0,len(header['children'])):
GatherConcepts(header['children'][i])
The problem with this code is that it gives me only 2 levels (because I'm calling the function itself 2 times, thereby not using recursion properly), not 7.
How can I improve this to get all the levels?
Any pointers would be highly appreciated.
You have some unnecessary redundancies. If I understand you correctly, you need to add the handles to the list separately from the recursion, because you want to test branch in the parent.
def GatherConcepts(header):
if 'children' in header and 'branch' in header:
for child in header['children']:
concepts.append(child['handle'])
GatherConcepts(child)
You don't need to test the length of header['children'] -- if it's zero then the loop will just not do anything.
In order to get recursion correctly, you can use this simple template for it:
def recursive(variable):
if something:
# base step
return somethingelse
else:
# recursive step
return recursive(somethingelse)
In your case, you can try something like this:
def gather_concepts(header):
# recursive step
if 'branch' in header and 'handle' in header:
concepts.append(header['handle'])
if 'children' in header:
for child in header['children']:
return gather_concepts(child)
# base step
else:
return
You should tweak this code under your needs though, because I haven't tested it myself.
Related
I created a function in python that will change the priority for the first occurrence of an object, but im having trouble fixing it so that it would only work for the first occurrence without the use of break. In my code below I have used break and it works as intended but I would like to not use it.
def update_priority(self, object, priority):
for i in range(len(self._queue)):
if object == self._queue[i].get_item():
# checking object already has that priority
if priority == self._queue[i].get_priority():
# dont change if it has the priority
pass
# if the object does not have that priority set to new
else:
self._queue[i].set_priority(pri)
break
else:
pass
It sounds like you also want to learn how to reduce the length of the code. A rule of thumb is to concentrate on making your code clear and concise first, so you can try to identify ways to simplify the structure. For example, you can restructure and remove redundant branches. Many of your cases are just passes. Also, yes, college classes say that break statements aren't great. For clarity, you might want to use a conditional variable to end the loop. In this case, you don't really need to do that, but an alternative is to wrap the code in a function and bypass the rest of a loop simply by returning, You already use a function, so you can just return from the function if all you do is update the one item's priority (and exit). Perhaps you want to return a status code indicating that an item was found or not. (True or False).
def update_priority(self, object, priority):
# check all items in the queue (you do not require the index.)
# the entry is stored in "entry"
for entry in self._queue:
# if you find the object and its priority needs an update
if object == entry.get_item() and priority != entry.get_priority():
# set the priority
entry.set_priority(priority)
# return true for success, you found the object and updated it
return True
""" If you arrive at this line, the object didn't exist or
it didn't need an update (if you need to distinguish between "object not found" and
"object found but didn't update," use an extra flag or nest the != entry.get_priority as you did before"""
return False
Your solution is correct you do not need to change it so it doesnt use break. There is no other way to end a loop unless its a while loop and the condition is false or you reach the end of range in a for loop.
I have this case in Python (with Pyramid framwork), where I'm trying to check for condition.
Here is the code:
if some_condition:
value = self.__parent__.__parent__.__parent__.method()
else:
value = self.__parent__.__parent__.method()
The question is, is there more pythonic way (syntax sugar shortcut) for representing __parent__.__parent__... dynamically?
I know that there is Python syntax like this:
value1, value2, value3 = (None,) * 3
Is there something similar and dynamic for my case?
I searched in Google, in Python documentation, in Reddit source code, in Open Stack source code, and I spend 2 days in searching, so decided to ask here.
If you don't like the parent chain you could always write a helper method to get a node at a given depth. Though this might be less legible.
eg.
def get_parent(item, depth):
original_depth = depth
try:
while depth:
item = item.__parent__
depth -= 1
return item
except AttributeError:
raise AttributeError("No parent node found at depth {}".format(
original_depth-depth))
Usage:
get_parent(self, 3).method()
As far as I know there is no such syntax in python.
However you may indeed implement custom method for obtaining a list of parent resources:
def find_ancestors(resource):
ancestors = [resource]
while hasattr(ancestors[-1], '__parent__'):
ancestors.append(ancestors[-1].__parent__)
return ancestors
Or a method to iterate them:
def iter_ancestors(resource):
yield resource
while hasattr(resource, '__parent__'):
resource = resource.__parent__
yield resource
Also, I'm not sure if such way is the appropriate one. I think you should take a look at find_interface(..) method and somehow manage to define appropriate interfaces for your resources to locate them. Doing such way your code will look like:
value = find_interface(self, ResourceA if some_condition else ResourceB).method()
UPDATE: The code provided by #Dunes in his answer is another good approach to get ancestors by their index.
I need to get the first and only child element of a node and the child is guaranteed to be there. I could write something like this
def get_first(Node):
for x in Node:
return x
But I was hoping for something more elegant. Does anyone know of something?
Have you tried by index?
def get_first(node):
return node[0]
Well, I personally don't see anything wrong with your code. It is clean and will work for any iterable object.
Nevertheless, if you must do away with the for-loop, then you can use next:
def get_first(Node): # Also, Node should be lowercase according to PEP 8
return next(Node)
However, this will only work for iterators. If Node is not an iterator, then you can make it one with iter:
def get_first(Node):
return next(iter(Node))
Sorry if this is a general question but I am a beginner in Python and many times when I see other people code using recursion, they create a helper function for the main function and then call that helper function which itself is recursive.
This seems a bit different from the simplest cases of recursion for example (sum of lists, factorial) where the function only calls itself.
Can someone explain this technique more carefully perhaps with examples?
Much appreciated.
Example 1: (Reversing linked list using recursion)
def revert_list(self):
self.head = self._revert_helper(self.head)
def _revert_helper(self, node):
temp = None
if node.forward == None:
return node
else:
temp = self._revert_helper(node.forward)
node.forward.forward = node
node.forward = None
return temp
Example 2: (Binary Search Tree)
def __contains__(self, key):
return self._bstSearch(self._root, key)
# Returns the value associated with the key.
def valueOf(self, key):
node = self._bstSearch(self._root, key)
assert node is not None, "Invalid may key."
return node.value
# Helper method that recursively searches the tree for a target key:
# returns a reference to the Node. This allows
# us to use the same helper method to implement
# both the contains and valueOf() methods of the Map class.
def _bstSearch(self, subtree, target):
if subtree is None: # base case
return None
elif target < subtree.key: # target is left of the subtree root
return self._bstSearch(subtree.left)
elif target > subtree.key: # target is right of the subtree root
return self.bstSearch(subtree.right)
else: # base case
return subtree
This is actually used more often in other languages, because python can usually emulate that behavior with optional arguments. The idea is that the recursion gets a number of initial arguments, that the user doesn't need to provide, which help keep track of the problem.
def sum(lst):
return sumhelper(lst, 0)
def sumhelper(lst, acc):
if lst:
acc += lst[0]
return sumhelper(lst[1:], acc)
return acc
Here it's used to set a starting parameter to 0, so the user doesn't have to provide it. However, in python you can emulate it by making acc optional:
def sum(lst, acc=0):
if lst:
acc += lst[0]
return sum(lst[1:], acc)
return acc
Usually when I do this, it is because the recursive function is tricky or annoying to call, so I have a wrapper that is more convenient. For example, imagine a maze solver function. The recursive function needs a data structure to keep track of visited spots inside the maze, but for convenience to the caller I just want the caller to need to pass in a maze to solve. You can maybe handle this with a default variable in Python.
The other major reason I have done this is for speed. The recursive function is very trusting, and assumes its arguments are all valid; it just goes full speed ahead with the recursion. Then the wrapper function carefully checks all the arguments before making the first call to the recursive function. As a trivial example, factorial:
def _fact(n):
if n == 0: # still need to handle the basis case
return 1
return n*_fact(n-1)
def fact(n):
n0 = int(n)
if n0 != n:
raise ValueError("argument must make sense as an int")
if n < 0:
raise ValueError("negative numbers not allowed")
return _fact(n)
I have edited this from the original, and now it's actually a pretty reasonable example. We coerce the argument to an integer ("duck typing") but we require that the != operator not indicate it to have changed in value by this coercion; if converting it to int changes the value (for example, a float value that had a fractional part truncated) we reject the argument. Likewise, we check for negative and reject the argument. Then the actual recursive function is very trusting and contains no checks at all.
I could give less vague answers if you posted an example you have seen of code that inspired this question.
EDIT: Okay, discussion of your examples.
Example 1: (Reversing linked list using recursion)
Pretty simple: the "helper" function is a general recursive function that will work on any node in the class that has a linked list. Then the wrapper is a method function that knows how to find self.head, the head of the list. This "helper" is a class member function, but it could also be a simple function in a general data-structures stuff library. (This makes more sense in Python than in languages like C, because a function like this could work with any linked list that is a class with a member called forward as its "next pointer" value. So you really could write this once and then use it with multiple classes that implement linked lists.)
Example 2: (Binary Search Tree)
The actual recursive function returns None if no node can be found with the specified key. Then there are two wrappers: one that implements __contains__(), which works just fine if it returns None; and valueOf(), which raises an exception if the key is not found. As the comment notes, two wrappers lets us solve two different problems with a single recursive function.
Also, just as with the first example, the two wrappers kick off the search in a specific location: self._root, the root of the tree. The actual recursive function can be started anywhere inside a tree.
If __contains__() were implemented with a default argument of a node to search, and the default was set to some unique value, it could check for the special value and start at the root in that case. Then when __contains__() is called normally, the unique value would be passed in, and the recursive function could know that it needs to look at the special location self._root. (You can't just pass in self._root as the default value, because the default value is set at compile time, and the class instance can change after that, so it wouldn't work right.)
class UniqueValue:
pass
def __contains__(self, key, subtree=UniqueValue):
if subtree is UniqueValue:
subtree = self._root
if subtree is None: # base case
return None
elif key < subtree.key: # target is left of the subtree root
return self.__contains__(key, subtree.left)
elif key > subtree.key: # target is right of the subtree root
return self.__contains__(key, subtree.right)
else: # base case
return subtree
Note that while I said it could be implemented as I show here, I didn't say I prefer it. Actually I prefer the two wrappers version. This is a little bit tricky, and it wastes time on every recursive call checking to see if subtree is UniqueValue. More complex and wastes time... not a win! Just write the two wrappers, which start it off in the right place. Simple.
From my experience (and my experience only), I use this style of coding when
The recursion is only useful in the larger function (not very recommended, but I have some bad habits)
There needs to be preparation done for the function, but only once (instead of a flag or other switch)
One way I use it is for logging purposes, while avoiding re-logging levels
def _factorial(x):
return 1 if x == 0 else x*_factorial(x)
#log #assuming some logging decorator "log"
def factorial(x):
return _factorial(x)
Otherwise, log would be called for each recursive level of the factorial function, something I may not desire.
Another usage would be to resolve default arguments.
def some_function(x = None):
x = x or set() #or whatever else
#some stuff
return some_function()
Would check if x is falsey for every iteration, while what I actually need is a decorator, or as an alternative:
def some_function(x = None):
return _some_function(x if x else set())
where _some_function is the helper function.
Specifically with 2, it allows for some freedom of abstraction. If for some reason you didn't want to use a bstsearch, you could just swap it for some other function in __contains__ (and you'd also be able to reuse code in different places)
So for my first big python project I'm building a text based game. It's supposed to be modular so the story and items etc. can be edited and replaced with little editing of the actual source code. Basically, the user command is stored as a string which is immediately broken into a list. The first element is an action like 'inspect' and the second element is a pseudo-argument for that action like 'location' or 'item'. After the command is interpreted, it goes to the execution module called 'item_or_loc' It's here that I get the error. Can anyone help? I'll provide more info or the entire source code if it'll help.
Command module:
def item_or_loc(iolo):
if iolo in items.items_f():
print (items.iolo(1))
elif iolo in locations.locations_f():
print (locations.iolo(1))
else:
print ('Command not recognized, try again.')
def location(loco):
plo_l = PlayerClass #(player location object_location)
if loco == 'location':
plo_l.player_loc(0)
def abort(abo):
sys.exit()
def inventory(invo):
pio_i = PlayerClass #(player inventory object_inventory)
if invo == 'inventory':
pio_i.player_inv(0)
Items module:
patient_gown=('Patient gown', 'A light blue patient\'s gown.')
wrench=('Wrench','')
stick=('Stick','')
prybar=('Prybar','')
screwdriver=('Screwdriver','')
scalpel=('Scalpel','')
broken_tile=('Broken tile','')
hatchet=('Hatchet','')
janitor_suit=('Janitor suit','')
Locations module: Basically the same as the Items module
Player module:
import items
import locations
class PlayerClass:
def player_inv(inv_index):
pinventory = [items.patient_gown[inv_index]]
print (pinventory)
def player_loc(loc_index):
ploc = [locations.cell[loc_index]]
print (ploc)
You don't return anything from items.items_f. You need to return a container or sequence. I would advise a different approach from the below, but it's a start, at least.
def items_f():
patient_gown=('Patient gown','A light blue patient\'s gown.')
wrench=('','')
stick=('','')
crowbar=('','')
screwdriver=('','')
scalpel=('','')
broken_tile=('','')
hatchet=('','')
janitor_suit=('','')
return (patient_gown, wrench, stick, crowbar,
screwdriver, scalpel, broken_tile, hatchet, janitor_suit)
To explain, items_f is not a container itself, but is rather a function (or more precisely, a method, which you can think of simply as a function "attached" to an object). Functions don't have to return anything, but then when you call them, the value that results from the call is simply None.
Now, when you do a test like if x in y:, y has to be a sequence or container type; and since you're testing the result of the function items_f, and since that function returns None as you've defined it above, the test throws an error.
The best way to handle this situation really depends on the larger structure of the program. A first step in the right direction might be something like this:
def items_f():
return (('Patient gown', 'A light blue patient\'s gown.'),
('Wrench', 'A crescent wrench.'),
('Stick', '...'))
But that's probably not the best solution either. My suggestion based on what you've added above (which, by the way, is now missing the items_f function) would be to use a data structure of some kind that holds items. A simple approach would be a dictionary:
items = {'patient_gown':('Patient gown', 'A light blue patient\'s gown.'),
'wrench':('Wrench', '...'),
...
}
This creates a dictionary that contains all possible items. Now when you want a particular item, you can get it like so:
item = items['patient_gown']
This way you don't need a function at all; you can just access the whole dictionary directly.