Package: dictvars
dictvarsCreate dicts from variables in scope.Why?In python it is very common to create a dict from variables already
defined, for example when returning a context dict from a view function
that will be passed to a serializer or a template render.Code like this:returndict(user=user,form=form,comments=comments)Withvarsdictyou can get rid of the redundancy of having all
variables named twice in the code.The above code can be replaced for this:returndictvars(user,form,comments)Alternatively, variable names can be passed as strings withvarsnamed:returnvarsnamed('form','comments','myapp')Installpip install dictvarsExampleGlobal variables can be passed tovarsdictas well.The following example is a complete code to illustrate how
a "real" code looks like when using and not usingvarsdictandvarsnamed.fromdictvarsimportdictvars,varsnamedmyapp='MyApp'# a global vardefsomefunc_regular_python():# pretend this is a controller code that makes senseuser=dict(some='very',complex_='expression')permission=user.get('permission',False)user_has_permission=bool(permission)form=dict(another='object',perm=user_has_permission)comments=[]forvaluesin[d.values()fordin[user,form]]:comments.extend([vforvinvaluesifisinstance(v,str)])returndict(form=form,comments=comments,myapp=myapp)defsomefunc_dictvars():# pretend this is a controller code that makes senseuser=dict(some='very',complex_='expression')permission=user.get('permission',False)user_has_permission=bool(permission)form=dict(another='object',perm=user_has_permission)comments=[]forvaluesin[d.values()fordin[user,form]]:comments.extend([vforvinvaluesifisinstance(v,str)])returndictvars(form,comments,myapp)defsomefunc_varsnamed():# pretend this is a controller code that makes senseuser=dict(some='very',complex_='expression')permission=user.get('permission',False)user_has_permission=bool(permission)form=dict(another='object',perm=user_has_permission)comments=[]forvaluesin[d.values()fordin[user,form]]:comments.extend([vforvinvaluesifisinstance(v,str)])returnvarsnamed('form','comments','myapp')if__name__=='__main__':frompprintimportpprintpprint(somefunc_regular_python())pprint(somefunc_dictvars())pprint(somefunc_varsnamed())Output is the same in all versions:{'comments': ['very', 'expression', 'object'],
 'form': {'another': 'object', 'perm': False},
 'myapp': 'MyApp'}
{'comments': ['very', 'expression', 'object'],
 'form': {'another': 'object', 'perm': False},
 'myapp': 'MyApp'}
{'comments': ['very', 'expression', 'object'],
 'form': {'another': 'object', 'perm': False},
 'myapp': 'MyApp'}Renaming variablesThe standard kwargs syntax ofdictis also supported bydictvars.Suppose you have a variablecurrent_userbut you want to use onlyuseron your dict:defsomefunc_dictvars(current_user):form=dict(some='very',complex_='expression')comments=['bla','bla']returndictvars(form,comments,app=myapp,user=current_user)Works as expected:{'app': 'MyApp',
 'comments': ['bla', 'bla'],
 'form': {'some': 'very', 'complex_': 'expression'},
 'user': 'John Do'}LimitationsTo create a dict from the passed variables, some "magic" is done to
obtain the original variables names: the variables list from the scope
is traversed looking for variables that are the same (same reference,
same id).This implementation detail can lead to unintended leak of variables
when an object is referenced more then one time.An example:defsomefunc():a='1'b='2'c='3'leak=breturndictvars(a,b)print(somefunc())Returns:{'a': '1',
 'b': '2',
 'leak': '2'}Please note that no new value or object is leaked, only the name of
an object that was already in the dict.I find that this is rare enough to not be a problem most of the time,
additional variables returned usually can just be ignored.I'm not sure how to fix this yet. Open to suggestions.If this is a problem on a specific context, one can just pass the
offending variable with a explicit name, just like a regular dict:defsomefunc():a='1'b='2'c='3'no_leaks_now=breturndictvars(a,b=b)print(somefunc())Returns:{'a': '1',
 'b': '2'}Yet another alternative in such cases would be to swapdictvarsforvarsnamed:returnvarsnamed('a','b')