Pythonic shortcut (syntax sugar) for nested self.__parent__.__parent__ - python

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.

Related

Proper way to handle an empty Stack when implementing a peek() method in Python

When implementing a stack using Python, what is the conventional way to handle an operation on an empty stack?
I have the following stack.peek method of a simple stack class implemented using a Python list:
def peek(self):
if not self.empty:
return self.items[-1]
If the stack is empty, is it better to return a None type value or raise an error? I don't like the idea of returning a string stating that "the stack is empty" which is how all of the data structure books I've referenced demonstrate. What is the conventional way to handle this in production code?
Raising an exception is more appropriate than returning anything. Btw, you might consider subclassing list to cover the typical push, pop, and peek:
class Stack(list):
push = list.append
peek = lambda self: self[-1]

Recursion in dict

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.

python .get() and None

I love python one liners:
u = payload.get("actor", {}).get("username", "")
Problem I face is, I have no control over what 'payload' contains, other than knowing it is a dictionary. So, if 'payload' does not have "actor", or it does and actor does or doesn't have "username", this one-liner is fine.
Problem of course arises when payload DOES have actor, but actor is not a dictionary.
Is there as pretty a way to do this comprehensively as a one liner, and consider the possibility that 'actor' may not be a dictionary?
Of course I can check the type using 'isinstance', but that's not as nice.
I'm not requiring a one liner per se, just asking for the most efficient way to ensure 'u' gets populated, without exception, and without prior knowledge of what exactly is in 'payload'.
Using EAFP
As xnx suggested, you can take advantage of the following python paradigm:
Easier to ask for forgiveness than permission
you can use it on KeyErrors as well:
try:
u = payload["actor"]["username"]
except (AttributeError, KeyError):
u = ""
Using a wrapper with forgiving indexing
Sometimes it would be nice to have something like null-conditional operators in Python. With some helper class this can be compressed into a one-liner expression:
class Forgive:
def __init__(self, value = None):
self.value = value
def __getitem__(self, name):
if self.value is None:
return Forgive()
try:
return Forgive(self.value.__getitem__(name))
except (KeyError, AttributeError):
return Forgive()
def get(self, default = None):
return default if self.value is None else self.value
data = {'actor':{'username': 'Joe'}}
print(Forgive(data)['actor']['username'].get('default1'))
print(Forgive(data)['actor']['address'].get('default2'))
ps: one could redefine __getattr__ as well besides __getitem__, so you could even write Forgive(data)['actor'].username.get('default1').
Why not use an Exception:
try:
u = payload.get("actor", {}).get("username", "")
except AttributeError:
u = ""
The answer hege_hegedus gave is correct, however there's one caveat in that exception handling is a lot slower than going through if..else statement.
For example if you're iterating over thousands of payload object and an actor entry is only occasionally not a dictionary, this code is perfectly valid.
However if you're iterating over thousands of payload objects and every other actor entry is not a dictionary then you'd be better off with this code.
u = ''
if 'actor' in payload and isinstance(payload['actor'], dict):
u = payload['actor'].get('username', '')
For more discussion go here -- https://mail.python.org/pipermail/tutor/2011-January/081143.html
UPDATE
Also the code statement can be re-written as a one-liner albeit not nearly as legible as two-line statement
u = payload['actor'].get('username', '') if 'actor' in payload and isinstance(payload['actor'], dict) else ''
If you really need to do it in 1 line, you'll have to implement the functionality yourself. Which is worth doing if you use this semantics many times in your program.
There are two ways to do it: function or custom dictionary-like object for payload.
1) Function handles the case of actor being not a dict. It can check for isinstance or do the try or whatever else -- it's not essential. The usage would look something like u = get("username", "", payload.get("actor", {})) or u = get("", payload, 'actor', 'username') (with arbitrary amount of nested calls for items in payload).
2) A class of custom objects is a powerful thing -- do it if you can and really need this abstraction in the program. A descendant of dict or UserDict (in Python3) can check for what it stores or outputs on __getitem__ calls.

Resolve overloading in Python

I know Python doesn't support overloading, but I'm not sure how to do the following task in Python without resorting to different method names.
I have two methods which require different set of parameters:
def get_infobox_from_list(templates):
for template in templates:
if get_base_length(template[0]) >= 0:
return template
return None
def get_infobox(site, name):
# first try box template
infobox = get_infobox_from_list(get_templates(site, "{}/Box".format(name)))
if infobox is None:
infobox = get_infobox_from_list(get_templates(site, name))
return infobox
Both methods do similar things (they get you a template), but their parameters are different. Now I've read that Python is usually allowing this by using default arguments.
That might be helping sometimes, but the difference is, that the method either needs two parameters (site and name) or one (templates) but no other combination (like site and templates, only name, only site, name and templates or all three).
Now in Java I could simply define those two overloading methods. So if somebody is calling either one of them their parameters must match without defining to many or to few. So my question is, how should it be done in Python really.
You could try using *args:
def get_infobox_from_list(*args):
if len(args) == 1:
return _get_infobox_from_list_template(*args)
else:
return _get_infobox_from_list_sitename(*args)
Then you can define the two similar sub-functions. But this is pretty awkward, and suggests that two separate methods with different names might be a better fit.
You could use a "wrapper" method (not sure what the correct terminology here is) that passes the parameters along to the correct version of the get_infobox_... function.
def get_infobox(site=None, name=None, templates=None):
if site is not None and name is not None and templates is None:
get_infobox_from_site_and_name(site, name)
elif templates is not None and site is None and name is None:
get_infobox_from_list(templates)
else:
raise Exception # or some particular type of exception
However, I imagine there is a better way to accomplish what you want to do - I've never found a need to resort to a pattern like this in Python. I can't really suggest a better option without understanding why you want to do this in greater detail, though.

pythonic way to rewrite an assignment in an if statement

Is there a pythonic preferred way to do this that I would do in C++:
for s in str:
if r = regex.match(s):
print r.groups()
I really like that syntax, imo it's a lot cleaner than having temporary variables everywhere. The only other way that's not overly complex is
for s in str:
r = regex.match(s)
if r:
print r.groups()
I guess I'm complaining about a pretty pedantic issue. I just miss the former syntax.
How about
for r in [regex.match(s) for s in str]:
if r:
print r.groups()
or a bit more functional
for r in filter(None, map(regex.match, str)):
print r.groups()
Perhaps it's a bit hacky, but using a function object's attributes to store the last result allows you to do something along these lines:
def fn(regex, s):
fn.match = regex.match(s) # save result
return fn.match
for s in strings:
if fn(regex, s):
print fn.match.groups()
Or more generically:
def cache(value):
cache.value = value
return value
for s in strings:
if cache(regex.match(s)):
print cache.value.groups()
Note that although the "value" saved can be a collection of a number of things, this approach is limited to holding only one such at a time, so more than one function may be required to handle situations where multiple values need to be saved simultaneously, such as in nested function calls, loops or other threads. So, in accordance with the DRY principle, rather than writing each one, a factory function can help:
def Cache():
def cache(value):
cache.value = value
return value
return cache
cache1 = Cache()
for s in strings:
if cache1(regex.match(s)):
# use another at same time
cache2 = Cache()
if cache2(somethingelse) != cache1.value:
process(cache2.value)
print cache1.value.groups()
...
There's a recipe to make an assignment expression but it's very hacky. Your first option doesn't compile so your second option is the way to go.
## {{{ http://code.activestate.com/recipes/202234/ (r2)
import sys
def set(**kw):
assert len(kw)==1
a = sys._getframe(1)
a.f_locals.update(kw)
return kw.values()[0]
#
# sample
#
A=range(10)
while set(x=A.pop()):
print x
## end of http://code.activestate.com/recipes/202234/ }}}
As you can see, production code shouldn't touch this hack with a ten foot, double bagged stick.
This might be an overly simplistic answer, but would you consider this:
for s in str:
if regex.match(s):
print regex.match(s).groups()
There is no pythonic way to do something that is not pythonic. It's that way for a reason, because 1, allowing statements in the conditional part of an if statement would make the grammar pretty ugly, for instance, if you allowed assignment statements in if conditions, why not also allow if statements? how would you actually write that? C like languages don't have this problem, because they don't have assignment statements. They make do with just assignment expressions and expression statements.
the second reason is because of the way
if foo = bar:
pass
looks very similar to
if foo == bar:
pass
even if you are clever enough to type the correct one, and even if most of the members on your team are sharp enough to notice it, are you sure that the one you are looking at now is exactly what is supposed to be there? it's not unreasonable for a new dev to see this and just fix it (one way or the other) and now its definitely wrong.
Whenever I find that my loop logic is getting complex I do what I would with any other bit of logic: I extract it to a function. In Python it is a lot easier than some other languages to do this cleanly.
So extract the code that just generates the items of interest:
def matching(strings, regex):
for s in strings:
r = regex.match(s)
if r: yield r
and then when you want to use it, the loop itself is as simple as they get:
for r in matching(strings, regex):
print r.groups()
Yet another answer is to use the "Assign and test" recipe for allowing assigning and testing in a single statement published in O'Reilly Media's July 2002 1st edition of the Python Cookbook and also online at Activestate. It's object-oriented, the crux of which is this:
# from http://code.activestate.com/recipes/66061
class DataHolder:
def __init__(self, value=None):
self.value = value
def set(self, value):
self.value = value
return value
def get(self):
return self.value
This can optionally be modified slightly by adding the custom __call__() method shown below to provide an alternative way to retrieve instances' values -- which, while less explicit, seems like a completely logical thing for a 'DataHolder' object to do when called, I think.
def __call__(self):
return self.value
Allowing your example to be re-written:
r = DataHolder()
for s in strings:
if r.set(regex.match(s))
print r.get().groups()
# or
print r().groups()
As also noted in the original recipe, if you use it a lot, adding the class and/or an instance of it to the __builtin__ module to make it globally available is very tempting despite the potential downsides:
import __builtin__
__builtin__.DataHolder = DataHolder
__builtin__.data = DataHolder()
As I mentioned in my other answer to this question, it must be noted that this approach is limited to holding only one result/value at a time, so more than one instance is required to handle situations where multiple values need to be saved simultaneously, such as in nested function calls, loops or other threads. That doesn't mean you should use it or the other answer, just that more effort will be required.

Categories