Regarding Function in Python - python

I am new to Python. I discover that in the arguments of e.g., annotate, it is allow to put xy=..., xytext=...., is it a feature of Python? If yes how do we define a function in python that allow this?
import numpy as np
from matplotlib import pyplot as plt
plt.annotate('Here is something special', xy = (2, 1), xytext=(1,5),arrowprops={'facecolor': 'r'})

This is a python's feature, called keyword parameters.
Functions can also be called using keyword arguments of the form "keyword = value". You can read about this topic in the documentation.
keyword arguments is not different than normal arguments except order isn't important. There is nothing special to do in the definition. For example:
def my_func(a, b):
pass
my_func(1, 2)
my_func(b=2, a=1)
# Both of them get the same results

I'm not sure if I completely understand what you want to do, but I think that this part of the Python documentation might answer your question:
https://docs.python.org/release/1.5.1p1/tut/keywordArgs.html

Related

Python: Correct way to test whether function/method signature has changed

I am currently developing an application (my_app) that uses logic from another python package (internal_package), that is being developed in parallel.
Lets say I use a function func1 from internal_package in my code. In internal_package, it is defined like this:
def func1(a, b):
# do something
...
However, If the function signature of func1 (i.e. the parameters with which the function is called) changes, lets say to
def func1(a, b, c):
# do something
...
My code would of course raise an Exception, since I did not pass parameter c.
To become aware of that immediately, I want to write a test in pytest. In my understanding, this kind of test is not a unit test, but an integration test.
My approach would be something like this:
import inspect
import internal_package
def test_func1_signature():
expected_signature = ? # not sure how to correctly provide the expected signature here
actual_signature = inspect.signature(internal_package.func1)
assert actual_signature == expected_signature
I would expect this to be a common issue, but I was not able to find anything related.
What would be the most pythonic way of performing this sort of test?
In case anyone is interested, I ended up using getfullargspec from the inbuilt inspect library. In the documentation it says:
Get the names and default values of a Python function’s parameters. A named tuple is returned:
FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)
As I am interested in in the args part, I retrieve them from func1 as follows:
inspect.getfullargspec(func1)[0]
Which then returns ['a', 'b']. I can then write a simple test in pytest like this:
import pytest
import inspect
def test_func1_signature:
expected_signature = ['a', 'b'] # I specify what i expect
actual_signature = inspect.getfullargspec(func1)[0]
assert actual_signature == expected_signature
If anyone knows a better/more pythonic/more correct way, please let me know.

initialize function and binding by iteration python [duplicate]

Do I have to formally define a function before I can use it as an element of a dictionary?
def my_func():
print 'my_func'
d = {
'function': my_func
}
I would rather define the function inline. I just tried to type out what I want to do, but the whitespace policies of python syntax make it very hard to define an inline func within a dict. Is there any way to do this?
The answer seems to be that there is no way to declare a function inline a dictionary definition in python. Thanks to everyone who took the time to contribute.
Do you really need a dictionary, or just getitem access?
If the latter, then use a class:
>>> class Dispatch(object):
... def funcA(self, *args):
... print('funcA%r' % (args,))
... def funcB(self, *args):
... print('funcB%r' % (args,))
... def __getitem__(self, name):
... return getattr(self, name)
...
>>> d = Dispatch()
>>>
>>> d['funcA'](1, 2, 3)
funcA(1, 2, 3)
You could use a decorator:
func_dict = {}
def register(func):
func_dict[func.__name__] = func
return func
#register
def a_func():
pass
#register
def b_func():
pass
The func_dict will end up mapping using the entire name of the function:
>>> func_dict
{'a_func': <function a_func at 0x000001F6117BC950>, 'b_func': <function b_func at 0x000001F6117BC8C8>}
You can modify the key used by register as desired. The trick is that we use the __name__ attribute of the function to get the appropriate string.
Consider using lambdas, but note that lambdas can only consist of one expression and cannot contain statements (see http://docs.python.org/reference/expressions.html#lambda).
e.g.
d = { 'func': lambda x: x + 1 }
# call d['func'](2) will return 3
Also, note that in Python 2, print is not a function. So you have to do either:
from __future__ import print_function
d = {
'function': print
}
or use sys.stdout.write instead
d = {
'function': sys.stdout.write
}
Some functions can be easily 'inlined' anonymously with lambda expressions, e.g.:
>>> d={'function': lambda x : x**2}
>>> d['function'](5)
25
But for anything semi-complex (or using statements) you probably just should define them beforehand.
There is no good reason to want to write this using a dictionary in Python. It's strange and is not a common way to namespace functions.
The the Python philosophies that apply here are:
There should be one-- and preferably only one --obvious way to do it.
Combined with
Readability counts.
Doing it this way also makes things hard to understand and read for the typical Python user.
The good things the dictionary does in this case is map strings to functions and namespace them within a dictionary, but this functionality is already provided by both modules and classes and it's much easier to understand by those familiar with Python.
Examples:
Module method:
#cool.py
def cool():
print 'cool'
Now use the module like you would be using your dict:
import cool
#cool.__dict__['cool']()
#update - to the more correct idiom vars
vars(cool)['cool']()
Class method:
class Cool():
def cool():
print 'cool'
#Cool.__dict__['cool']()
#update - to the more correct idiom vars
vars(Cool)['cool']()
Edit after comment below:
argparse seems like a good fit for this problem, so you don't have to reinvent the wheel. If you do decide to implement it completely yourself though argparse source should give you some good direction. Anyways the sections below seem to apply to this use case:
15.4.4.5. Beyond sys.argv
Sometimes it may be useful to have an ArgumentParser parse arguments
other than those of sys.argv. This can be accomplished by passing a
list of strings to parse_args(). This is useful for testing at the
interactive prompt:
15.4.5.1. Sub-commands¶
ArgumentParser.add_subparsers()
Many programs split up their functionality into a number of sub-commands, for example, the svn program can invoke sub-commands
like svn checkout, svn update, and svn commit.
15.4.4.6. The Namespace object
It may also be useful to have an ArgumentParser assign attributes to
an already existing object, rather than a new Namespace object. This
can be achieved by specifying the namespace= keyword argument:
Update, here's an example using argparse
strategizer = argparse.ArgumentParser()
strat_subs = strategizer.add_subparsers()
math = strat_subs.add_parser('math')
math_subs = math.add_subparsers()
math_max = math_subs.add_parser('max')
math_sum = math_subs.add_parser('sum')
math_max.set_defaults(strategy=max)
math_sum.set_defaults(strategy=sum)
strategizer.parse_args('math max'.split())
Out[46]: Namespace(strategy=<built-in function max>)
strategizer.parse_args('math sum'.split())
Out[47]: Namespace(strategy=<built-in function sum>)
I would like to note the reasons I would recommend argparse
Mainly the requirement to use strings that represent options and sub options to map to functions.
It's dead simple (after getting past the feature filled argparse module).
Uses a Python Standard Library Module. This let's others familiar with Python grok what your doing without getting into implementation details, and is very well documented for those who aren't.
Many extra features could be taken advantage of out of the box (not the best reason!).
Using argparse and Strategy Pattern together
For the plain and simple implementation of the Strategy Pattern, this has already been answered very well.
How to write Strategy Pattern in Python differently than example in Wikipedia?
#continuing from the above example
class MathStudent():
def do_math(self, numbers):
return self.strategy(numbers)
maximus = strategizer.parse_args('math max'.split(),
namespace=MathStudent())
sumera = strategizer.parse_args('math sum'.split(),
namespace=MathStudent())
maximus.do_math([1, 2, 3])
Out[71]: 3
sumera.do_math([1, 2, 3])
Out[72]: 6
The point of inlining functions is to blur the distinction between dictionaries and class instances. In javascript, for example, this techinque makes it very pleasant to write control classes that have little reusability. Also, and very helpfully the API then conforms to the well-known dictionary protocols, being self explanatory (pun intended).
You can do this in python - it just doesn't look like a dictionary! In fact, you can use the class keyword in ANY scope (i.e. a class def in a function, or a class def inside of a class def), and it's children can be the dictonary you are looking for; just inspect the attributes of a definition as if it was a javascript dictionary.
Example as if it was real:
somedict = {
"foo":5,
"one_function":your method here,
"two_function":your method here,
}
Is actually accomplished as
class somedict:
foo = 5
#classmethod
def one_method(self):
print self.foo
self.foo *= 2;
#classmethod
def two_method(self):
print self.foo
So that you can then say:
somedict.foo #(prints 5)
somedict.one_method() #(prints 5)
somedict.two_method() #(prints 10)
And in this way, you get the same logical groupings as you would with your "inlining".

seaborn rc parameters for set_context and set_style

In the tutorial for setting up the aesthetics of your plots, there are a few different methods:
set_style
set_context
axes_style
Each one of these accepts an rc keyword parameter dictionary. In each individual API page for the above three functions, it says:
rcdict, optional:
Parameter mappings to override the values in the preset seaborn style dictionaries. This only updates parameters that are considered part of the style definition.
Back in the tutorial page, under axes_style it goes on to say exactly how you can see what parameters are available for the rc dictionary for this one function:
If you want to see what parameters are included, you can just call the function with no arguments, which will return the current settings:
However, using this on the other functions always returns None. So, for example, I am using the following mix of matplotlib and seaborn
to set parameters:
mpl.rcParams['figure.figsize'] = [16,10]
viz_dict = {
'axes.titlesize':18,
'axes.labelsize':16,
}
sns.set_context("notebook", rc=viz_dict)
sns.set_style("whitegrid")
I also noticed that putting my dictionary in the set_style method does nothing, while, at least for those parameters, it only works in set_context. This means that they each have mutually exclusively characteristics that can be edited. However, this is not outlined anywhere in the docs.
I want to know which one of these three functions will accept a parameter for figsize. I'd also be curious to see what else they accept that might help me fine-tune things. My goal is to exclusively use the seaborn interface as often as possible. I don't need the fine tune control of things matplotlib provides, and often find it awkward anyway.
It would appear that the answer is 'none of the above'. The valid keys for set_style and set_context are listed here:
_style_keys = [
"axes.facecolor", "axes.edgecolor",
"axes.grid", "axes.axisbelow", "axes.labelcolor",
"figure.facecolor", "grid.color",
"grid.linestyle", "text.color",
"xtick.color", "ytick.color",
"xtick.direction", "ytick.direction",
"lines.solid_capstyle",
"patch.edgecolor", "patch.force_edgecolor",
"image.cmap", "font.family", "font.sans-serif",
"xtick.bottom", "xtick.top",
"ytick.left", "ytick.right",
"axes.spines.left", "axes.spines.bottom",
"axes.spines.right", "axes.spines.top",]
_context_keys = [
"font.size", "axes.labelsize",
"axes.titlesize", "xtick.labelsize",
"ytick.labelsize", "legend.fontsize",
"axes.linewidth", "grid.linewidth",
"lines.linewidth", "lines.markersize",
"patch.linewidth",
"xtick.major.width", "ytick.major.width",
"xtick.minor.width", "ytick.minor.width",
"xtick.major.size", "ytick.major.size",
"xtick.minor.size", "ytick.minor.size",]
Also note that set_style is just a convenience function which calls axes_style.
So you will have to use matplotlib.rcParams, although if the typical rcParams['figure.figsize'] = [16,10] syntax is not amenable you could of course create your own style.

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?

function arguments in python

I'm trying to wrap my head around the way positional and keyword arguments work in python, and, it seems, I'm failing rather miserably.
Given a function with a call signature matplotlib.pyplot.plot(*args,**kwargs), it can be called as
import matplotlib.pyplot as plt
x=[1,2,3]
y=[5,6,7]
plt.plot(x,y,'ro-')
plt.show()
Now, I'm trying to wrap it into something which I can call as mplot(x,y,'ro-',...) where ... are whatever arguments the original function was ready to accept. The following fails miserably, but I can't really figure how to fix it:
def mplot(x,y,fmt,*args,**kwargs):
return plt.plot(x,y,fmt,*args,**kwargs)
mplot(x,y,'ro-')
Any pointers to a way out would be very much appreciated.
You need it this way:
def mplot(x,y,fmt,*args,**kwargs):
#do stuff with x, y and fmt
return plt.plot(*args,**kwargs)
I'm assuming that your intention is to consume the x, y and fmt in your mplot routine and then pass the remaining parameters to plt.plot.
I don't believe that this is actually what you want (I can see that plt.plot wants to receive x, y and fmt and so they should not be consumed). I had deleted this answer but since your posted code apparently works, I'll leave this visible for a little while and see if it provokes the real question to be revealed!

Categories

Resources