I've created a class that implements customized addition, subtraction, etc. But for this class I'd like to have some additional parameters for these methods (__add__
, ...).
So my first thought was: A global dictionary that can be set or altered before I do the operations and internally it just accesses this dictionary and assumes these were given as kwargs
. This obviously solved my problem but another one emerged: I had to keep track of this global dictionary and it's state.
So I thought I can solve this with a dictionary that can be used as context manager that allows me to set them temporarly but cleans up afterwards:
from copy import deepcopy
class Arguments(object):
"""A dictionary container that can be used as context manager.
The context manager allows to modify the dictionary values and after
exiting it resets them to the original state.
Parameters
----------
kwargs :
Initial values for the contained dictionary.
Attributes
----------
defaults : dict
The `dict` containing the defaults as key-value pairs
"""
defaults = {}
def __init__(self, **kwargs):
# Copy the original and update the current dictionary with the values
# passed in.
self.dct_copy = deepcopy(self.defaults)
self.defaults.update(kwargs)
def __enter__(self):
# return the dictionary so one can catch it if one wants don't want to
# always update the class attribute or change some defaults in between
return self.defaults
def __exit__(self, type, value, traceback):
# clear the dictionary (in case someone added a new value) and update
# it with the original values again
self.defaults.clear()
self.defaults.update(self.dct_copy)
Do you think this approach is good? Are there alternatives or even builtin or plugins that do essentially the same (maybe some configuration-like class)? Is the code fairly straightforward without to many problems, is the coding style ok? Do you spot any potential bugs or problems?
The following part is only to illustrate what I want to do and how I think of using it in case I haven't formulated in clearly in the introduction text. This class is obvious nonsense (and only of explanatory purpose) and should not be part of any review:
class Container(object):
def __init__(self, data):
self.data = data
def __add__(self, other):
# Magic methods don't accept args when called as "xxx + yyy"
# so take the global defaults and pass them in.
return self.add(other, **Arguments.defaults)
def add(self, other, **kwargs):
# It could be that some kwargs are not set, then apply the default
# from the global defaults.
for key in Arguments.defaults:
if key not in kwargs: # We don't want to overwrite explicit kwargs
kwargs[key] = Arguments.defaults[key]
print(kwargs) # Just print the arguments we got.
The magic method takes no arguments except both operands:
>>> Container(10) + 2
{}
I have to use a direct method call if I want to provide arguments:
>>> Container(10).add(2, some_argument=10)
{'some_argument': 10}
But with the context manager I would be able to do something like this:
>>> with Arguments(some_argument=10):
... Container(10) + 2 # just one operation, in general I do 100s here.
{'some_argument': 10}
It would allow me to define global defaults: Arguments.defaults[kwarg_name] = kwarg_default
but overwrite them temporary in some context without needing to call the explicit method or subclassing the container just to alter one default value.
It was asked about the context and I have a class that contains some primary data (which is straightforward to add
) but also some other informations, like a dict
which contains information about the data. The defaults contains a function that does basically a merge with conflict resolution (if the key was present in both). I want to be able to give this function some parameters during the operation, for example which keywords must not be present in both and which will be affected by the operation and with add
that's easy but cumbersome to repeat - and with __add__
it's just impossible without hardcoding it somewhere. And it's not only that dict
, I have more attributes, some are trivial to "do" in the operation and don't need any arguments but others do.
In short: I expect this context-dictionary to be a solution to adding arguments to magic methods and quickly reset or alter them if the need arises.
Arguments
can be a poor choice if other factors in the code that we can't see goes in favor of using alternatives). With the real code available, it is possible to propose alternatives about the big picture that could lead to use a completely different approach \$\endgroup\$Container
information, and you may also want to add more to yourArguments
class. \$\endgroup\$