Gathering statistics on a list of dicts
Minor improvements

I think defining value_counts = AttributeValueCount('type', 'color') would be more user-friendly than having to pass in a list, so you could just define the constructor as

class AttributeValueCount:
    def __init__(self, *keylist):
        self._keylist = keylist
        self._counts = {key: defaultdict(int) for key in keylist}


and remove that need for an iterable. And if a user still has an iterable to pass to the constructor, they can still unpack it:

keys = ['type', 'color']
value_counts = AttributeValueCount(*keys)


I would also use add and update methods as in a dictionary or a set: add is for a single element and update is for several:

    def update(self, iterable):
        for element in iterable:
            self.add(element)

    def add(self, element):
        for key in self._keylist:
            if key in element: 
                self._counts[key][element[key]] += 1
            else:
                self._counts[key]['Non existent'] += 1


You can also simplify this add method using dict.get():

    def add(self, element):
        for key in self._keylist:
            category = element.get(key, 'Non existent')
            self._counts[key][category] += 1


Lastly, the __repr__ method is meant to return an "official" representation of the object, something that could potentialy be passed to eval to reconstruct it. I’d rather use __str__ here, or even something completely different, like the summary you’re talking about:

    def summary(self):
        return '\n'.join(
                '-- {} --\n{}'.format(
                    key,
                    '\n'.join(
                        '\t {}: {}'.format(value, count)
                        for value, count in self._counts[key].items()
                    ))
                for key in self._keylist
        )


Note that I used str.join instead of string concatenation as it is usually faster and more memory efficient.

Major improvements

The first thing I would add is the ability to specify the name of the "missing" category. I have a tendency to consider None in such cases, rather than any arbitrary string, but seeing at your data, it seems like None could be a valid entry. So I'd say: let the user decide based on their data.

There is still a question as where to specify this default: in __init__ or at each update/add call? Both might be valid.

An other change I would make is to completely invert the flow of things. Instead of specifying the keys you're interested in beforehand, you just store the data. And you provide methods to retrieve the counts associated to each key latter, this will allow data exploration to be more dynamic. This will give a session like:

&gt;&gt;&gt; counts = AttributeValueCount(data, missing='Non existent')
&gt;&gt;&gt; print(counts['type'])
farm: 2
wild: 1
extinct: 1
&gt;&gt;&gt; print(counts['color'])
red: 1
orange: 1
None: 1
Non existent: 1
&gt;&gt;&gt; print(counts['volume'])
2000: 1
5000: 1
Non existent: 2


Which seems easier than having to recreate an AttributeValueCount('volume') afterwards.

There, also, you have 2 possibilities:


only store values using __init__, add and update and compute the counts later (\$\mathcal{O}(n)\$ at each __getitem__);
compute the counts upfront (\$\mathcal{O}(n\times{}m)\$) but have a constant time __getitem__.


I would go for the second solution as it is interesting how to deal with missing keys when you first encounter a new category:

from collections import Counter


class AttributeValueCount:
    def __init__(self, iterable, *, missing=None):
        self._missing = missing
        self.length = 0
        self._counts = {}
        self.update(iterable)

    def update(self, iterable):
        categories = set(self._counts)
        for length, element in enumerate(iterable, self.length):
            categories.update(element)
            for category in categories:
                try:
                    counter = self._counts[category]
                except KeyError:
                    self._counts[category] = counter = Counter({self._missing: length})
                counter[element.get(category, self._missing)] += 1
        self.length = length + 1

    def add(self, element):
        self.update([element])

    def __getitem__(self, key):
        return self._counts[key]

    def summary(self, key=None):
        if key is None:
            return '\n'.join(self.summary(key) for key in self._counts)

        return '-- {} --\n{}'.format(key, '\n'.join(
                '\t {}: {}'.format(value, count)
                for value, count in self._counts[key].items()
        ))


Usage being:

&gt;&gt;&gt; from count_attributes import AttributeValueCount
&gt;&gt;&gt; data = [
...     {'name': 'apple', 'type': 'farm', 'color': 'red', 'volume': 2000},
...     {'name': 'orange', 'type': 'farm', 'color': 'orange', 'volume': 5000},
...     {'name': 'elderberry', 'type': 'wild', 'color': None},
...     {'name': 'pythonfruit', 'type': 'extinct'} 
... ]
&gt;&gt;&gt; c = AttributeValueCount(data, missing='Non existent')
&gt;&gt;&gt; print(c.summary())
-- type --
     Non existent: 0
     farm: 2
     wild: 1
     extinct: 1
-- name --
     Non existent: 0
     apple: 1
     orange: 1
     elderberry: 1
     pythonfruit: 1
-- volume --
     Non existent: 2
     2000: 1
     5000: 1
-- color --
     Non existent: 1
     red: 1
     orange: 1
     None: 1
&gt;&gt;&gt; c['volume']
Counter({'Non existent': 2, 2000: 1, 5000: 1})
&gt;&gt;&gt; c.add({'foo': 'bar'})
&gt;&gt;&gt; print(c.summary())
-- name --
     Non existent: 1
     apple: 1
     orange: 1
     elderberry: 1
     pythonfruit: 1
-- type --
     Non existent: 1
     farm: 2
     wild: 1
     extinct: 1
-- volume --
     Non existent: 3
     2000: 1
     5000: 1
-- color --
     Non existent: 2
     red: 1
     orange: 1
     None: 1
-- foo --
     Non existent: 4
     bar: 1