What is context in python, in particular what does **context mean? Is it a way to pass the variables in the current context around? A code example will be most appreciated.
from mako.template import Template
template = Template('var1 = ${var1}')
for v in range(1, 5):
context = {'var1': v}
print template.render(**context)
The ** operator, when it appears in a function call, converts a dictionary into a set of keyword arguments to a function. When it appears in a function definition, it converts a set of keyword arguments to a function into a dictionary. So for example:
>>> d = {'a':0, 'b':1, 'c':2}
>>> def print_my_arguments(**my_arguments):
... print my_arguments
...
>>> print_my_arguments(a=0, b=1, c=2)
{'a': 0, 'c': 2, 'b': 1}
>>> print_my_arguments(**d)
{'a': 0, 'c': 2, 'b': 1}
In your case anything you pass to render as a kwarg is passed as a Context to your template in order to render.
The context represents a dictionary of data available to the page/template while rendering. So when you do something like
context = {'var1': v}
and your template has code like
$(var1)
It would print v
Mako resolves this by looking to the Context, which is just wraps a _data with the kwargs passed down to it via render.
Related
What is a proper way in Python to write a function that will return the very same parameters it received at run-time?
E.g.:
def pass_thru(*args, **kwargs):
# do something non-destructive with *args & **kwargs
return ??? <- somehow return *args & **kwargs
Consider the following function:
def a(*args, **kwargs):
return args, kwargs
When we call the function, the value returned is a tuple, containing first another tuple with the arguments, then a dictionary with the keyword arguments:
b = a(1, 2, 3, a='foo')
print(b)
Outputs: ((1, 2, 3), {'a': 'foo'})
print(b[0]) # Gives the args as a tuple
print(b[1]) # Gives the kwargs as a dictionary
The problem is that your arguments are just a sequence of values, not a value itself you can manipulate. Keyword arguments are not themselves first-class values (that is, a=3 is not a value); they are purely a syntactic construct.
* and ** parameters get you halfway there:
def pass_thru(*args, **kwargs):
return *args, kwargs
Then
>>> pass_thru(1, 2, a=3)
(1, 2, {'a': 3})
but you can't simply pass that back to pass_thru; you'll get a different result.
>>> pass_thru(pass_thru(1,2,a=3))
((1, 2, {'a': 3}), {})
You can try unpacking the tuple:
>>> pass_thru(*pass_thru(1,2,a=3))
(1, 2, {'a': 3}, {})
but what you really need is to unpack the dict as well. Something like
>>> *a, kw = pass_thru(1,2,a=3)
>>> pass_thru(*a, **kw)
(1, 2, {'a': 3})
As far as I know, there is no way to combine the last example into a single, nested function call.
My goal is to, given a python dict which I call datainit, create a recursive collections.defaultdict which I call data, such as data is initialised with datainit, and data can be extended with any path of missing keys,
as illustrated below
from collections import *
datainit={'number':1}
data =something_with(defaultdict(), datainit)
data['A']['B']['C']=3
#At this stage, I want:
#data['A']['B']['C'] ==3
#data['number'] == 1
#and nothing else.
The normal way to do that starting with an empty dict is, for instance:
nested_dict = lambda: defaultdict(nested_dict)
data = nested_dict()
Trying:
nested_dict = lambda: defaultdict(nested_dict, datainit)
data = nested_dict()
Will logically result in my datainit being duplicated for each missing key:
>>> datainit={'number':1}
>>> nested_dict = lambda: defaultdict(nested_dict, datainit)
>>> data=nested_dict()
>>> data
defaultdict(<function <lambda> at 0x7f58e5323758>, {'number': 1})
>>> data['A']['B']['C']=2
>>> data
defaultdict(<function <lambda> at 0x7f58e5323758>, {'A': defaultdict(<function <lambda> at 0x7f58e5323758>, {'B': defaultdict(<function <lambda> at 0x7f58e5323758>, {'C': 2, 'number': 1}), 'number': 1}),
'number': 1})
All this makes sense, but how do I do to just start with an initial dict and then just use an empty dict for each missing keys?
What should be my something_with(defaultdict(), datainit).
Probably obvious, but I cannot see it!
You have two tiers; the top level defaultdict, which must have the number key, and a series of arbitrarily nested dictionaries, which must not. Your mistake is to try to treat these as one, and to try to treat 'number' as something the factory for missing values should handle.
Just set the number key in the top dictionary. There is just one such key, with a value, and it should not be handled by the defaultdict() factory. The factory is there to provide a default value for arbitrary missing keys, number is not an arbitrary key.
from collections import defaultdict
def topleveldict():
nested_dict = lambda *a, **kw: defaultdict(nested_dict, *a, **kw)
return nested_dict(number=1) # or nested_dict({'number': 1})
data = topleveldict()
The topleveldict() function is only needed if you plan to create the structure in multiple places in your codebase. If there is just one such object or just one place you create these, then just inline the code from that function:
nested_dict = lambda *a, **kw: defaultdict(nested_dict, *a, **kw)
data = nested_dict(number=1) # or nested_dict({'number': 1})
How can one define the initial contents of the keyword arguments dictionary? Here's an ugly solution:
def f(**kwargs):
ps = {'c': 2}
ps.update(kwargs)
print(str(ps))
Expected behaviour:
f(a=1, b=2) => {'c': 2, 'a': 1, 'b': 2}
f(a=1, b=2, c=3) => {'c': 3, 'a': 1, 'b': 2}
Yet, I would like to do something a little bit more in the lines of:
def f(**kwargs = {'c': 2}):
print(str(kwargs))
Or even:
def f(c=2, **kwargs):
print(str(???))
Ideas?
First to address the issues with your current solution:
def f(**kwargs):
ps = {'c': 2}
ps.update(kwargs)
print(str(ps))
This creates a new dictionary and then has to take the time to update it with all the values from kwargs. If kwargs is large that can be fairly inefficient and as you pointed out is a bit ugly.
Obviously your second isn't valid.
As for the third option, an implementation of that was already given by Austin Hastings
If you are using kwargs and not keyword arguments for default values there's probably a reason (or at least there should be; for example an interface that defines c without explicitly requiring a and b might not be desired even though the implementation may require a value for c).
A simple implementation would take advantage of dict.setdefault to update the values of kwargs if and only if the key is not already present:
def f(**kwargs):
kwargs.setdefault('c', 2)
print(str(kwargs))
Now as mentioned by the OP in a previous comment, the list of default values may be quite long, in that case you can have a loop set the default values:
def f(**kwargs):
defaults = {
'c': 2,
...
}
for k, v in defaults.items():
kwargs.setdefault(k, v)
print(str(kwargs))
A couple of performance issues here as well. First the defaults dict literal gets created on every call of the function. This can be improved upon by moving the defaults outside of the function like so:
DEFAULTS = {
'c': 2,
...
}
def f(**kwargs):
for k, v in DEFAULTS.items():
kwargs.setdefault(k, v)
print(str(kwargs))
Secondly in Python 2, dict.items returns a copy of the (key, value) pairs so instead dict.iteritems or dict.viewitems allows you to iterate over the contents and thus is more efficient. In Python 3, 'dict.items` is a view so there's no issue there.
DEFAULTS = {
'c': 2,
...
}
def f(**kwargs):
for k, v in DEFAULTS.iteritems(): # Python 2 optimization
kwargs.setdefault(k, v)
print(str(kwargs))
If efficiency and compatibility are both concerns, you can use the six library for compatibility as follows:
from six import iteritems
DEFAULTS = {
'c': 2,
...
}
def f(**kwargs):
for k, v in iteritems(DEFAULTS):
kwargs.setdefault(k, v)
print(str(kwargs))
Additionally, on every iteration of the for loop, a lookup of the setdefault method of kwargs needs to be performed. If you truly have a really large number of default values a micro-optimization is to assign the method to a variable to avoid repeated lookup:
from six import iteritems
DEFAULTS = {
'c': 2,
...
}
def f(**kwargs):
setdefault = kwargs.setdefault
for k, v in iteritems(DEFAULTS):
setdefault(k, v)
print(str(kwargs))
Lastly if the number of default values is instead expected to be larger than the number of kwargs, it would likely be more efficient to update the default with the kwargs. To do this, you can't use the global default or it would update the defaults with every run of the function, so the defaults need to be moved back into the function. This would leave us with the following:
def f(**kwargs):
defaults = {
'c': 2,
...
}
defaults.update(kwargs)
print(str(defaults))
Enjoy :D
A variation possible on your first approach on Python 3.5+ is to define the default and expand the provided arguments on a single line, which also lets you replace kwargs on the same line, e.g.:
def f(**kwargs):
# Start with defaults, then expand kwargs which will overwrite defaults if
# it has them
kwargs = {'c': 2, **kwargs}
print(str(kwargs))
Another approach (that won't produce an identical string) that creates a mapping that behaves the same way using collections.ChainMap (3.3+):
from collections import ChainMap
def f(**kwargs):
# Chain overrides over defaults
# {'c': 2} could be defined outside f to avoid recreating it each call
ps = ChainMap(kwargs, {'c': 2})
print(str(ps))
Like I said, that won't produce the same string output, but unlike the other solutions, it won't become more and more costly as the number of passed keyword arguments increases (it doesn't have to copy them at all).
Have you tried:
def f(c=2, **kwargs):
kwargs['c'] = c
print(kwargs)
Update
Barring that, you can use inspect to access the code object, and get the keyword-only args from that, or even all the args:
import inspect
def f(a,b,c=2,*,d=1,**kwargs):
code_obj = inspect.currentframe().f_code
nposargs = code_obj.co_argcount
nkwargs = code_obj.co_kwonlyargcount
localvars = locals()
kwargs.update({k:localvars[k] for k in code_obj.co_varnames[:nposargs+nkwargs]})
print(kwargs)
g=f
g('a', 'b')
I'd like to be able to setup a mock that allows me to return something when I apply the builtin dict method.
I've tried using __iter__ to no avail. I can't seem to get anything but an empty dictionary:
import mock
mocked_object = mock.MagicMock()
mocked_object.__iter__.return_value = [1, 2, 3]
dict(mocked_object)
# {}
From dict documentation
If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object. Otherwise, the positional argument must be an iterable object. Each item in the iterable must itself be an iterable with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value.
MagicMock objects expose a keys method just because are mock objects and so dict() will consider they mapping objects. Unfortunately that way is little bit complicated to use if we want that on dict call mock become a dictionary with predefined key-values. The follow examples show how to implement a dict conversion to a predefined dictionary by use mapping object protocol:
>>> m = MagicMock()
>>> d = {"a":"A", "b":"B", "c":"C"}
>>> m.keys.return_value.__iter__.return_value = ["a", "b", "c"]
>>> m.__getitem__.side_effect = ["A","B","C"]
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}
>>> #Little bit generic
>>> m.keys.return_value.__iter__.return_value = d.keys()
>>> m.__getitem__.side_effect = lambda k:d[k]
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}
Both are little bit hard to read and in our test we would like something of simpler to read.
To lead dict to use iterator instead mapping we can just remove keys method from our mock and set __iter__.return_value:
>>> del m.keys
>>> m.__iter__.return_value = [("a","A"),("b","B"),("c","C")]
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}
>>> #Little bit generic
>>> m.__iter__.return_value = d.items()
>>> dict(m)
{'a': 'A', 'c': 'C', 'b': 'B'}
IMHO that is a simple and neat way to set up your mock and get a predefined dictionary from dict call.
Actually I think you need to do something like this:
mocked_object.keys.return_value.__iter__.return_value = [1, 2, 3]
With this, the dict method will give you an object with those keys, and the result of getattr(mocked_object, '1') (so, another mocked method) as values. I think you might be able to do what you want by mocking the keys() method as well if you want more control on the result.
I want to use kwargs in Python like this:
def myfunc(**kwargs):
... do something ...
x = myfunc(a=1, b=2, #value=4)
But I can't, because #value is not a valid Python keyword
Alternatively, I can do this:
x = myfunc(**{'a':1, 'b':2, '#value': 4})
which is kind of awkward.
Is there any way I can use some kind of hybrid approach here?
# this doesn't work
x = myfunc(a=1,b=2, {'#value': 4})
Sure you can:
x = myfunc(a=1, b=2, **{'#value': 4})
Using explicit keyword parameters does not prevent you from passing in a dictionary as well.
Demo:
>>> def myfunc(**kwargs):
... print kwargs
...
>>> myfunc(a=1, b=2, **{'#value': 4})
{'a': 1, 'b': 2, '#value': 4}