I’m trying to write a Database Abstraction Layer in Python which lets you construct SQL statments using chained function calls such as:
results = db.search("book")
.author("J. K. Rowling")
.price("<40.00")
.title("Harry")
.execute()
but I am running into problems when I try to dynamically add the required methods to the db class.
Here is the important parts of my code:
import inspect
def myName():
return inspect.stack()[1][3]
class Search():
def __init__(self, family):
self.family = family
self.options = ['price', 'name', 'author', 'genre']
#self.options is generated based on family, but this is an example
for opt in self.options:
self.__dict__[opt] = self.__Set__
self.conditions = {}
def __Set__(self, value):
self.conditions[myName()] = value
return self
def execute(self):
return self.conditions
However, when I run the example such as:
print(db.search("book").price(">4.00").execute())
outputs:
{'__Set__': 'harry'}
Am I going about this the wrong way? Is there a better way to get the name of the function being called or to somehow make a ‘hard copy’ of the function?
You can simply add the search functions (methods) after the class is created:
PS: This class has an
__init__()method that does not have thefamilyparameter (the condition setters are dynamically added at runtime, but are added to the class, not to each instance separately). IfSearchobjects with different condition setters need to be created, then the following variation on the above method works (the__init__()method has afamilyparameter):Reference: http://docs.python.org/howto/descriptor.html#functions-and-methods
If you really need search methods that know about the name of the attribute they are stored in, you can simply set it in
make_set_condition()with(just before the
return set_cond). Before doing this, methodSearch.namehas the following name:after setting its
__name__attribute, you get a different name:Setting the method name this way makes possible error messages involving the method easier to understand.