Optional arguments with few mandatory arguments - python

I am new to python and came across a problem.
I have to get a dictionary from the user via a function that has few elements (key-value). At the same time, if the user is not providing the dictionary, they can provide individual elements as arguments.
How do I check if user has provided dictA, if not, src msg. If the user doesn't provides either one of them, return an error back to the calling function.
Lets say:
def myfunc(dictA, src, msg, e=True)
where dictA is the dictonary and src, msg are arguements if the user didn't provide dictA.

I wouldn't support them passing in dictA or the other arguments. I would just have them pass in dictA as kwargs if that want to use that. Then you can just check if the values have been there
New function prototype might be
def myfunc(src, msg, e=True)
And then usages could be
myfunc(a_source, a_msg)
Or
myfunc(**dictA)
This way your function will automatically check that those values are at least present. And any additional value checking can be done on only one input
For example the following call would fail (without you needing to do anything else) because it would still be missing the positional argument of msg.
myfunc(**{'src': 'a_source'})
Similarly it will fail if you send too many positional arguments as well (i.e. passing in a positional argument and a kwarg via a dictionary)

Related

Python ast - getting function parameters and processing them

I'm trying to use the ast module in Python to parse input code, but am struggling with a lot of the syntax of how to do so. For instance, I have the following code as a testing environment:
import ast
class NodeVisitor(ast.NodeVisitor):
def visit_Call(self, node):
for each in node.args:
print(ast.literal_eval(each))
self.generic_visit(node)
line = "circuit = QubitCircuit(3, True)"
tree = ast.parse(line)
print("VISITOR")
visitor = NodeVisitor()
visitor.visit(tree)
Output:
VISITOR
3
True
In this instance, and please correct me if I'm wrong, the visit_Call will be used if it's a function call? So I can get each argument, however there's no guarantee it will work like this as there are different arguments available to be provided. I understand that node.args is providing my arguments, but I'm not sure how to do things with them?
I guess what I'm asking is how do I check what the arguments are and do different things with them? I'd like to check, perhaps, that the first argument is an Int, and if so, run processInt(parameter) as an example.
The value each in your loop in the method will be assigned to the AST node for each of the arguments in each function call you visit. There are lots of different types of AST nodes, so by checking which kind you have, you may be able to learn things about the argument being passed in.
Note however that the AST is about syntax, not values. So if the function call was foo(bar), it's just going to tell you that the argument is a variable named bar, not what the value of that variable is (which it does not know). If the function call was foo(bar(baz)), it's going to show you that the argument is another function call. If you only need to handle calls with literals as their arguments, then you're probably going to be OK, you'll just look instances of AST.Num and similar.
If you want to check if the first argument is a number and process it if it is, you can do something like:
def visit_Call(self, node):
first_arg = node.args[0]
if isinstance(first_arg, ast.Num):
processInt(first_arg.n)
else:
pass # Do you want to do something on a bad argument? Raise an exception maybe?

Dynamically update all instances of multiple input function

I'm creating a program with a class that has 3 input attributes. The program calls a function that creates many of these objects with their inputs being given based on some other criteria not important to this question.
As I further develop my program, I may want to add more and more attributes to the class. This means that I have to go and find all instances of the function I am using to create these objects, and change the input arguments.
For example, my program may have many of these:
create_character(blue, pizza, running)
where inputs correspond to character's favorite color, food, and activity. Later, I may want to add a fourth input, such as favorite movie, or possibly a fifth or sixth or ninety-ninth input.
Do professional programmers have any advice for structuring their code so that they don't have to go through and individually change each line that the create_character function is called so that it now has the new, correct number of inputs?
Find and replace seems fine, but this makes error possible, and also seems tedious. I'm anticipating calling this function at least 50 times.
I can think of a few options for how you could design your class to make easier to extend later new kinds of "favorite" things.
The first approach is to make most (or all) of the arguments optional. That is, you should specify a default value for each one (which might be None if there's not a real value that could apply as a default). This way, when you add an extra argument, the existing places that call the function without the new argument will still work, they'll just get the default value.
Another option would be to use a container (like a dictionary) to hold the values, rather than using a separate variable or argument for each one. For instance, in your example could represent the character's favorites using a dictionary like favorites = {'color': blue, 'food': pizza, 'activity': running} (assuming the those values are defined somewhere), and then you could pass the dictionary around instead of the separate items. If you use the get method of the dictionary, you can also make this type of design use default values (favorites.get('movie') will return None if you haven't updated the code that creates the dictionary to add a 'movie' key yet).
You can take advantage of argument/keyword argument unpacking to support dynamically-changing function parameters. And also factory function/classes that generate the function you need:
def create_character(required1, required2, *opt_args, **kwargs):
""" create_character must always be called with required1 and required2
but can receive *opt_args sequence that stores arbitrary number of
positional args. kwargs hold a dict of optional keyword args """
for i, pos_arg in enumerate(opt_args):
# pos_arg walks opt_args sequence
print "position: {}, value: {}".format(i+3, pos_arg)
for keyword, value in kwargs:
print "Keyword was: {}, Value was: {}".format(keyword, value)
pos_args = (1,2,3)
create_character('this is required','this is also required', *pos_args)
""" position: 3, value: 1
position: 4, value: 2
position: 5, value: 3 """
a_dict = {
'custom_arg1': 'custom_value1',
'custom_arg2': 'custom_value2',
'custom_arg3': 'custom_value3'
}
create_character('this is required','this is also required', **a_dict)
""" Keyword was: custom_arg2, value: custom_value2
Keyword was: custom_arg3, value: custom_value3
Keyword was: custom_arg1, value: custom_value1 """
I really like the list or dictionary input method, but it was still messy and allowed for the possibility of error. What I ended up doing was this:
I changed the class object to have no inputs. Favorites were first assigned with random, default, or unspecified options.
After the class object was created, I then edited the attributes of the object, as so:
self.favorite_movie = "unspecified"
self.favorite_activity = "unspecified"
new_character = (character())
new_character.favorite_movie = "Dr. Strangelove"
I think that the downside to this approach is that it should be slower than inputting the variables directly. The upside is that this is easy to change in the future. Perhaps when the program is finished, it will make more sense to then convert to #Blckknight 's method, and give the input as a list or dictionary.

Argparse optional required arguments produce error if missing, but the action is still performed

I have the following snippet:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--p', required=True)
parser.add_argument('arg', action=MyAction)
parser.parse_args()
, where MyAction is a simple custom action class.
As you see, I want to enforce the presence of the p argument. However, my action is performed even if the argument is not present, and then an error message is shown that indicates the fact the the argument is missing.
Obviously, I could check in my action class for the presence of the p argument, but this defies the purpose of having a required parameter in the first place. Why is my action being run if the argument is not present?
Parsing is driven by the commandline strings, and tries to be order agnostic. Within those rules, it alternates between parsing an optional and a positional.
For example, with myprog --p one two:
'--p' - pass the 'one' string to the p action (e.g. setattr(namespace, 'p', 'one')
'two' - matches the nargs for 'arg'. Calls your MyAction.__call__ with values='one'.
at the end of parsing it checks if all required actions have been 'seen'. With your setup both '--p' and 'arg' are required.
With myprog two --p one it does the same, except arg is processed first. The namespace may have a default value for p.
With myprog two, arg is processed, and the required test will raise an error. error: the following arguments are required: --p
Since you have written a custom Action, you can easily explore how the namespace contents vary depending on the commandline arguments and their order.
So the --p and the arg will be processed independently, and in either order, depending on the commandline strings. required testing is performed at the end, using a list of seen_actions. And default values are set at the start of parsing. It is difficult to implement reliable inter-action tests within custom Actions. Usually it is better to perform such tests after parsing.
The defined Actions only change the args namespace. So parsing does not change anything beyond what it returns. Unless there's an error and it forces an sys.exit. A custom MyAction class can change that, but at your own risk.

How to give key_prefix, variable values while caching in Flask-Cache

We can cache any view/non-view function as
#cache.cached(timeout=50, key_prefix='all_comments')
Can we give key_prefix some variable values. Let say, I'm caching a function as
#cache.cached(timeout=50, key_prefix=value)
def get_all_comments(value):
Can we give key_prefix as the same arguments as we are getting in function. If not argument, then atleast some other variable by any proper way.
In the docs it says
New in version 0.3.4: Can optionally be a callable which takes no arguments but returns a string that will be used as the cache_key.

Detect an invalid keyword argument

I have the following function:
def foo(**kwargs):
if not kwargs:
# No keyword arguments? It's all right. Set defaults here...
elif ('start_index' or 'end_index') in kwargs:
# Do something here...
else:
# Catch unexpected keyword arguments
raise TypeError("%r are invalid keyword arguments" % (kwargs.keys())
Question:
I want to make sure that the only valid keyword arguments are start_index or end_index. Anything else will raise an error, even if mixed with the valid ones. What's the cookbook recipe to make sure that only start_index or end_index are accepted? Yes, I'm looking for a cookbook recipe but I'm not sure how to search for it. I'm not sure if using an if-elif-else structure is the correct way to do it either.
Why do you need **kwargs here? Just
def foo(start_index=None, end_index=None):
and Python will perform all validation for you.
For the sake of completeness, Here's an alternative that still uses **kwargs.
def foo(**kwargs):
start_index = kwargs.pop('start_index', STARTINDEX_DEFAULT)
end_index = kwargs.pop('end_index', ENDINDEX_DEFAULT)
if kwargs:
# Catch unexpected keyword arguments
raise TypeError("%r are invalid keyword arguments" % (kwargs.keys())
# Do something here...
But, you shouldn't want to use this when you don't absolutely need it, use regular parameters with default values (as in Roman Bodnarchuk's answer).
Cases when you might need this is when you also want to use *args, and need a way to distinguish the keyword arguments from arbitrarily man positional arguments. using **kwargs this way forces the keyword arguments to be passed as keywords; A positional argument can never find its way into **kwargs.
Another reason is so that you can really distinguish between a default and an explicit parameter which happens to be the default. None is often used as a default value for arguments to indicate "the argument doesn't apply", but sometimes you actually need to interpret the None as something other than a default. Checking for the presence or absence of a key in the **kwargs dict can accurately distinguish between these cases. (An alternative is to create an instance of a subclass of object whos sole purpose is to be the default value of a specific argument to that specific function)
If you really want to use **kwargs, I'd write that like:
def foo(**kwargs):
# Define default values for all keys
args = {'start_index': 0, 'end_index': -1}
# Get the keys passed in that aren't in args
extraargs = set(kwargs) - set(args)
if extraargs:
raise TypeError("Invalid arguments: %s" % list(extraargs))
# Overwrite the default values with the passed-in values
args.update(kwargs)
# Now, do stuff with the values in args
But all of that is a complicated, slow way to duplicate built-in functionality. Don't do that unless you really need to.
In any case getting keys from a dict is as easy as using .get e.g.
kwargs.get('WIDTH',500)
this way if it doesn't find WIDTH as a key you get 500.

Categories

Resources