def create_attr_list_type(class_name, *fields):
    """Create a new attr_list_type which is a class offering get and set
    methods which is capable of serializing and deserializing itself from
    netlink message.  The fields are a bunch of tuples of name and a class
    which should provide pack and unpack (except for in the case where we
    know it will be used exclusively for serialization or deserialization).
    attr_list_types can be used as packers in other attr_list_types.  The
    names and packers of the field should be taken from the appropriate
    linux kernel header and source files.
    """
    name_to_key = {}
    key_to_name = {}
    key_to_packer = {}
    for i, (name, packer) in enumerate(fields):
        key = i + 1
        name_to_key[name.upper()] = key
        key_to_name[key] = name
        key_to_packer[key] = packer

    class AttrListType(AttrListPacker):
        def __init__(self, **kwargs):
            self.attrs = {}
            for k, v in kwargs.items():
                if v is not None:
                    self.set(k, v)

        def set(self, key, value):
            if not isinstance(key, int):
                key = name_to_key[key.upper()]
            self.attrs[key] = value

        def get(self, key, default=_unset):
            try:
                if not isinstance(key, int):
                    key = name_to_key[key.upper()]
                return self.attrs[key]
            except __HOLE__:
                if default is not _unset:
                    return default
                raise

        def __repr__(self):
            attrs = ['%s=%s' % (key_to_name[k].lower(), repr(v))
                     for k, v in self.attrs.items()]
            return '%s(%s)' % (class_name, ', '.join(attrs))

        @staticmethod
        def pack(attr_list):
            packed = array.array(str('B'))
            for k, v in attr_list.attrs.items():
                if key_to_packer[k] == RecursiveSelf:
                    x = AttrListType.pack(v)
                else:
                    x = key_to_packer[k].pack(v)
                alen = len(x) + 4

                # TODO(agartrell): This is scary.  In theory, we should OR
                # 1 << 15 into the length if it is an instance of
                # AttrListPacker, but this didn't work for some reason, so
                # we're not going to.

                packed.fromstring(struct.pack(str('=HH'), alen, k))
                packed.fromstring(x)
                packed.fromstring('\0' * ((4 - (len(x) % 4)) & 0x3))
            return packed

        @staticmethod
        def unpack(data):
            global global_nest
            attr_list = AttrListType()
            while len(data) > 0:
                alen, k = struct.unpack(str('=HH'), data[:4])
                alen = alen & 0x7fff
                if key_to_packer[k] == RecursiveSelf:
                    v = AttrListType.unpack(data[4:alen])
                else:
                    v = key_to_packer[k].unpack(data[4:alen])
                attr_list.set(k, v)
                data = data[((alen + 3) & (~3)):]
            return attr_list

    return AttrListType
dataset/ETHPy150Open facebook/gnlpy/netlink.py/create_attr_list_type