def join(cls, *grids):
        keys = {}
        for g in grids:
            for k in g.iterkeys():
                if k not in keys:
                    keys[k] = 0
                keys[k] += 1
        for k, v in keys.iteritems():
            if v > 1:
                raise ValueError(
                    "Grids cannot be joined, they shares some keys: %s" % k)

        kv = [g._getKeysValues() for g in grids]
        keys = [i[0] for i in kv]
        values = [i[1] for i in kv]

        new_keys = []
        [new_keys.extend(i) for i in keys]

        new_values = []
        values = _cartezianProduct(*values)
        for i in values:
            value = []
            for j in i:
                value.extend(j)
            new_values.append(value)

        d = {}
        for value in new_values:
            for k, v in zip(new_keys, value):
                if k not in d:
                    d[k] = []
                d[k].append(v)

        return cls(d)
    def join(cls, *grids):
        keys = {}
        for g in grids:
            for k in g.iterkeys():
                if k not in keys:
                    keys[k] = 0
                keys[k] += 1
        for k, v in keys.iteritems():
            if v > 1:
                raise ValueError("Grids cannot be joined, they shares some keys: %s" % k)
        
        kv = [g._getKeysValues() for g in grids]
        keys = [i[0] for i in kv]
        values = [i[1] for i in kv]

        new_keys = []
        [new_keys.extend(i) for i in keys]

        new_values = []
        values = _cartezianProduct(*values)
        for i in values:
            value = []
            for j in i:
                value.extend(j)
            new_values.append(value)

        d = {}
        for value in new_values:
            for k, v in zip(new_keys, value):
                if k not in d:
                    d[k] = []
                d[k].append(v)

        return cls(d)
    def cartezian(cls, *args, **kwargs):
        """Construct tuning grid from required parameter values (Cartesian product)

        It will construct tuning grid from `grid` parameter. `grid` is a
        dictionary with parameter names as keys and required values of this
        parameter as values. Resulting tuning grid is constructed as Cartesian
        product of parameter values.
        """
        grid = dict(*args, **kwargs).items()
        grid_keys = [k for k, v in grid]
        grid_values = [v for k, v in grid]
        grid_values = _cartezianProduct(*grid_values)
        ret = cls((k, []) for k in grid_keys)
        for item in grid_values:
            for key, value in zip(grid_keys, item):
                ret[key].append(value)
        ret._criterion = [None] * len(grid_values)
        return ret
    def cartezianGrid(cls, *args, **kwargs):
        """Construct tuning grid from required parameter values (Cartesian product)

        It will construct tuning grid from `grid` parameter. `grid` is a
        dictionary with parameter names as keys and required values of this
        parameter as values. Resulting tuning grid is constructed as Cartesian
        product of parameter values.
        """
        grid = dict(*args, **kwargs).items()
        grid_keys = [k for k, v in grid]
        grid_values = [v for k, v in grid]
        grid_values = _cartezianProduct(*grid_values)
        ret = cls((k, []) for k in grid_keys)
        for item in grid_values:
            for key, value in zip(grid_keys, item):
                ret[key].append(value)
        ret._criterion = [None] * len(grid_values)
        return ret