2

I've got an interesting question that I do not understand at all why this is happening. So, I'm trying to sort a list of tuples, where the first element of tuple is an object, based on the attributes within the said objects. So, I have created the following code to test this functionality:

class s(object):
    def __init__(self, name):
        self._name = name
    def get_name(self):
        return self._name

def val(x):
    #This used in place of a lambda
    return x[0]._name

e1 = s("Fred")
e2 = s("Bill")
print(e2.get_name())

list1 = [(e1, 3), (e2, 4)]

for n in list1:
    print(val(n))

list2 = sorted(list1, key = val)

print(list2)

print(list2[0] == e2)

print(e2.get_name)
print(e2._name)

With the output of this being:

Bill
Fred
Bill
[(<__main__.s object at 0x0000002AC47D6438>, 4), (<__main__.s object at 0x0000002AC47D6240>, 3)]
False
<bound method s.get_name of <__main__.s object at 0x0000002AC47D6438>>
Bill

I have absolutely no clue why I'm getting the memory addresses of the attributes as the first elements of my tuples after sorting, and I've scoured through SO and there really shouldn't be any issue with this code since it looks exactly the same as alot of other posts on this. Can ANYONE please help me out here and point out why this is happening? I expect this output:

print(list2) #After sorting
OUTPUT:
[(e2, 4), (e1, 3)]
Jenna
  • 97
  • 6
  • Please fix the indentation of the code in your question. Badly indented Python cannot be run, and is not a [mcve]. – khelwood Apr 25 '18 at 11:20
  • Will do, apologies – Jenna Apr 25 '18 at 11:21
  • you want to sort based on the integers in the tuple??? – fazkan Apr 25 '18 at 11:22
  • Sort based on the name attr inside the objects of the "s" class; i.e sort by "Fred" and "Bill" – Jenna Apr 25 '18 at 11:23
  • The val function is in wrong place – Benjámin Gerván Apr 25 '18 at 11:23
  • Yeah, I just fixed it, it's in the right place in my code; was a mistake on my part during the edit to fix the indentation of the class. Original problematic output is still caused however, and I don't know how to fix it – Jenna Apr 25 '18 at 11:24
  • Consider adding a `__repr__` method to your class. `<__main__.s ...="" at="" object="">` is the default string representation for an instance of `s`. – khelwood Apr 25 '18 at 11:24
  • Right, but surely I can do this without one; the methods work outside of the sorted(<...>), something is going wrong when I try to sort if using my function val(x) as the key and I'm wondering what exactly is causing the objects themselves to be replaced by the memory addresses of the attribute I'm sorting by. Right, but shouldn't sorted just organise the objects based on their value? I've seen similiar code in other questions work fine, but I'm not sure why mine doesn't work: https://stackoverflow.com/questions/403421/how-to-sort-a-list-of-objects-based-on-an-attribute-of-the-objects – Jenna Apr 25 '18 at 11:26
  • https://stackoverflow.com/questions/403421/how-to-sort-a-list-of-objects-based-on-an-attribute-of-the-objects Check this, the `__eq__` and `__lt__` functions could solve the issue without lambda. – Benjámin Gerván Apr 25 '18 at 11:29
  • While true, surely there is a way to fix this without them; I'm mainly curious as to why sorted is spitting back the string represntation for each instance rather than just leaving the objects alone like one might expect. – Jenna Apr 25 '18 at 11:32
  • Does anyone have any idea? :S – Jenna Apr 25 '18 at 11:38

1 Answers1

0

You got the memory address, because the () is missing at the end.

print(e2.get_name) -> <bound method s.get_name of ...
print(e2.get_name()) -> Bill

The other q:

class s(object):
    def __init__(self, name):
        self._name = name

    def get_name(self):
        return str(self._name)

    def __repr__(self):
        return str(self._name)

 def val(x):
     #This used in place of a lambda
     return x[0]._name.lower()

 e1 = s("Fred")
 e2 = s("Bill")
 list1 = [(e1, 3), (e2, 4)]

 for n in list1:
     print(val(n))

 list2 = sorted(list1, key = val)

 print(list2[0] == e2)

Out: fred bill [(Bill, 4), (Fred, 3)] False

The False is because the compare check the tuple for the object. If you change it to list2[0][0] == e2, it will return True

  • So I need to change __repr__ for this to work? Is there any reason why sorted() is replacing the object in the tuple by its string representation? (Basically can this be done without changing __repr__?) – Jenna Apr 25 '18 at 11:47
  • @BenjaminGervin you added the __repr__, the class objects are then replaced with the name. I think the real question was that why is sorted returning raw objects instead of the original objects name like e1 and e2 – fazkan Apr 25 '18 at 11:59
  • I'll take that as a no? – Jenna Apr 25 '18 at 12:02
  • I answered that in the first few line, the missing parenthese caused that. – Benjámin Gerván Apr 25 '18 at 12:14
  • And the other is, the list of tuples, the `__repr__` needed, whitout it, the representation is like in the question. – Benjámin Gerván Apr 25 '18 at 12:15
  • The e1, and e2 only variables, the object won't be show as default representation it, I can address a million of different variable, the object wil be the same. I don't think the question pointed to that. But if so, the asnwer is right here. – Benjámin Gerván Apr 25 '18 at 12:20
  • But why is it needed? – Jenna Apr 25 '18 at 12:22
  • Useful link: https://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python In short: the repr tells the python how to represent the object. By default it a memory address and class name (`<__main__.s at...="" but="" define="" have="" it.="" object="" possibility="" the="" to="" you=""> – Benjámin Gerván Apr 25 '18 at 12:27