def attr_num(self, attrname):
    "Get the attribute number and scope by attribute name\n\n        This maintains a cache of name-to-number mappings for attributes\n        to keep from having to query the CDF library constantly. It's mostly\n        an internal function.\n\n        Parameters\n        ==========\n        attrname : bytes\n            name of the zVariable. Not this is NOT a string in Python 3!\n\n        Raises\n        ======\n        CDFError : if variable is not found\n\n        Returns\n        =======\n        out : tuple\n            attribute number, scope (True for global) of this attribute\n        "
    res = self._attr_info.get(attrname, None)
    if (res is None):
        attrNum = ctypes.c_long(0)
        self._call(const.GET_, const.ATTR_NUMBER_, attrname, ctypes.byref(attrNum))
        scope = ctypes.c_long(0)
        self._call(const.SELECT_, const.ATTR_, attrNum, const.GET_, const.ATTR_SCOPE_, ctypes.byref(scope))
        if (scope.value == const.GLOBAL_SCOPE.value):
            scope = True
        elif (scope.value == const.VARIABLE_SCOPE.value):
            scope = False
        else:
            raise CDFError(const.BAD_SCOPE)
        res = (attrNum.value, scope)
        self._attr_info[attrname] = res
    return res
Get the attribute number and scope by attribute name

This maintains a cache of name-to-number mappings for attributes
to keep from having to query the CDF library constantly. It's mostly
an internal function.

Parameters
==========
attrname : bytes
    name of the zVariable. Not this is NOT a string in Python 3!

Raises
======
CDFError : if variable is not found

Returns
=======
out : tuple
    attribute number, scope (True for global) of this attribute
def attr_num(self, attrname):
    "Get the attribute number and scope by attribute name\n\n        This maintains a cache of name-to-number mappings for attributes\n        to keep from having to query the CDF library constantly. It's mostly\n        an internal function.\n\n        Parameters\n        ==========\n        attrname : bytes\n            name of the zVariable. Not this is NOT a string in Python 3!\n\n        Raises\n        ======\n        CDFError : if variable is not found\n\n        Returns\n        =======\n        out : tuple\n            attribute number, scope (True for global) of this attribute\n        "
    res = self._attr_info.get(attrname, None)
    if (res is None):
        attrNum = ctypes.c_long(0)
        self._call(const.GET_, const.ATTR_NUMBER_, attrname, ctypes.byref(attrNum))
        scope = ctypes.c_long(0)
        self._call(const.SELECT_, const.ATTR_, attrNum, const.GET_, const.ATTR_SCOPE_, ctypes.byref(scope))
        if (scope.value == const.GLOBAL_SCOPE.value):
            scope = True
        elif (scope.value == const.VARIABLE_SCOPE.value):
            scope = False
        else:
            raise CDFError(const.BAD_SCOPE)
        res = (attrNum.value, scope)
        self._attr_info[attrname] = res
    return res