问题
So I have a function defined that works great at doing merge sort on a linear array if it is implemented by its lonesome, but if I put it into a class it bugs out. I think it's a great example of what I don't quite understand about how classes work; possibly in regards to namespace management(?).
See below:
def sort(array):
print('Splitting', array)
if len(array) > 1:
m = len(array)//2
left = array[:m]
right = array[m:]
sort(left)
sort(right)
i = 0
j = 0
k = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
array[k] = left[i]
i += 1
else:
array[k] = right[j]
j += 1
k += 1
while i < len(left):
array[k] = left[i]
i += 1
k += 1
while j < len(right):
array[k] = right[j]
j += 1
k += 1
print('Merging', array)
arr = [1,6,5,2,10,8,7,4,3,9]
sort(arr)
Produces the expected correct output:
Splitting [1, 6, 5, 2, 10, 8, 7, 4, 3, 9]
Splitting [1, 6, 5, 2, 10]
Splitting [1, 6]
Splitting [1]
Merging [1]
Splitting [6]
Merging [6]
Merging [1, 6]
Splitting [5, 2, 10]
Splitting [5]
Merging [5]
Splitting [2, 10]
Splitting [2]
Merging [2]
Splitting [10]
Merging [10]
Merging [2, 10]
Merging [2, 5, 10]
Merging [1, 2, 5, 6, 10]
Splitting [8, 7, 4, 3, 9]
Splitting [8, 7]
Splitting [8]
Merging [8]
Splitting [7]
Merging [7]
Merging [7, 8]
Splitting [4, 3, 9]
Splitting [4]
Merging [4]
Splitting [3, 9]
Splitting [3]
Merging [3]
Splitting [9]
Merging [9]
Merging [3, 9]
Merging [3, 4, 9]
Merging [3, 4, 7, 8, 9]
Merging [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
However, I get an error when I attempt to use this function in a class; something to do with namespace managment, I think. See below:
class MergeSort(object):
def __init__(self, array):
self.array = array
def sort(self):
print('Splitting', self.array)
if len(self.array) > 1:
m = len(self.array)//2
left = self.array[:m]
right = self.array[m:]
sort(left)
sort(right)
i = 0
j = 0
k = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
self.array[k] = left[i]
i += 1
else:
self.array[k] = right[j]
j += 1
k += 1
while i < len(left):
self.array[k] = left[i]
i += 1
k += 1
while j < len(right):
self.array[k] = right[j]
j += 1
k += 1
print('Merging', self.array)
x = MergeSort([1,6,5,2,10,8,7,4,3,9])
x.sort()
Produces the error output:
Splitting [1, 6, 5, 2, 10, 8, 7, 4, 3, 9]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-15-89509f86277e> in <module>()
1 x = MergeSort([1,6,5,2,10,8,7,4,3,9])
----> 2 x.sort()
<ipython-input-14-2bba116f00ce> in sort(self)
11 right = self.array[m:]
12
---> 13 sort(left)
14 sort(right)
15
NameError: name 'sort' is not defined
My initial instinct, after google searching around was to change subroutines sort(left) and sort(right) by adding prefixive self., but that generates a positional argument error. Would love a comment or two on what it is that I'm not understanding here. And cheers for good votes if my question is not stupid, and down votes if it is.
回答1:
The reason sort(left)
doesn't work is that, as you surmised, you can't call a method on self
without specifying self
. Leaving that off means it looks for a local or global name sort
, doesn't find one, and raises a NameError
.
The reason self.sort(left)
doesn't work is that the API you defined doesn't work that way. Your class takes the list as a constructor argument, and then takes a sort
with no arguments, that operates on the list passed in at construction time. So, you have no way to call your own sort
with a different array. If you try self.sort(left)
, you're passing the wrong number of arguments, just like calling abs(1, 2)
, and you get the same TypeError
.
You have to use your API the way you designed it: Create a new MergeSort
sorter object with the new list, then call sort
on that new object:
leftsorter = MergeSort(left)
leftsorter.sort()
rightsorter = MergeSort(right)
rightsorter.sort()
回答2:
Replacing the sort(left)
and sort(right)
components of the sort() function within my class with
leftsorter = MergeSort(left)
leftsorter.sort()
rightsorter = MergeSort(right)
rightsorter.sort()
(Thank you abarnert)
While at the same time removing debugging print statements from the code (thank you Evgany P), and by avoiding reusing a built in function name sort() to avoid confusion, I have a working MergeSort class.
class MergeSort(object):
def __init__(self, array):
self.array = array
def merge_sort(self):
if len(self.array) > 1:
m = len(self.array)//2
left = self.array[:m]
right = self.array[m:]
leftsorter = MergeSort(left)
leftsorter.merge_sort()
rightsorter = MergeSort(right)
rightsorter.merge_sort()
i = 0
j = 0
k = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
self.array[k] = left[i]
i += 1
else:
self.array[k] = right[j]
j += 1
k += 1
while i < len(left):
self.array[k] = left[i]
i += 1
k += 1
while j < len(right):
self.array[k] = right[j]
j += 1
k += 1
x = MergeSort([3,5,6,2,1,4,10,9,8,7])
x.merge_sort()
x.array
Out[ ]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Well done everybody!
回答3:
You need to call self.sort()
within the class.
A larger problem is that none of your function or class method return anything, just prints, are you satisfied with that?
来源:https://stackoverflow.com/questions/50754601/implementing-merge-sort-function-in-python-class-errors