Python 'object() takes no parameters' error - python

I have the class parameter below which should return the index of 2 numbers within the 'nums' list that sums up to the target.
When I tried to test the class using 9 as the target by writing 'Solution(nums,9)', Python returned the 'TypeError: object() takes no parameters' error. Can anyone advise me on what I did wrong in my script?
nums = [2, 7, 11, 15]
class Solution(object):
def twoSum(self, nums, target):
nums_1 = nums
for i in range(len(nums)):
for a in range(len(nums_1)):
if i != a:
if nums[i] + nums_1[a] == target:
return(sorted([i, a]))
Solution(nums,9)
Traceback (most recent call last):
TypeError: object() takes no parameters

You can't use it like that, because your class have default __init__(which your class get by default, since you didn't define it), and it doesn't take any parameters unless you define it to take it.
Use the following:
sol = Solution()
sorted_stuff = sol.twoSum(nums, 9)
print(sorted_stuff)

You have missed the __init__() method while defining your Solution class. Its not always compulsory, but since you are creating an instance of the class by calling Solution() with some arguments, the __init__ method must be implemented. So the implementation can be:
_nums = [2, 7, 11, 15]
class Solution(object):
def __init(nums, target):
self.nums = nums
self.target = target
def twoSum(self, nums=None, target=None):
if not nums:
nums = self.nums
if not target:
target= self.target
nums_1 = nums
for i in range(len(nums)):
for a in range(len(nums_1)):
if i != a:
if nums[i] + nums_1[a] == target:
return(sorted([i, a]))
s = Solution(_nums,9)
s.twoSum()
Also you can do:
s = Solution()
s.twoSum(_nums,9)
This gives you the freedom to either have the args defined during the class initialization or calling the actual method with the args.

Related

python merge sort within a class

I am trying to make merge sort work within a class "Sorter for a python project, using the first code. The problem is that whenever I initialize the code, it calls the error "merge_sort' is not defined", and if I remove the "merge_sort" and use "left = lst[:mid]", it only cuts the list into half & reorganizes, but doesn't complete the script with the whole list. Is there a way to get around this issue? Thanks!!
from sorter import Sorter
unsorted_list = [5, -3, 4, 10, -14, 2, 4, -5]
my_sorter = Sorter()
my_sorter.unsorted_tuple = tuple(unsorted_list)
sorted_list = my_sorter._merge_sort()
print(sorted_list)
My code:
class Sorter():
def __init__(self):
self.unsorted_tuple = tuple([])
self.algorithm = 'default'
def generate_new_tuple(self, n):
new_list = []
for x in range (0, n):
new_list.append(random.randint(0, maxsize))
tuple(new_list)
self.unsorted_tuple = new_list
return None
def _merge_sort(self, reverse=False):
lst = list(self.unsorted_tuple)
result = []
i,j = 0,0
if(len(lst)<= 1):
return lst
mid = int(len(lst)/2)
left = _merge_sort(lst[:mid])
right = _merge_sort(lst[mid:])
while i<len(left) and j<len(right):
if left[i] <= right[j]:
result.append(left[i])
i+=1
else:
result.append(right[j])
j+=1
result += left[i:]
result += right[j:]
return result
You're confused about how classes and methods work.
The compiler is correct (by definition ...): there is no function _merge_sort. That name applies to a method, and must be called with a Sorter object. You have gone to a lot of trouble to set up this class, but then you've ignored those encapsulation protections when you try to recur on the halves of your list:
left = _merge_sort(lst[:mid])
right = _merge_sort(lst[mid:])
You're trying to invoke your method as if it were a common function. Instead, you have to instantiate Sorter objects for each half of the list, set their unsorted attributes to those half-lists, and then you can invoke the method on each of those. Something like:
left_half = Sorter()
left_half.unsorted_tuple = lst[:mid]
left = left_half._merge_sort()
right_half = Sorter()
right_half.unsorted_tuple = lst[mid:]
right = right_half._merge_sort()
Please consider the "weight" of this code; perhaps you can reconfigure your class to better support your needs. For starters, give __init__ another parameter for the initial value of the list/tuple.
Does that get you moving?

Python - implement CUSTOM "lshift" method - but not for bitarray elements

I have a class which has as parameter list of integer values.
I must implement custom lshift method which will do the adding to the list (I must override lshift method for my use case). This is custom lshift method so it does not have anything with bitarrays but only working with integers in the list (adding it to the list ) and it receives argument element. I should do this without import of additional python classes. I have defined also tests for this functionality so you can see how result should look like. (I have already implemented custom methods for add,len and iter but I suppose this is not relevant)
class CustomShift:
def __init__(self, iterator=None):
self.iterator = iterator
if (self.iterator):
self.iterator = list(dict.fromkeys(self.iterator))
def __lshift__(self, element):
"""Add an element to the list.
>>> shiftInstance = CustomShift()
>>> _ = shiftInstance << 4
>>> sorted(shiftInstance << 5 << 6 << 4)
[4, 5, 6]
"""
if self.iterator is None:
self.iterator = []
if element:
self.iterator.append(element)
if __name__ == "__main__":
import doctest
from pprint import pprint
doctest.testmod()
first two tests pass, but third fails!
TypeError: unsupported operand type(s) for <<: 'NoneType' and 'int'
Not sure what I am doing wrong, any hint will be appreciated.
Thanks in advance
First off, __lshift__ need to return a value - even if it mutates the instance it is working on. In order for chaining to work the way you expect to, it must return itself. Since the first << operation doesn't return anything, any subsequent ones will result in the TypeError exception you noted.
Second, the __lshift__ method has a logic error - the element is only appended if the iterator argument is None. Thus in the most general use case that you intend, nothing would actually happen.
Finally, in your test case, you wanted to call sort on the object which implies that this object need to provide some kind of iterator (via __iter__), otherwise it will simply fail with TypeError: 'CustomShift' object is not iterable. Putting this together, your class will look like so:
class CustomShift:
def __init__(self, iterator=None):
self.iterator = iterator
if (self.iterator):
self.iterator = list(dict.fromkeys(self.iterator))
def __lshift__(self, element):
"""Add an element to the list.
>>> shiftInstance = CustomShift()
>>> _ = shiftInstance << 4
>>> sorted(shiftInstance << 5 << 6 << 4)
[4, 5, 6]
"""
if self.iterator is None:
self.iterator = []
if element:
self.iterator.append(element)
return self
def __iter__(self):
return iter(self.iterator)
However, the test will still fail, because as it is structured, shiftInstance already has a 4 appended which was assigned to _.
Failed example:
sorted(shiftInstance << 5 << 6 << 4)
Expected:
[4, 5, 6]
Got:
[4, 4, 5, 6]
This should however put you towards a direction on how you might want to proceed from what you got.

Using the map() function within a class

I've been trying to get the map() function to work within a class but have had trouble because I'm not sure if I should be passing self into it. If so, I'm unsure how to make self into a list to go with my other iterables. Here is my code so far:
from itertools import repeat
class test:
def __init__(self):
self.nums = [1, 4, 8]
self.empty_list = []
map(self.fxn, repeat(self, len(self.nums)), self.nums)
print(self.empty_list)
def fxn(self, num):
self.empty_list.append(num ** num)
instance = test()
Even after trying to append to the empty list, the list still seems to be blank, what am I doing wrong in that example?
map doesn't mutate its argument. It returns a new iterable.
self.nums = list(map(...))
test.fxn is a function of two arguments: self and num. self.fxn is a bound method of one argument: num. Since you're just repeatedly applying it on self, you can bind it and save yourself the extra argument.
self.nums = list(map(self.fxn, self.nums))
You can change map(self.fxn, repeat(self, len(self.nums)), self.nums) to self.empty_list=list(map(self.fxn,self.nums)) which is equivalent to self.empty_list=list(map(lambda x: self.fxn(x),self.nums)) and self.empty_list=[self.fxn(i) for i in self.nums] and remember to change fxn() from self.empty_list.append(num ** num) to return num ** num (and since it is list(map(...))-list it will be a list), so try the below:
class test:
def __init__(self):
self.nums = [1, 4, 8]
self.empty_list=list(map(self.fxn,self.nums))
print(self.empty_list)
def fxn(self, num):
return num ** num
instance = test()
Output:
[1, 256, 16777216]

Second argument of the iter() method

I'm trying to figure out how to make iterator, below is an iterator that works fine.
class DoubleIt:
def __init__(self):
self.start = 1
def __iter__(self):
self.max = 10
return self
def __next__(self):
if self.start < self.max:
self.start *= 2
return self.start
else:
raise StopIteration
obj = DoubleIt()
i = iter(obj)
print(next(i))
However, when I try to pass 16 into the second argument in iter() (I expect the iterator will stop when return 16)
i = iter(DoubleIt(), 16)
print(next(i))
It throws TypeError: iter(v, w): v must be callable
Therefore, I try to do so.
i = iter(DoubleIt, 16)
print(next(i))
It returns <main.DoubleIt object at 0x7f4dcd4459e8>. Which is not I expected.
I checked the website of programiz, https://www.programiz.com/python-programming/methods/built-in/iter
Which said that callable object must be passed in the first argument so as to use the second argument, but it doesn't mention can User defined object be passed in it in order to use the second argument.
So my question is, is there a way to do so? Can the second argument be used with the "Self defined Object"?
The documentation could be a bit clearer on this, it only states
iter(object[, sentinel])
...
The iterator created in this case will call object with no arguments
for each call to its __next__() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.
What is maybe not said perfectly clearly is that what the iterator yields is whatever the callable returns. And since your callable is a class (with no arguments), it returns a new instance of the class every iteration.
One way around this is to make your class callable and delegate it to the __next__ method:
class DoubleIt:
def __init__(self):
self.start = 1
def __iter__(self):
return self
def __next__(self):
self.start *= 2
return self.start
__call__ = __next__
i = iter(DoubleIt(), 16)
print(next(i))
# 2
print(list(i))
# [4, 8]
This has the dis-/advantage that it is an infinite generator that is only stopped by the sentinel value of iter.
Another way is to make the maximum an argument of the class:
class DoubleIt:
def __init__(self, max=10):
self.start = 1
self.max = max
def __iter__(self):
return self
def __next__(self):
if self.start < self.max:
self.start *= 2
return self.start
else:
raise StopIteration
i = iter(DoubleIt(max=16))
print(next(i))
# 2
print(list(i))
# [4, 8, 16]
One difference to note is that iter stops when it encounters the sentinel value (and does not yield the item), whereas this second way uses <, instead of <= comparison (like your code) and will thus yield the maximum item.
Here's an example of a doubler routine that would work with the two argument mode of iter:
count = 1
def nextcount():
global count
count *= 2
return count
print(list(iter(nextcount, 16)))
# Produces [2, 4, 8]
This mode involves iter creating the iterator for us. Note that we need to reset count before it can work again; it only works given a callable (such as a function or bound method) that has side effects (changing the counter), and the iterator will only stop upon encountering exactly the sentinel value.
Your DoubleIt class provided no particular protocol for setting a max value, and iter doesn't expect or use any such protocol either. The alternate mode of iter creates an iterator from a callable and a sentinel value, quite independent of the iterable or iterator protocols.
The behaviour you expected is more akin to what itertools.takewhile or itertools.islice do, manipulating one iterator to create another.
Another way to make an iterable object is to implement the sequence protocol:
class DoubleSeq:
def __init__(self, steps):
self.steps = steps
def __len__(self):
return self.steps
def __getitem__(self, iteration):
if iteration >= self.steps:
raise IndexError()
return 2**iteration
print(list(iter(DoubleSeq(4))))
# Produces [1, 2, 4, 8]
Note that DoubleSeq isn't an iterator at all; iter created one for us using the sequence protocol. DoubleSeq doesn't hold the iteration counter, the iterator does.

How to modify the value of index while trying to fecth it?

For example there is a list called Demo_list.
Demo_list = [4,5,6,7]
If i give
Demo_list[0]
we will get value as 4.
But if i gave only Demo_list[0] i want to get square of that value and the list should not be modified.
Is it possible?
Yes, it is possible.
variable = Demo_list[0]**2
The code above won't modify the list.
demo_list = [4, 6, 7, 8]
for i in range (len(demo_list)):
j = demo_list[i] * demo_list[i]
print j
May be you are looking something like that..
#For complete list
SqrtList = [x**2 for x in Demo_list]
#For single element
Sqrtvariable = Demo_list**2
You can use the < math > function
import math
print ( math.pow(demo[0],2)
where, 2 is the power that you want to raise the value in demo[0].
Edit (Inheriting from the collections, and overriding the abstract list methods , in your case (getitem),that you wish to modify).
import collections
class MyList(collections.MutableSequence):
def __init__(self, *args):
self.list=list()
self.extend(list(args))
def __len__(self):
return len(self.list)
def __getitem__(self,i):
return (self.list[i]**2)
def __delitem__(self,i):
del self.list[i]
def __setitem__(self,i,v):
self.list[i]=v
def insert(self,i,v):
self.list.insert(i,v)
def __str__(self):
return str(self.list)
Note: When you override these abstract methods, you need to define your list, with the type, you declared in this class. i.e.,
demo_list=MyList(1,2,3,4)
demo_list[1]
Output : 4

Categories

Resources