'self' equals string object?

So, I’m a noob to Python, have intermediate skills in C++/C#. I’ve been struggling with this error for the better part of a week now trying to solve it myself and honestly at this second I’m really hating Python! Help me understand what is happening here and after another couple beers I’ll probably change my mind :slight_smile:

I’m trying to write a class (I’ve tested this code as a function and it works). When I try to access the class, I get the error: "AttributeError: ‘str’ object has no attribute ‘canID’. Using ‘print’ troubleshooting, I think I’ve determined that ‘self’ is being treated as a string object, or the class is considered a string object - not sure which.

Here is my code - wtf is going on?!:

class GetAddress():
    
    ''' TAKES A HEX CAN_ID AND RETURNS A MODULE ADDRESS '''
    
    def __init__(self, canID):       
       self.canID = canID
       self.modAddr = ""
        
        

    def getAddress(self): 
        print("Type: " + str(type(self))) # troubleshooting
        #check for 8 digits        
        if len(self.canID) < 8:        
           print(str(self.canID))
           self.modAddr = "ERR"

        
        else:
            print("canID: " + str(self.canID))
            
            # Change hex message to binary value (bv)
            #
            self.bv = f'{int(self.canID,16):0>32b}'            
            print("bv: " + str(self.bv))                   #debug
            
            
            # trim first 13 digits
            # 
            self.trimmed = self.bv[13:]
            #print("Trim canID: " + str(self.trimmed))      #debug

                        
            # get next 6 digits
            #
            self.end = len(self.trimmed) - 14 
            self.start = 0
            self.bvSubString = self.trimmed[self.start : self.end + 1]
            #print("substring: " + str(self.bvSubString))  #debug


            #convert subString into two parts
            #
            self.num_0 = self.bvSubString[0:2]
            self.num_1 = self.bvSubString[2:6]
            #print("num 1: " + str(self.num_0))             #debug
            #print("num 2: " + str(self.num_1))             #debug
                        

            # the resulting number is a binary value...
            # convert it to int(base 2) then hex
            # 
            self.modAddr1 = format(hex(int(self.num_0,2)))
            self.modAddr2 = format(hex(int(self.num_1,2)))
            self.modAddr = str(self.modAddr1).lstrip("0x") + str(self.modAddr2).lstrip("0x")
            #print("modAddr: " + self.modAddr)              #debug
        
        
    def __str__(self):
        # return the resulting hex value as string
        return self.modAddr

# testing
address = GetAddress.getAddress('181B1F40')
print("CAN address: " + str(address))

When you write:

address = GetAddress.getAddress('181B1F40')

It never creates an instance of GetAddress, but rather it calls the function getAddress (which it finds in the namespace of the class) and passes the string directly as the self parameter—which is why its a string type. It looks like what you intend is this:

address = GetAddress('181B1F40').getAddress()

Or, equivalently, something like:

ga = GetAddress('181B1F40')
address = ga.getAddress()

The first part creats an instance of GetAddress, with the string being passed to your __init__ method. The second part calls the getAddress method, with the instance implicitly passed as the self parameter.

For more details about this, see here in the documentation.

@jrivers I knew it had to be something fundamental I wasn’t getting. Thanks for the explanation and the link.