JSON selector class in Python I've created a simple little class called JSONSelector to be able to select relevant data from a JSON object (a dict in Python). Here's what I have so far - it's based off of a few SQL statements, NumPy methods, and JavaScript iterating methods:

class JSONSelector:
    def __init__(self, json):
        self.json = json

    def __str__(self):
        return "{}({})".format(type(self).__name__, str(self.json))
    __repr__ = __str__

    def select(self, selectors):
        if selectors == "*":
            return type(self)(self.json)
        else:
            temp = {}
            for sel in selectors:
                temp[sel] = self.json.get(sel, None)
            return type(self)(temp)

    def where(self, cond):
        temp = {}
        for key, value in self.json.items():
            if cond(key, value):
                temp[key] = value
        return type(self)(temp)

    def astype(self, type_):
        temp = {}
        for key, value in self.json.items():
            temp[key] = type_(value)
        return JSONSelector(temp)

    def sort(self, **kwargs):
        return type(self)(dict(sorted(self.json.items(), **kwargs)))

    def foreach(self, func):
        for key, value in self.json.items():
            if func(key, value) == False: break

    def print(self, func=None):
        if not func:
            print(self)
            return
        else:
            print(func(self))
            return


Here's a test case with an explanation:

a = JSONSelector({
    "stuff": 5,
    "seeded": 6,
    "number": "7",
    "more_stuff": 8
})

a.select("*") \  # Select all entries from the dict
    .where(lambda key,value: type(value) is int) \ # Where the value is an integer
    .sort(key=lambda x: x[1]) \ # Sort by the value
    .astype(str) \ # Convert the values to type str
    .foreach(lambda key, value: print(key + ": " + value)) # Loop over all entries


I'd like to know if any of my code is redundant, where I can shorten things up, and if anything is incorrect. Thank you in advance!
A few notes:

Firstly, I would add some docstrings to each function to document what the expected behaviour is.

In select when you're not doing any mutations (i.e. under the * case), it seems you could just return self. Is there any reason to make a new copy?

In select, where, astype instead of creating a temporary dict, you could use a dict comprehension instead, example:

def where(self, cond):
    return type(self)({key: value for key, value in self.json.items() if cond(key, value)})


In astype you're using JSONSelector, however everywhere else you're using type(self) this should be consistent whichever one you go for.

print seems like an unnecessary function, but if you keep it the return lines have no effect.

Hope that's helpful.