I have the following function which takes 4 arguments (we don't know which are set and which aren't before runtime).
myFuct(self, arg1, arg2, arg3, arg4):
# db insert function for only those args that are set
Is there an efficient way of unraveling the set arguments in a mysql database with a single sql query?
P.S. I am looking for a pythonic way to do this without having to say if-this-then-that for a million times...
Thanks in advance.
Not entirely sure what you need.
def myfunc(*args, **kwargs):
...
Can take any number of arguments, is this what you're looking for?
print(*(1,2,3,4)) * "unravels" the arguments in the order they are given but can be passed as one object or any number of objects.
However, passing these into a SQL statement without knowing the precise length of the arguments. Since SQL to my knowledge is a bit strict on how you pass the arguments.
You could do something like:
def myfunc(*args):
statement = "INSERT INTO table VALUES(" + ', '.join(str(x) for x in args) + ");"
db.execute(statement)
Note of course that this can only be used if you actually pass arguments to myfunc that are of the correct type, order and length.
in postgresql you have something called a prepared statement which would come in handy here.
def myfunc(*args):
statement = "INSERT INTO table VALUES(" + ', '.join('$'+str(i) for i in range(0, len(args)+1)) + ");"
handle = db.prepare(statement)
handle(args)
Where you simply define $1, $2 and so on in the prepared statement and then pass the equivilant number of arguments to the handler which will execute the query with the correct format on each of the values enabling you to pass integers, strings and arrays.. any way you like :)
Also, if the argument is a dictionary (mentioned in a comment)...
You'd have to do:
def myfunc(*args):
keys = ', '.join(str(x) for x in list(args.keys()))
values = ', '.join(str(val) for k, val in list(args.items()))
statement = "INSERT INTO table (" + keys + ") VALUES(" + values + ");"
db.execute(statement)
Again, assumes the dictionary is passed with proper variables for a execution to proceed.
You can use variable-length argument list construct:
def myfunc(*args):
args_non_empty = [a for a in args if a]
This allows you to pass any number of argument to your method. You can easily then filter them by traversing the list.
Related
Beginner issue here. I am sure there is a more pythonic way of doing this. basically I need to create a string using the contents of a list and a dict, plus I need to insert constants. I am trying to produce a end product for a function call via Eval. My current code works but it smells of 1980s BASIC (which ages me). I've looked at .join, zip and itter package but with no luck.
The list (argumentlist) contains argument names (such as open, close, length) and the dict (self.indicator_paremeters) contains all potential argument names along with their default value. So for example within the dict there is a key 'length' and its default value. In addition I need to concatenate '+' and commas, to create the end string.
Here is code sample to date.
def loop_thru_arguement_list_to_create_end_string(self, argument, resultant_argument_string):
if resultant_argument_string == "":
resultant_argument_string = argument + ' = ' + str(self.indicator_paremeters.get(
argument))
else:
resultant_argument_string = resultant_argument_string + ", " + argument + ' = ' + str(
self.indicator_paremeters.get(
argument))
return resultant_argument_string
This function is called from the loop here (need to rename that function):
def extract_argument_list_from_function(self, fullarguments) -> str:
resultant_argument_string = ""
argumentlist = fullarguments[0]
for argument in argumentlist:
resultant_argument_string = self.loop_thru_arguement_list_to_create_end_string(argument,
resultant_argument_string)
return resultant_argument_string
fullarguments = is a dict from a inspect.getfullargspec call. I only want the args, hence the [0].
All methods above are in a wider class.
self.indicator_paremeters is the dict holding all potential arguments.
The code above works fine but just doesn't feel right. Its the IF statement in particular which doesn't feel pythonic.
In my opinion you just need this:
def extract_argument_list_from_function(self, fullarguments: List) -> str:
res = ''
for arg in fullarguments[0]:
param = self.indicator_paremeters.get(arg)
res = f'{res}, {arg} = {param}' if res else f'{arg} = {param}'
return res
you can delete the loop_thru_arguement_list_to_create_end_string method
So, I have the following function which should resemble the already implemented " print " function in Python. ( I know it is silly to make a function that only uses a pre-defined function but I am practicing with different things ) The thing that I want to do with my function is: make it act the same as the pre-defined one. That is, when the print function is called with no parameters, I would like it to print an empty line just as " print() " does. How do i do that ?
def print_str( string, how_many_times, tail ):
print ( string * how_many_times, end = tail )
print doesn't take a single string, it takes 0 or most strings as argument. end has a reasonable default. You can imagine a (simplified) definition of
def print(*args, end='\n'):
...
You need to do the same for yours. A reasonable default for how_many_times would be 1. If you don't want print_str to take multiple arguments, "" would be a reasonable default for string.
def print_str(string="", how_many_times=1, tail='\n'):
print(string * how_many_times, end=tail)
You can do something like this:
def myfunc(a=None):
if a == None:
print()
else:
print("hi")
If no arguments are presented it prints nothing, but if an argument is given it prints 'hi'.
This question already has answers here:
SQLite parameter substitution problem
(8 answers)
Closed 6 years ago.
So I have a table in my Customers.db file that looks like this:
I wanted to make a function which returns the "rows" which has the id equal to the user input. The Table is also called 'Customers and all the columns are type TEXT.
def run_query(db, query, args=NONE):
con = sqlite3.connect(db)
cur = con.cursor()
if args is None:
cur.execute(query)
else:
cur.execute(query, args)
data = cur.fetchall()
cur.close()
con.close()
return data
def get_info_by_id(db, ide):
query = "SELECT * FROM Customers WHERE id = ?"
return run_query(db, query, ide)
When I ran this in the shell like this
get_info_by_id('Customers.db', '920')
I get the error "sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 3 supplied."
You need to update your run_query function as:
def run_query(db, query, *args):
# ^ *args here for variable number of arguments
# It will read additional arguments as tuples
..
cur.execute(query, args) # No need of if-else now
.. # It expects arguments to be in tuple format
For more information related to *args, take a look at: What does asterisk * mean in Python?
The args argument of cur.execute needs to be an iterable so that they can be bound to multiple placeholders (?) if necessary. Therefore you should always be passing a list or tuple.
get_info_by_id('Customers.db', ['920'])
When you pass a string it gets treated as an iterable of single-character strings, hence it says there were 3 bindings (3 characters in '920').
So I have a database with 10 fields(call them a, b, c....j), and I need to create a function "find_use()" that can find and modify records in the database based on any combination of fields given to it as arguments ( ie: find_use(a=="happy", g =="birthday") ). Also, due to privileges, I am not generating the SQL queries directly, but instead use an SQL wrapper the system provides called "selector()" which will locate records based on the same arguments, ie: query = selector(a=="happy", g=="birthday"), which would then return a list of the matching records
So the problem is, since I don't know what arguments find_use() will be receiving, I don't know how to structure the inner call to selector(). Ideally, the call to selector should be created dynamically; something to the effect of:
def find_use(a='',b='',c='',.....j=''):
vars = locals()
for v in vars:
if v.value() != '':
q_string += '{0} == {1},'.format(v.key(),v.value())
query = selector(q_string)
...do something to query...
This, however, will not work since selector does not take a string, but rather arguments in the same format as the find_use() function. How, then, can this be done. I have the feeling this is actually really easy, and I'm just missing something obvious. Any input would be greatly appreciated.
I think you are looking for keyword argument unpacking:
def find_use(**kwargs):
query = selector(**kwargs)
...do something to query...
When defined this way, find_use can receive an arbitrary number of keyword arguments. The keyword arguments are collected in a dict, kwargs.
For example,
def foo(**kwargs):
print(kwargs)
foo(a = 'happy', g = 'birthday')
yields
{'a': 'happy', 'g': 'birthday'}
and if
def bar(a, g):
print(a)
print(g)
then
bar(**{'a': 'happy', 'g': 'birthday'}) # like selector(**kwargs)
yields
happy
birthday
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm learning Python and wanted to see if anyone could help break down and understand what this function does step by step?
def label(self, index, *args):
"""
Label each axes one at a time
args are of the form <label 1>,...,<label n>
APIPARAM: chxl
"""
self.data['labels'].append(
str('%s:|%s'%(index, '|'.join(map(str,args)) )).replace('None','')
)
return self.parent
It's a good idea to change the formatting, before trying to understand what it does:
def label(self, index, *args):
"""
Label each axes one at a time
args are of the form <label 1>,...,<label n>
APIPARAM: chxl
"""
self.data['labels'].append(
str( '%s:|%s' % \
( index, '|'.join( map( str,args ) ) )
).replace( 'None', '' )
)
return self.parent
So:
it appends something to self.data[ 'labels' ] list. We know this because append() is a method of list object.
This something is a string such that:
string is of the form xxx:|yyy
xxx is replaced with the value of argument index
yyy is replaced with all the other arguments converted to strings (map(str,args)) and joined with | character (join(...)) so resulting in something like 'a|b|None|c'
every occurence of None in the string above is replaced with an empty string and this is appended to the list
EDIT:
As #abarnert pointed out it might be good to explain what does *args mean and why later on it's used as args, so here it goes.
*args (which is an asterisk + an arbitrary name) means "any number of anonymous arguments available further in args list". One can also use **kwargs - note two asterisk which is used for accepting keyworded arguments, i.e. ones passed to the function in the form of foo = bar where foo is the name of the argument and bar is its value rather than just bar.
As said above args and kwargs are arbitrary, one could just as well use *potatoes or **potatoes but using args and kwargs is a convention in Python (sometimes people also use **kw instead of **kwargs, but the meaning is the same - any number of anonymous and any number of keyworded arguments respectively).
Both are used if the number of arguments which the function/method should accept is not known beforehand - consider for a example a function which processes names of the party guests, one may not know how many there may be, so defining a following function makes sense:
def add_party_quests( *quests ):
for guest in quests:
do_some_processing( guest )
Then both calls below are valid:
add_party_guests( 'John' )
add_party_guests( 'Beth', 'Tim', 'Fred' )
This is also explained in this SO post: https://stackoverflow.com/a/287101/680238
I assume the misleading lines are:
self.data['labels'].append(
str('%s:|%s'%(index, '|'.join(map(str,args)) )).replace('None','')
)
Those can be formatted more clearly to aid reading:
self.data['labels'].append(
str('%s:|%s' % (
index,
'|'.join(map(str, args))
)).replace('None', '')
)
But can be better rewritten as:
self.data['labels'].append( # append to the list at `self.data['labels']`
'%s:|%s' % ( # a string of the format X:|Y
index, # where X is the index
'|'.join( # and Y is a list joined with '|'s
str(arg) if arg is not None else # with each item in the list
'' for arg in args # being it's string representation
)
)
)
*args turns into a list of arguments called args. self.data['labels'] looks to be a list. .append adds an item to the list. The item appended is returned by the string returned by the right most part, replace. To parse what string that is, start inside the parens and work your way out. map(str,args) converts all the args to strings and returns that list. '|'.join( takes the output of map and joins it into a single string, of the general pattern elem1|elem2|elem3..., it then uses the format string '%s:|%s'. The first %s gets replaced by the value of index, the second by the string output by '|'.join. It then calls replace on this string, replacing all occurences of 'None' with ''. Then it returns self.parent.