Reputation: 21
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
Upvotes: 2
Views: 58
Reputation: 8510
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.
Upvotes: 3