I'm writing a class that has a number of methods operating on similar types of arguments:
class TheClass():
    def func1(self, data, params, interval):
        ....   
    def func2(self, data, params):
        ....
    def func3(self, data, interval):
        ....
    def func4(self, params):
        ....
    ...
There's a certain convention about these arguments (e.g. data/params should be numpy.farrays, interval - a list of 2 floats), but I'd like to allow user to have more freedom: e.g. functions should accept int as data or params, or only one int as an interval and then assume that this is the end point with the starting point 0, etc.
So to avoid all these transformations within methods, that should do only the logic, I'm using decorators like this:
def convertparameters(*types):
    def wrapper(func):
        def new_func(self, *args, **kwargs):
            # Check if we got enough parameters
            if len(types) > len(args):
                raise Exception('Not enough parameters')
            # Convert parameters
            new_args = list(args)
            for ind, tip in enumerate(types):
                if tip == "data":
                    new_args[ind] = _convert_data(new_args[ind])
                elif tip == "params":
                    new_args[ind] = _convert_params(new_args[ind])
                elif tip == "interval":
                    new_args[ind] = _convert_interval(new_args[ind])
                else:
                    raise Exception('Unknown type for parameter')
            return func(self, *new_args, **kwargs)
        return new_func
    return wrapper
Where _convert_data, _convert_params and _convert_interval do the dirty job. Then I define the class as follows:
class TheClass():
    @convertparameters("data", "params", "interval")
    def func1(self, data, params, interval):
        ....   
    @convertparameters("data", "params")
    def func2(self, data, params):
        ....
    @convertparameters("data", "interval")
    def func3(self, data, interval):
        ....
    @convertparameters("params")
    def func4(self, params):
        ....
    ...
It does the trick, but there're several quite disturbing things:
@staticmethod or something that post-process output of the method) the ordering of these decorators matterfunc1(*args, **kwargs)
Are there any better (or more "Pythonic") ways to do such massive parameter transformation?
UPDATE 1: SOLUTION based on n9code's suggestion
In order to avoid confusion there's a modification of the convertparameters wrapper that solves 3rd issue (masking of signature and docstring of methods) - suggested by n9code for Python >2.5. 
Using decorator module (to be installed separately: pip install decorator) we can transfer all function's "metadata" (docstring, name and signature) at the same time getting rid of nested structure inside the wrapper
from decorator import decorator 
def convertparameters(*types):
    @decorator
    def wrapper(func, self, *args, **kwargs):
        # Check if we got enough parameters
        if len(types) > len(args):
            raise Exception('Not enough parameters')
        # Convert parameters
        new_args = list(args)
        for ind, tip in enumerate(types):
            if tip == "data":
                new_args[ind] = _convert_data(new_args[ind])
            elif tip == "params":
                new_args[ind] = _convert_params(new_args[ind])
            elif tip == "interval":
                new_args[ind] = _convert_interval(new_args[ind])
            else:
                raise Exception('Unknown type for parameter')
        return func(self, *new_args, **kwargs)
    return wrapper
UPDATE 2: MODIFIED SOLUTION based on zmbq's suggestion
Using inspect module we could also get rid of arguments of decorator, checking the names of arguments of the initial function. This will eliminate another layer of the decorator
from decorator import decorator
import inspect
@decorator
def wrapper(func, self, *args, **kwargs):
    specs = inspect.getargspec(func)
    # Convert parameters
    new_args = list(args)
    for ind, name in enumerate(specs.args[1:]):
        if name == "data":
            new_args[ind] = _convert_data(new_args[ind])
        elif name == "params":
            new_args[ind] = _convert_params(new_args[ind])
        elif name == "interval":
            new_args[ind] = _convert_interval(new_args[ind])
    return func(self, *new_args, **kwargs)
And the usage is much simpler then. The only important thing is keep using the same names for arguments between different functions.
class TheClass():
    @convertparameters
    def func1(self, data, params, interval):
        ....   
    @convertparameters
    def func2(self, data, params):
        ....
                Class methods don't need a class instance. They can't access the instance ( self ) but they have access to the class itself via cls . Static methods don't have access to cls or self . They work like regular functions but belong to the class's namespace.
__class__ is an attribute on the object that refers to the class from which the object was created. a. __class__ # Output: <class 'int'> b. __class__ # Output: <class 'float'> After simple data types, let's now understand the type function and __class__ attribute with the help of a user-defined class, Human .
In python, unlike other languages, you cannot perform method overloading by using the same method name. Why? Everything is an object in python, classes, and even methods. Say you have an object Addition, which is a class (everything in python is an object, so the class Addition is an object too).
The __int__ method is called to implement the built-in int function. The __index__ method implements type conversion to an int when the object is used in a slice expression and the built-in hex , oct , and bin functions.
This is a problem, you are right, but it is being solved easily with functools.wraps. Simply decorate your newfunc with it, and you will save the signature of the original function.
from functools import wraps
def convertparameters(*types):
    def wrapper(func):
        @wraps(func)
        def new_func(self, *args, **kwargs):
            pass # Your stuff
Tough, this works only for Python 3. In Python 2, the signature would not be preserved, only __name__ and __doc__ would be. So in case of Python, you could use the decorator module:
from decorator import decorator
def convertparameters(*types):
    @decorator
    def wrapper(func, self, *args, **kwargs):
        pass  # return a result
    return wrapper
EDIT based on user3160867's update.
To make the code a bit more concise, don't provide arguments to the decorator - deduce them from the decorated function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With