Python - How do I write a more efficient, Pythonic reduce? - python

I'm trying to build a very lightweight Node class to serve as a Python-based hierarchy search tool. See the definition below.
from functools import reduce
from operator import or_
class Node:
def __init__(self, name):
self.name = name
self.children = []
def add_child(self, child_node):
self.children.append(child_node)
def contains(self, other_node):
if self == other_node:
return True
elif other_node in self.children:
return True
else:
return reduce(or_, [child.contains(other_node)
for child in self.children], False)
def is_contained_by(self, other_node):
return other_node.contains(self)
def __eq__(self, other_node):
return self.name == other_node.name
def __de__(self, other_node):
return self.name != other_node.name
contains seems to be a textbook case of functional programming (pulled directly from Why Functional Programming Matters).
Question: is there a more efficient or Pythonic way of writing contains? I know that map is usually replaced by list comprehension, but I hadn't seen a better way of doing reduce-based recursion.
Thanks,
Mike
===EDITED ... HERE'S THE REDONE CLASS TAKING INTO ACCOUNT THE ANSWER AND COMMENTS===
class Node:
def __init__(self, name):
self.name = name
self.children = []
def add_child(self, child_node):
# Hattip to lazyr for catching this.
if self.contains(child_node) or child_node.contains(self):
raise TreeError('A relationship is already defined.')
else:
self.children.append(child_node)
def contains(self, other_node):
# Hattip to lazyr for pointing out any() and to Jochen Ritzel for
# eliminating the silly child check.
return (self == other_node or
any(child.contains(other_node) for child in self.children))
def is_contained_by(self, other_node):
return other_node.contains(self)
def __eq__(self, other_node):
return self.name == other_node.name
def __de__(self, other_node):
return self.name != other_node.name
def __repr__(self):
return self.name

I think (not tested) that you instead of reduce should use any like this, which will stop on the first hit:
return any(child.contains(other_node) for child in self.children)
By the way, did you mean for a.contains(b) to return False when a == b and len(a.children) > 0?
Edit: If your tree contains a loop, like this:
a = Node("a")
b = Node("b")
a.add_child(a)
a.add_child(b)
then
a.contains(b)
will crash the program. You may want to check for this either in contains or in add_child, depending on which you use the most.

Related

recursion of objects and methods in python

I wanna create a class which consist of parents and children and a recursion method to call the last child :
class MyClass:
def __init__(self,val,child =None):
self.val = val
self.child = child
def findLastChildVal(self):
if self.child ==None:
return self.val
return (...)
c = MyClass("I'm child")
p = MyClass("I'm parent",c)
p.findLastChildVal()
I have no Idea what to write instead of (...). It's confusing.
This is a classic recursion problem, in my opinion it will be much easier to use a static function instead of a member function:
class MyClass:
def __init__(self, val, child =None):
self.val = val
self.child = child
#staticmethod
def find_last_child_val(current_node: MyClass):
if current_node.child == None:
return current_node.val
else:
return MyClass.find_last_child_val(current_node.child)
c = MyClass("I'm child")
p = MyClass("I'm parent", c)
MyClass.find_last_child_val(p)
Update:
Pay attention that searching for a child using a recursion like this, is not efficient. find_last_child_val() runs in O(n) complexity. It is much more efficient to perform n iterations in a for loop instead of a recursion. If you can't think of a way to reduce the tree traversal complexity, I suggest using a different data structure.

Generalized __eq__() method in Python

I'd like to create a generalized __eq__() method for the following Class. Basically I'd like to be able to add another property (nick) without having to change __eq__()
I imagine I can do this somehow by iterating over dir() but I wonder if there is a way to create a comprehension that just delivers the properties.
class Person:
def __init__(self, first, last):
self.first=first
self.last=last
#property
def first(self):
assert(self._first != None)
return self._first
#first.setter
def first(self,fn):
assert(isinstance(fn,str))
self._first=fn
#property
def last(self):
assert(self._last != None)
return self._last
#last.setter
def last(self,ln):
assert(isinstance(ln,str))
self._last=ln
#property
def full(self):
return f'{self.first} {self.last}'
def __eq__(self, other):
return self.first==other.first and self.last==other.last
p = Person('Raymond', 'Salemi')
p2= Person('Ray', 'Salemi')
You could use __dict__ to check if everything is the same, which scales for all attributes:
If the objects are not matching types, I simply return False.
class Person:
def __init__(self, first, last, nick):
self.first = first
self.last = last
self.nick = nick
def __eq__(self, other):
return self.__dict__ == other.__dict__ if type(self) == type(other) else False
>>> p = Person('Ray', 'Salemi', 'Ray')
>>> p2= Person('Ray', 'Salemi', 'Ray')
>>> p3 = Person('Jared', 'Salemi', 'Jarbear')
>>> p == p2
True
>>> p3 == p2
False
>>> p == 1
False
You can get all the properties of a Class with a construct like this:
from itertools import chain
#classmethod
def _properties(cls):
type_dict = dict(chain.from_iterable(typ.__dict__.items() for typ in reversed(cls.mro())))
return {k for k, v in type_dict.items() if 'property' in str(v)}
The __eq__ would become something like this:
def __eq__(self, other):
properties = self._properties() & other._properties()
if other._properties() > properties and self._properties() > properties:
# types are not comparable
return False
try:
return all(getattr(self, prop) == getattr(other, prop) for prop in properties)
except AttributeError:
return False
The reason to work with the reversed(cls.mro()) is so something like this also works:
class Worker(Person):
#property
def wage(self):
return 0
p4 = Worker('Raymond', 'Salemi')
print(p4 == p3)
True
you can try to do this, it will also work if you want eq inside dict and set
def __eq__(self, other):
"""Overrides the default implementation"""
if isinstance(self, other.__class__):
return self.__hash__() == other.__hash__()
return NotImplemented
def __hash__(self):
"""Overrides the default implementation,
and set which fieds to use for hash generation
"""
__make_hash = [
self.first
]
return hash(tuple(sorted(list(filter(None, __make_hash)))))

How to implement selection sort using forward iterators?

I'm working on a homework assignment where I shall implement selection sorting using forward iterators for both python lists and linked lists(single).
Here are some codes I have for iterators:
from abc import *
class ForwardIterator(metaclass=ABCMeta):
#abstractmethod
def getNext(self):
return
#abstractmethod
def getItem(self):
return
#abstractmethod
def getLoc(self):
return
#abstractmethod
def clone(self):
return
def __eq__(self, other):
return self.getLoc() == other.getLoc()
def __ne__(self, other):
return not (self == other)
def __next__(self):
if self.getLoc() == None:
raise StopIteration
else:
item = self.getItem()
self.getNext()
return item
class ForwardAssignableIterator(ForwardIterator):
#abstractmethod
def setItem(self, item):
"""Sets the item at the current position."""
return
class PythonListFAIterator(ForwardAssignableIterator):
def __init__(self, lst, startIndex):
self.lst = lst
self.curIndex = startIndex
def getNext(self):
self.curIndex += 1
def getItem(self):
if self.curIndex < len(self.lst):
return self.lst[self.curIndex]
else:
return None
def setItem(self, item):
if self.curIndex < len(self.lst):
self.lst[self.curIndex] = item
def getLoc(self):
if self.curIndex < len(self.lst):
return self.curIndex
else:
return None
def clone(self):
return PythonListFAIterator(self.lst, self.curIndex)
The LinkedListFAIterator is similar to PythonListFAIterator, plus getStartIterator, and __iter__ method.
I don't know how I can write codes to implement selection sort with one paraemter, a FAIterator (the forward iterator). Please help me. I know I shall find the minimum element and put it at the beginning of the list. I also know that I shall use the clone method to create multiple iterators to keep track of multiple locations at once. But I don't know how to write the code.
Please give me some hints.

Create python functions from expression trees

I'm trying to create collection filters from expression trees (these would be generated from the GUI using wxpython tree controls). I would then use these filters with python's filter(func, iterable) method.
The challenge now is how can I create a function at runtime based on the rules found in the expression tree. An example of how such a function would look is:
def filterFunc(element):
if element == 'Apple' or element == 'Orange' or element == 'Duck':
return True
return False
The solution I'm currently thinking is to traverse the tree, generate a string containing actual Python code based on the tree contents(probably painful to code), and then call eval() on the resulting string.
Any advice or pointers on what would the correct/pythonic way to solve this would be much appreciated !
I'm assuming that your expression tree is composed of a number of objects, whose type corresponds with what kind of expression it is. Ex. Or, Equals, strings, etc. Something like this:
class OrExpression:
def __init__(self, left, right):
self.left = left
self.right = right
class EqualsExpression:
def __init__(self, left, right):
self.left = left
self.right = right
class Literal:
def __init__(self, value):
self.value = value
class Variable:
def __init__(self, name):
self.name = name
An expression equivalent to your example would look like this:
e = OrExpression(
EqualsExpression(
Variable("element"),
Literal("Apple")
),
OrExpression(
EqualsExpression(
Variable("element"),
Literal("Orange")
),
EqualsExpression(
Variable("element"),
Literal("Duck")
)
)
)
You could create a method eval for each class that evaluates itself for a given context. Like so:
class OrExpression:
def __init__(self, left, right):
self.left = left
self.right = right
def eval(self, variables):
return self.left.eval(variables) or self.right.eval(variables)
class EqualsExpression:
def __init__(self, left, right):
self.left = left
self.right = right
def eval(self, variables):
return self.left.eval(variables) == self.right.eval(variables)
class Literal:
def __init__(self, value):
self.value = value
def eval(self, variables):
return self.value
class Variable:
def __init__(self, name):
self.name = name
def eval(self, variables):
return variables[self.name]
Then you can call eval and supply the context. In your example, you only need to pass in the value of element.
print e.eval({"element": "Apple"})
print e.eval({"element": "Duck"})
print e.eval({"element": "Banana"})
Result:
True
True
False
But what if, instead, you don't differentiate kinds of expression by type? Suppose your tree is composed of plain old nodes, that identify what kind of expression they are using their value attribute. The code is approximately the same, just using a single monolithic switch case, instead of individual eval methods.
class Node:
def __init__(self, value=None, *children):
self.value = value
self.children = children
def evalTree(t, variables):
if t.value == "Or":
return evalTree(t.children[0], variables) or evalTree(t.children[1], variables)
elif t.value == "Equals":
return evalTree(t.children[0], variables) == evalTree(t.children[1], variables)
elif t.value == "Literal":
return t.children[0].value
elif t.value == "Variable":
name = t.children[0].value
else:
raise Exception("Unrecognized node type")
t = Node("Or",
Node("Equals",
Node("Variable", Node("element")),
Node("Literal", Node("Apple"))
),
Node("Or",
Node("Equals",
Node("Variable", Node("element")),
Node("Literal", Node("Apple"))
),
Node("Equals",
Node("Variable", Node("element")),
Node("Literal", Node("Apple"))
)
)
)
print evalTree(t,{"element": "Apple"})
print evalTree(t,{"element": "Duck"})
print evalTree(t,{"element": "Banana"})
Result:
True
True
False

Comparison of hashable objects

I have a tuple of python objects, from which I need a list of objects with no duplicates, using set() (this check for duplicate objects is to be done on an attribute.). This code will give a simple illustration:
class test:
def __init__(self, t):
self.t = t
def __repr__(self):
return repr(self.t)
def __hash__(self):
return self.t
l = (test(1), test(2), test(-1), test(1), test(3), test(2))
print l
print set(l)
However, it did not work. I can do it on an iteration over l, but any idea why set() is not working? Here is the official documentation.
From the documentation you linked to:
The set classes are implemented using dictionaries. Accordingly, the
requirements for set elements are the same as those for dictionary
keys; namely, that the element defines both __eq__() and __hash__().
To be more specific, if a == b then your implementation must be such that hash(a) == hash(b). The reverse is not required.
Also, you should probably call hash in __hash__ to handle long integers
class Test:
def __init__(self, t):
self.t = t
def __repr__(self):
return repr(self.t)
def __hash__(self):
return hash(self.t)
def __eq__(self, other):
return isinstance(other, Test) and self.t == other.t
Small nit picks:
Your implementation of __eq__ doesn't give the other object a chance to run its own __eq__. The class must also consider its members as immutable as the hash must stay constant. You don't want to break your dicts, do you?
class Test:
def __init__(self, t):
self._t = t
#property
def t(self):
return self._t
def __repr__(self):
return repr(self._t)
def __hash__(self):
return hash(self._t)
def __eq__(self, other):
if not isinstance(other, Test):
return NotImplemented # don't know how to handle `other`
return self.t == other.t

Categories