21.3 Writing your own Functors in Python

Deriving new instances of OEUnaryFunctions and OEUnaryPredicates requires C++, but for many cases, a special case of these has been instantiated for atoms and bonds. OEPyAtomPredicate and OEPyBondPredicate are special case predicates that take a Python function as the single argument. In essence, we are creating a callback that itself holds a callback. This Python function must be defined a certain way. First, it can only take a single argument, an atom for an OEPyAtomPredicate and a bond for an OEPyBondPredicate. Second, it must return 1 if the atom(bond) satisifies the condition and 0 otherwise. Since it may sometimes be necessary to create predicates that hold state, a class instance method can be used. Just make sure that the method (to which a pointer will be stored inside the C++ predicate) stays in scope while the predicate is used.

The following example shows a user defined functor which screens for atoms whose atomic mass is greater than 15.

#!/usr/bin/env python
# ch21-2.py

from openeye.oechem import *

def AtomWgtGT15(atom):
    if OEGetAverageWeight(atom.GetAtomicNum())>15:
        return 1
    return 0

WeightGT15 = PyAtomPredicate(AtomWgtGT15)

mol = OEGraphMol()
OEParseSmiles(mol, "c1c(O)c(O)c(Cl)cc1CCCBr")
OETriposAtomNames(mol)

for atom in mol.GetAtoms(WeightGT15):
    print atom.GetName(), "has weight > 15."