from collections.abc import Mapping
from typing import Iterable, List


class MappingView(object):
    def __init__(self, mapping: Mapping, *args: List[str]):
        self._mapping = mapping
        self._args = args

    def _keys(self) -> Iterable:
        if len(self._args) == 0:
            return self._mapping.keys()
        else:
            return [arg for arg in self._args if arg in self._mapping]

    def __len__(self) -> int:
        return len(self._keys())

    def __repr__(self) -> str:
        mapping = {key: self._mapping[key] for key in self._keys()}
        return f'{self.__class__.__name__}({mapping})'

    __class_getitem__ = classmethod(type([]))


class KeysView(MappingView):
    def __iter__(self) -> Iterable:
        yield from self._keys()


class ValuesView(MappingView):
    def __iter__(self) -> Iterable:
        for key in self._keys():
            yield self._mapping[key]


class ItemsView(MappingView):
    def __iter__(self):
        for key in self._keys():
            yield (key, self._mapping[key])
