SyntaxError: non-default argument follows default argument; __init__ related [duplicate] - python

This question already has answers here:
Why can't non-default arguments follow default arguments?
(4 answers)
Closed 5 years ago.
This is my last resort. I've searched everywhere, but it's always pertaining to it being re-written by another function or something. I assure you there is no other function that uses this init thing. I'm a beginner.
The error is that I get this: SyntaxError: non-default argument follows default argument. It points towards __init__([here]self, ...etcetc).
class book:
def __init__(self, bookId, nextBook=None, name, author, ageGroup):
self.bookId = bookId
self.nextBook = nextBook
self.name = str(name)
self.author = str(author)
self.ageGroup = str(ageGroup)
def getInfo(self):
return self.bookdId
def setInfo(self, bookId, bookName, authorName, ageGroup):
self.bookId = bookId
self.name = bookName
self.author = authorName
self.ageGroup = ageGroup
def getNextBook(self):
return self.nextBook
def setNextBook(self,val):
self.nextBook = val
class bookCollection:
def __init__(self,head = None):
self.head = head
self.size = 0
def getSize(self):
return self.size
def addBookToFront(self,bookId):
newBook = book(bookId,self.head)
self.head = newBook
self.size+=1
return True
def listAllBooks(self):
curr = self.head
while curr:
print(curr.data)
print(curr.name)
curr = curr.getNextBook()
def deleteBook(self,value):
prev = None
curr = self.head
while curr:
if curr.getInfo() == value:
if prev:
prev.setNextBook(curr.getNextBook())
else:
self.head = curr.getNextBook()
return True
prev = curr
curr = curr.getNextBook()
return False
def addBookAtPosition(self, newBookId, position):
counter = 1
if position == 0:
newBookId.setNextBook(self.head)
self.head = newBookId
else:
book = self.head
while book.getNextBook() is not None:
if counter == position:
newBookId.setNextBook(book.getNextBook())
book.setNextBook(newBookId)
book = book.getNextBook()
counter = counter + 1
def removeBookAtPosition(self, removedBookId, position):
counter = 1
if position == 0:
self.head = removedBookId.getNextBook()
else:
book = self.head
while book.getNextBook() is not None:
if counter == position - 1:
book.setNextBook(removedBookId.getNextBook())
book = book.getNextBook()
counter = counter + 1
#for reference: bookId, bookName, authorName, ageGroup
Boy = book(1, Boy, Roald-Dahl, Teens)

It's complaining about this line:
def __init__(self, bookId, nextBook=None, name, author, ageGroup):
Argument nextBook has a default value, namely None.
But arguments name, author and ageGroup don't have default values.
That is prohibited by the interpreter, or, more exact, by the parser part of the interpreter.
Either don't give nextBook a default value, or give default values also for name, author and ageGroup. If you want a default value only for nextBook, make it the last parameter, so after name, author and ageGroup.

Related

overload the > operator (__gt__)

I want my Book class to overload the > operator __gt__. So, I can use it in my BookCollection to find the right order.
I used > in InsertBook(). But it is not working! How do I fix it? I want it to be ordered by
the Book’s author (alphabetical / lexicographical order)
the Book’s year of publication
the Book’s title (alphabetical / lexicographical order).
This is my current code for the class Book.py:
class Book:
def __init__(self, title='', author='',year=None):
self.title = title
self.author = author
self.year = year
def setTitle(self, title):
self.title = title
def setAuthor(self, author):
self.author = author
def setYear(self, year):
self.year = year
def getTitle(self):
return self.title
def getAuthor(self):
return self.author
def getYear(self):
return self.year
def __gt__(self,item):
if (0,1,0) > (0,0,0):
return self.author > item.author
else:
return False
if (1,0,0) > (0,0,0):
return self.title > item.title
else:
return False
if (0,0,1) > (0,0,0):
return self.year > item.year
else:
return False
def getBookDetails(self):
return "Title: {}, Author: {}, Year: {}".format(self.title, self.author, self.year)
class BookCollection():
def __init__(self):
self.head = None
def isEmpty(self):
return self.head == None
def insertBook(self, book):
current = self.head
previous = None
stop = False
while current != None and not stop:
if current.getData() > book:
stop = True
else:
previous = current
current = current.getNext()
temp = BookCollectionNode(book)
if previous == None:
temp.setNext(self.head)
self.head = temp
else:
temp.setNext(current)
previous.setNext(temp)
def getNumberOfBooks(self):
temp = self.head
count = 0
while temp != None:
count = count + 1
temp = temp.getNext()
return count
def getAllBooksInCollection(self):
current = self.head
output = ""
while current != None:
output += str(current.getData()) + " "
current = current.getNext()
output = output[:len(output)-1] + "\n"
return output
def getBooksByAuthor(self,item):
current = self.head
found = False
stop = False
while current != None and not found and not stop:
if current.getData() == item:
found = True
else:
if current.getData() > item:
stop = True
else:
current = current.getNext()
return found
I used > in InsertBook(). But it is not working! How do I fix it? I want it to be ordered by
Your overload of the method makes no sense, why are you comparing completely static tuple values? That's always going to do the same thing, so your entire override is really just return self.author > item.author
Overriding __gt__ alone is a bad idea: you really need to override them all or you'll get incoherent result. The functools.total_ordering class decorator allows overriding just __eq__ and one ordering operator, you probably want to use that.
I want it to be ordered by
the Book’s author (alphabetical / lexicographical order)
the Book’s year of publication
the Book’s title (alphabetical / lexicographical order).
Then compare that? I'd recommend a key method or property for simplicity e.g.
#total_ordering
class Book:
#property
def _key(self):
return (self.author, self.year, self.title)
def __eq__(self, other):
return self._key == other._key
def __gt__(self, other):
return self._key > other._key
should do the trick and order your records by ascending author, ascending year of publication, and ascending title
That aside,
Python is not Java
All your trivial getters and setters are useless and redundant, just remove them outright. And getBookDetails should just be the implementation of your __str__.
BookCollection is similarly concerning, isEmpty is not a thing in Python, instead collections implement __len__ (and optionally __bool__ for efficiency). And the entire thing is a mess, why doesn't BookCollection just contain a list of books (or some other collection from the stdlib)? What's the purpose of making it some sort of ad-hoc half-assed linked list?
And it shoudl provide (or use) an iterator, you're implementing the same iteration scheme 3 different times for no reason.
Your naming scheme is also incorrect, Python normally uses snake_case for methods, and properties, and fields.

Trying to traverse a linked list twice

I am having some trouble with linked lists in Python. For a problem I am supposed to do trivia like question and answer with linked lists, each node having a question and answer. I am supposed to have the program go through the list over and over until each question is answered correctly twice. The following code is the method I made to do this.
class trivia(object):
def __init__(self, question, answer):
self.question = question
self.answer = answer
self.next = None
def getQuestion(self):
return self.question
def getAnswer(self):
return self.answer
def getNext(self):
return self.next
def setNext(self, next):
self.next = next
class triviaDeck(object):
def __init__(self):
self.head = None
def size(self):
current = self.head
count = 0
while current != None: # while not at the end of the list
count += 1
current = current.getNext()
return count
def showTrivia(self, pos=None):
if pos == None:
pos = self.size() - 1
if pos < self.size() and pos >= 0:
current = self.head
previous = None
index = 0
count = 0
while count != 2:
print(current.getQuestion())
answer = input()
if answer == current.getAnswer():
print("Correct")
count = count + 1
if current.getNext() == 2:
current = self.head
else:
current = current.getNext()
def add(self, question, answer):
temp = trivia(question, answer)
temp.setNext(self.head)
self.head = temp
if __name__ == '__main__':
deck = triviaDeck()
deck.add("A", "A")
deck.add("B", "B")
deck.add("C", "C")
deck.showTrivia()
Currently this code just goes through the list once and then exits.
For a circular linked list:
The first node inserted should point to itself
For additional nodes, adjust the pointers to insert the new node after the head
Try this code:
def add(self, question, answer):
temp = trivia(question, answer)
if not self.head: # first node
self.head = temp
temp.setNext(self.head) # single node, loop to itself
else: # add node
temp.setNext(self.head.getNext()) # shift loop
self.head.setNext(temp) # insert just after head
Also - For the count = 2 logic:
The node (trivia) object should have a counter property which counts correct responses to that question
If the response counter = 2, remove that node from the linked list
When the last node is removed, game over

Doubly-linked list in Python

It turned out to be an error as a time limit was exceeded,
but I've already raised the StopIteration...
I think I did something wrong for my iteration part, but it's really hard to find the error. The test output keeps running and even printed out the None value. How does it happen?
class LinkedListIterator:
def __init__(self, head):
self.__current = head.get_next()
def __iter__(self):
return self
def __next__(self):
if self.__current == None:
raise StopIteration
else:
item = self.__current.get_data()
self.__current = self.__current.get_next()
return item
These were the inputs I used to run the program:
my_list = LinkedListDLL()
my_list.add_to_head(1)
print("Contents:", end=" ")
for node in my_list:
print(node, end=" ")
print()
This code is meant to stop iteration when it reaches the head of the list.
if self.__current == None:
raise StopIteration
However, you represent the head with a NodeDLL object which is different from None.
You could keep a reference to the head and check against that instead:
class LinkedListIterator:
def __init__(self, head):
self._head = head
self._current = head.get_next()
def __iter__(self):
return self
def __next__(self):
if self._current is self._head:
raise StopIteration
else:
item = self._current.get_data()
self._current = self._current.get_next()
return item
What you want to implement is the API of a MutableSequence with the implementation of a doubly-linked-list.
To do that in Python, you should rely on collections.abc which can guide you through the process of implementing all required methods.
By example, a linked-list is actually a class inheriting from MutableSequence.
from collections.abc import MutableSequence
class LinkedList(MutableSequence):
pass
ll = LinkedList()
On instantiation of a class which has some abstract methods not yet written, you will get a TypeError which will guide you through which methods need to be implemented.
TypeError: Can't instantiate abstract class LinkedList with abstract methods __delitem__, __getitem__, __len__, __setitem__, insert
In particular, note that a list or a linked-list is not an iterator, it is an iterable. What this means is the __iter__ method should not return self and rely on __next__, it should instead return a brand new iterator on the content of the linked-list.
In other words, you can iterate only once through an iterator and multiple times through and iterable.
Full implementation
It turns out I have a full implementation of a doubly-linked-list implemented that way. You can have a look.
from collections.abc import MutableSequence
class LinkedList(MutableSequence):
class _Node:
def __init__(self, value, _next=None, _last=None):
self.value, self._next, self._last = value, _next, _last
def __str__(self):
return f'Node({self.value})'
def __init__(self, iterable=()):
self.start = None
self.last = None
empty = object()
iterable = iter(iterable)
first = next(iterable, empty)
if first is empty:
return
current = self._Node(first)
self.start, self.last = current, current
for value in iterable:
new_node = self._Node(value, _last=self.last)
self.last._next = new_node
self.last = new_node
def __len__(self):
if self.start is None:
return 0
else:
return sum(1 for _ in self)
def __iter_nodes(self):
current = self.start
while current is not None:
yield current
current = current._next
def __reversed_iter_nodes(self):
current = self.last
while current is not None:
yield current
current = current._last
def __iter__(self):
for node in self.__iter_nodes():
yield node.value
def __reversed__(self):
for node in self.__reversed_iter_nodes():
yield node.value
def __get_node(self, index):
if index >= 0:
for item in self.__iter_nodes():
if index == 0:
return item
index -= 1
else:
for item in self.__reversed_iter_nodes():
if index == 0:
return item
index += 1
raise IndexError
def __getitem__(self, index):
if index >= 0:
for item in self:
if index == 0:
return item.value
index -= 1
else:
for item in reversed(self):
if index == 0:
return item.value
index += 1
raise IndexError
def __setitem__(self, key, value):
self[key].value = value
def __delitem__(self, key):
node = self[key]
if node._last:
node._last._next = node._next
if node._next:
node._next._last = node._last
def insert(self, index, value):
if index > len(self):
self.last = self._Node(value, _last=self.last)
else:
where = self.__get_node(index)
_last = where._last
new_node = self._Node(value, _next=where, _last=_last)
if _last:
_last._next = new_node
else:
self.start = new_node
where._last = new_node
Example
ll = LinkedList(range(1, 5))
print(*ll)
print(*reversed(ll))
ll.insert(2, 'foo')
print(*ll)
Output
1 2 3 4
4 3 2 1
1 2 foo 3 4

Sometimes None is printed - and sometimes it doesn't, can't get why?

I got this school assignment, here is my code:
class Doubly_linked_node():
def __init__(self, val):
self.value = val
self.next = None
self.prev = None
def __repr__(self):
return str(self.value)
class Deque():
def __init__(self):
self.header = Doubly_linked_node(None)
self.tailer = self.header
self.length = 0
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (index.next is None):
string+=" " + str(index.next.value)
index = index.next
return string
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
self.header.prev=new
self.header=new
self.length+=1
if self.tailer.value==None:
self.tailer = self.header
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
self.tailer.next=new
self.tailer=new
self.length+=1
if self.header.value==None:
self.header = self.tailer
it builds a stack, allowing you to add and remove items from the head or tail (I didn't include all the code only the important stuff).
When I initiate an object, if I return self.next it prints None, but if I return self.prev, it prints nothing, just skips, I don't understand why since they are both defined exactly the same as you see, and if I insert only head several times for example for i in range(1,5): D.head_insert(i) and then I print D it prints 5 4 3 2 1 None but if I do tail insert for example for i in range(1,5): D.tail_insert(i) and print D it prints 1 2 3 4 5"as it should without the None. Why is that?
I have included an image:
Keep in mind that you create a Deque which is not empty. You're initializing it with a Node with value None
You're interchanging the value and the Node object. When you're checking if self.tailer.value==None: it's probably not what you're meaning
Following to point 2 is a special handling for the empty Deque, where header and tailer is None
Here is what I have in mind, if I would implement the Deque. I'm slightly changed the return value of __repr__.
class Deque():
def __init__(self):
self.header = None
self.tailer = None
self.length = 0
def __repr__(self):
if self.header is None:
return 'Deque<>'
string = str(self.header.value)
index = self.header.next
while index!=None:
string+=" " + str(index.value)
index = index.next
return 'Deque<'+string+'>'
def head_insert(self, item):
new = Doubly_linked_node(item)
new.next=self.header
if self.length==0:
self.tailer=new
else:
self.header.prev=new
self.header=new
self.length+=1
def tail_insert(self, item):
new = Doubly_linked_node(item)
new.prev=self.tailer
if self.length==0:
self.header=new
else:
self.tailer.next=new
self.tailer=new
self.length+=1
Following Günthers advice, I have modified the __repr__ to this:
def __repr__(self):
string = str(self.header.value)
index = self.header
while not (str(index.next) == "None"):
string += (" " + str(index.next.value))
index = index.next
return string
that did solve the problem, but it is the ugliest solution I have ever seen.
does anyone know a better way?
Following to the question of a better __repr__ method here my proposal. Extend the Deque class with an __iter__ method. So you can iterate over the Deque which is nice to have, e.g.:
for item in D:
print item
Based on that the __repr__ method is easy. Here is the whole change:
def __repr__(self):
return 'Deque<'+' '.join([str(item.value) for item in self])+'>'
def __iter__(self):
index=self.header
while index is not None:
yield index.value
index=index.next

Use a function built outside the class on an object in Python?

I have a class
class List:
def __init__(self,head,tail):
self.head = head
self.tail = tail
def cons(self,item):
return List(item,self)
def isEmpty(self):
return self.head == None
def display(self):
s = "["
first = True
list = self
while not list.isEmpty():
if not first:
s=s+","
first = False
s=s+str(list.head)
list = list.tail
s=s+"]"
return s`
which creates a List object. I have a function (not sure if it works yet);
def sorted(list):
sort = False
i = 0
while i < range(len(list))+1:
if list[i] < list[i+1]:
sort = True
return sort
else:
return sort
and I want to run this function on the List object without adding another method to the class. I know if this was in the class it would just be List.sorted() but how can I run this function on the object without it being the objects method?
sorted(List) doesn't seem to work either. Help please.
Please, please, PLEASE: don't use sorted as a function name. There is a standard (built-in) function sorted() already, that returns a sorted version of an iterable.
Given that your code just checks to see if the List is in order, perhaps you could call it in_order or ordered or is_ascending instead?
That said, let's try to get your code working:
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
class List:
def __init__(self, head:Node=None, tail:Node=None):
self.head = tail if head is None else head
self.tail = head if tail is None else tail
def cons(self, node:Node):
node.next = self.head
return List(node, self.tail)
def isEmpty(self):
return self.head == None
def display(self):
return str(self)
def __str__(self):
result = "["
first = True
n = self.head
while n is not None:
if not first:
result += ", "
result += str(n)
if n == self.tail:
break
n = n.next
first = False
result += "]"
return result
def ascendingp(self) -> bool:
n = self.head
last = None
while last != self.tail:
if last is not None and not last.data < n.data:
return False
last = n
n = n.next
return True
tests = (
(1,2,3),
(1,3,2),
(),
)
for t in tests:
last = None
first = None
for i in reversed(t):
n = Node(data=i)
first = n if first is None else first
n.next = last
last = n
l = List(head=last, tail=first)
print(str(l), "Ascending?", l.ascendingp())

Categories