Search code examples
pythonfunctionmethodsiterationattributeerror

Python throws Attribute Error for base class method in inherited class


I'm getting Attribute error as below while calling BaseSocketDataHandler class function by getting string from key name as string and converting it to method name with self.method_name = getattr(self, "self.__process_" + key.lower().replace(" ", "_")) while iterating info_dict_map

AttributeError: 'DataHandler' object has no attribute 'self.__process_info'

I don't get why I am getting this error. Is it proper way to call an function by string, or I should do something else?

class BaseSocketDataHandler(object):
    def __init__(self, sql_address, sql_user, sql_pswd, sql_db_name):
        .....
        self.db_connector = MySqlConnector(address=sql_address, suser=sql_user, spwd=sql_pswd, db_name=sql_db_name)
        .....
        self.info_dict = dict()
        self.info_dict_map = {"date_time": (0, 12), "info_len": (12, 13), "info": (13, 14), "reserved": (36, 37)}
        self.hex_data_dict = {"data_content": "0123456789abcdef10111213141516171819"

    @staticmethod
    def __convert_to_int(data):
        return int(data, 16)

    @staticmethod
    def __process_reserved(data):
        return data

    def __process_date_time(self, date_time_in_hex):
        date_time = tuple()
        for x in date_time_in_hex:
            date_time += self.__convert_to_int(x)
        return date_time

    def __process_info_len(self, info_len):
        return self.__convert_to_int(info_len)

    def __process_info(self, info):
        return self.__convert_to_int(number_of_sat)

    def make_info(self):
        for key, val in self.info_dict_map.items():
            method_name = getattr(self, "self.__process_" + key.lower().replace(" ", "_"))
            key_var = key
            setattr(self, key_var, method_name(self.hex_data_dict["data_content"][val[0]: val[1]]))
            self._info_dict.update({key: key_var})
            self.method_name = None




class DataHandler(BaseSocketDataHandler):
    def __init__(self):
        super(DataHandler, self).__init__(sql_address, sql_user, sql_pswd, sql_db_name)

    def run_forever(self):
        while True:
            try:
                self.make_info()
            except Exception as uee:
                self.log.exception(self._log_msg(uee))
                break

Solution

  • It is because "process" is preceded by two underscores. This is called name mangling. From the python documentation:

    Since there is a valid use-case for class-private members (namely to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name mangling. Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.