Remember all default methods

Im writing an application that collects and displays data from a scientific tool. One part of the data is the spectrum: essentially just a list of values, as well as a dictionary with some metadata. After the data has been collected by the application, it will not change, so the list and metadata can be considered immutable.

I like to use this to my advantage, remembering the functions that perform the calculations in the spectrum. Here is an example of a game:

class Spectrum(object): def __init__(self, values, metadata): self.values = values self.metadata = metadata # self.values and self.metadata should not change after this point. @property def first_value(self): return self.values[0] def multiply_by_constant(self, c): return [c*x for x in self.values] def double(self): return self.multiply_by_constant(2) 

I want each of these methods to be noticed by default. Is there a way (metaclass?) To accomplish this without copying to one of these decorators reminders and spelling @memoize everywhere?

+7
python immutability
source share
2 answers

I went ahead and wrote a metaclass to solve your question. It goes through all the attributes and checks if they are callable (usually a function, method or class) and decorates those that are. Of course, you would install decorator in your memoizing decorator (e.g. functools.lru_cache ).

If you want to only decorate methods, not any called ones, you can replace the hasattr(val, "__call__") inspect.ismethod(val) with inspect.ismethod(val) . But this may lead to an error in the future when you do not remember that it only works for methods and adds a function or class that will not be stored in memory!

See this SO question for more information on metaclasses in Python.

 def decorate(f): def wrap(*args, **kwargs): # Print a greeting every time decorated function is called print "Hi from wrap!" return f(*args, **kwargs) return wrap class DecorateMeta(type): def __new__(cls, name, bases, dct): # Find which decorator to use through the decorator attribute try: decorator = dct["decorator"] except KeyError: raise TypeError("Must supply a decorator") # Loop over all attributes for key, val in dct.items(): # If attribute is callable and is not the decorator being used if hasattr(val, "__call__") and val is not decorator: dct[key] = decorator(val) return type.__new__(cls, name, bases, dct) class Test: __metaclass__ = DecorateMeta decorator = decorate def seasonal_greeting(self): print "Happy new year!" Test().seasonal_greeting() # Hi from wrap! # Happy new year! 
+1
source share

I adapted the refrigerators in response to this:

 from inspect import isfunction class Immutable(type): def __new__(cls, name, bases, dct): for key, val in dct.items(): # Look only at methods/functions; ignore those with # "special" names (starting with an underscore) if isfunction(val) and val.__name__[0] != '_': dct[key] = memoized(val) return type.__new__(cls, name, bases, dct) 

The decorator is known in advance, so I do not need to specify it in the object itself. I also take care of the methods, although for reasons that I still do not understand, all the methods of the objects are not connected when Immutable.__new__ sees them, and therefore theyre functions, not methods. I also excluded methods with names beginning with an underscore: in the case of memoizing, you do not want to do anything with methods like __init__ or __eq__ .

+1
source share

All Articles