2

I am fairly new to Python and I am a bit confused that how are the l1 and l2 in the second function merge(self,l1,l2) accessing to .val? If we did not declare l1 and l2 as ListNode in the parameter of the merge function then how does it know that l1 and l2 are nodes and access to .val?

If someone can explain the concept I would really appreciate it. TIA

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if not lists or len(lists) == 0:
            return None
        
        while len(lists) > 1:
            combinedList = []
            for i in range(0, len(lists), 2):
                
                l1 = lists[i]
                    
                l2 = lists[i+1] if (i+1) < len(lists) else None
                combinedList.append(self.merge(l1,l2))
            
            lists = combinedList
            
        return lists[0]
            
        
    def merge(self, l1, l2):
        dummy = ListNode()
        output = dummy
        
        while l1 and l2:
            if l1.val < l2.val:
                output.next = l1
                l1 = l1.next
            else:
                output.next = l2
                l2 = l2.next
            output = output.next
                
        if l1:
            output.next = l1
        elif l2:
            output.next = l2
        
        return dummy.next
3
  • 2
    It doesn't need to know exactly what type is passed, what matters is that the object has .val etc. Commented Jul 18, 2022 at 3:36
  • 2
    If the l1 variable refers to an object that has a val attribute, then l1.val is a reference to the value of that attribute. Python doesn't need to know the type of l1 in advance, the object carries its type information with it. (Keep in mind that type hints, like the mergeKLists() method has, are for the benefit of external verification tools; Python doesn't actually use them for anything.) Commented Jul 18, 2022 at 3:37
  • 4
    "If we did not declare l1 and l2 as ListNode in the parameter of the merge function then how does it know that l1 and l2 are nodes and access to .val?" Python is a dynamically typed language. Those are simply "type annotations" which function as "type hints", they are not enforced at runtime, and are mainly for use as documentation, linters, and third-party tools (that may allow you to statically analyze your code). Commented Jul 18, 2022 at 3:53

1 Answer 1

3

How does it know? simple, it doesn't.

Unless you explicitly check if the thing you pass into any given function is what you want, that function simple doesn't know what is the thing you give it too, and will simple fail with some error or give some unexpected result if it isn't the desired thing.

Python is dynamically typed language that rely heavily in the so called duck typing, which can be summed up as: if it look like a duck, quack like a duck and walk like a duck, then is a duck.

now lets take a look to a quick example:

class MyObject:
    def __init__(self, val):
        self.val = val

here we defined some object, with the characteristic of having a .val attribute

now let make a function to do something with it

def fun(item:MyObject):
    return item.val + 10
     

and quickly test it

a = MyObject(10)
print(fun(a))

and it will print 20 just as expected.

But python is a dynamic language, and what that mean? it mean that you can at run time modify object, in any way, so you can make some completely different object look like any other, like

class B:
    pass

b=B()

as you see the b object can't more different from MyObject from before, it simple doesn't have anything, no attribute whatsoever (beside the default one every class have, but I digress), so it definitively would not work with fun, and it certainly doesn't, this will give you and error

print(fun(b))
#AttributeError: 'B' object has no attribute 'val'

but you can make it work

b.val=22
print(fun(b))

that will print 32, what happens here? we simple at run time added a new attribute to our b object, now, as far as fun is concerned our B instance is the same as a MyObject because it have a .val attribute that can be added with a number so is irrelevant if it is really a MyObject or not.

ok, but what about the signature of fun it clearly specify that it want a MyObject, right? that is a type annotation or type hint, it have no effect at run time, it is for documentation purposes and to clue us the programmers and/or user of the code of what is the proper intended usage of it, and for other third party tool that use those to analyse the code statically to detect bug that otherwise might pass undetected.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.