How can I modify my __repr__ to respresent correctly? - python

My __repr__ method works fine using objects created in it's class, but with objects that were created with the help of importing a library and using methods from it, it only represented the memory address...
from roster import student_roster #I only got the list if students from here
import itertools as it
class ClassroomOrganizer:
def __init__(self):
self.sorted_names = self._sort_alphabetically(student_roster)
def __repr__(self):
return f'{self.get_combinations(2)}'
def __iter__(self):
self.c = 0
return self
def __next__(self):
if self.c < len(self.sorted_names):
x = self.sorted_names[self.c]
self.c += 1
return x
else:
raise StopIteration
def _sort_alphabetically(self,students):
names = []
for student_info in students:
name = student_info['name']
names.append(name)
return sorted(`your text`names)
def get_students_with_subject(self, subject):
selected_students = []
for student in student_roster:
if student['favorite_subject'] == subject:
selected_students.append((student['name'], subject))
return selected_students
def get_combinations(self, r):
return it.combinations(self.sorted_names, r)
a = ClassroomOrganizer()
# for i in a:
# print(i)
print(repr(a))
I tried displaying objects that don't rely on anther library, and they dispayed properly.

The issue I was facing was linked to me not understanding the nature of the object. itertools.combinations is an iterable, and in order to represent the values stored I needed to either:
unpack it inside a variable like:
def get_combinations(self, r):
*res, = it.combinations(self.sorted_names, r)
return res
Iter through it inside a loop and leave the original code intact like
for i in a.get_combinations(2):
print(i)
I prefer the second solution

Related

Python return result is not alike "N()"

I made the method name is slide. and it must return the reference of it. Then, What should I do?.
First, I made this function like:
class N:
def slide(self, i):
#do something
return self
This slide method must return "N()" but "<~~ obejct at x0000>"
Definitely depends on your calling code. But this, for example, will work as expected to return a reference to an instantiated object N:
class N:
i = 1
def slide(self, i):
self.i = i;
return self
n = N()
print(n.i) # 1
r = n.slide(2)
print(r.i) # 2

Why does Python detect self-references in list and dicts when printing them, but not in classes

This is a question about the design of the Python language and is motivated by curiosity.
Python is able to detect self-references in loops and dicts when printing them
l = [1,2,3,[98,99]]
l[3].append(l)
print(f"{l = }")
# l = [1, 2, 3, [98, 99, [...]]]
d = {1:None,2:None,3:None,4:{}}
d[4][98] = d
print(f"{d = }")
# d = {1: None, 2: None, 3: None, 4: {98: {...}}}
but doesn't do it when class-objects have self-references
class Node():
def __init__(self,name,parent):
self.children = []
self.name,self.parent = name,parent
def __repr__(self):
return f"{self.name}: p={self.parent},"+\
f"{[c for c in self.children]}"
top = Node("apex",None)
top.children += [Node("alpha",top),Node("beta",top)]
print(top)
# RecursionError: maximum recursion depth exceeded while getting the repr of an object
It's easy enough to detect, and below is a decorator to do it. I wondered if there was some theoretical reason why it wasn't done automatically.
# Comments on my code are welcome, I want to improve
""" foo is a class-decorator.
It takes the parameter, a function, and returns another function
that accepts a class as a parameter, the second function returns an
amended copy of the class that has a new __repr__() function """
def foo(default=lambda x:"<...>"):
def bar(origcls):
# Note that default is available within this inner-program.
# Amend __repr__ so that it saves the id of the object
# and behaves differently if it has been seen before.
# Use the class-static variable _reprlist to record calls
# and the default-program to calculate the return if this
# object is being re-visited
try:
origcls._reprlist
except:
origcls._reprlist = set()
oldrepr = origcls.__repr__
def __repr__(self):
if id(self) in origcls._reprlist:
return default(self)
else:
origcls._reprlist.add(id(self))
answer = f"{oldrepr(self)}"
origcls._reprlist.remove(id(self))
return answer
origcls.__repr__ = __repr__
return origcls
return bar
#foo(lambda x:f"<<{x.name}>>")
class Node():
def __init__(self,name,parent):
self.children = []
self.name,self.parent = name,parent
def __repr__(self):
return f"{self.name}: p={self.parent},"+\
f"{[c for c in self.children]}"
top = Node("apex",None)
top.children += [Node("alpha",top),Node("beta",top)]
print(top)
# apex: p=None,[alpha: p=<<apex>>,[], beta: p=<<apex>>,[]]

python - getting specific generator data from the generator

let's start with the code
class MyClass:
def __init__(self):
self.elemplusone = None
self.elemplustwo = None
self.data = self.generate_data()
def generate_data(self):
for elem in range(10):
yield elem+1, elem+2
I need to get the first and the second element of generator. Right now, I'm calling it outside the class after creating an object:
a_generator = MyClass()
c = next(a_generator.data)
elemplusone = c[0]
elemplustwo = c[1]
but I need them to be specified (as separate generators) in the class and I can't create two generator methods.
Thanks
I also don't quite understand what you mean exactly. But does this help you?
class MyClass:
def __init__(self):
self.data = self.generate_data()
self.update_elements()
def update_elements(self):
self.elemplusone, self.elemplustwo = [x for x in next(self.data)]
def generate_data(self):
for elem in range(10):
print("Yielded")
yield elem + 1, elem + 2
a_generator = MyClass()
a_generator.elemplusone is 1 and a_generator.elemplustwo is 2.
Now you could call a_generator.update_elements() to yield your elements again and continue in your generator. Please let me know if this helps you. Good luck!

Python - Why is my locally defined linked list updated when I call other functions that doesn't return anything [duplicate]

This question already has answers here:
Function changes list values and not variable values in Python [duplicate]
(7 answers)
Closed 7 years ago.
The code below imports a linked list from LinkedQfile and creates a list object with some node objects.
If I run this code the output from check_something() becomes CD .
I thought linked_list in check_something() would become a local object inside the function and since I'm not assigning whatever I'm returning to anything it wouldn't change, that is I would expect the output ABCD. This is obviously not the case so I'm wondering if someone could explain to me what is going on here?
If linked_list was a global variable I would expect this outcome, my guess is that the return statements in each function returns some information to the object but I have no idea how and why! (I got the code from a lecture note and it works just like I want it to, I just want to know why!)
from LinkedQFile import LinkedQ
def check_something(linked_list):
check_first_element(linked_list)
check_second_element(linked_list)
print(linked_list)
def check_first_element(linked_list):
word = linked_list.dequeue()
if word == "A":
return
def check_second_element(linked_list):
word = linked_list.dequeue()
if word == "B":
return
def main():
list = LinkedQ()
list.enqueue("A")
list.enqueue("B")
list.enqueue("C")
list.enqueue("D")
check_something(list)
main()
And if needed, the LinkedQFile:
class Node:
def __init__(self, x, next= None):
self._data = x
self._next = next
def getNext(self):
return self._next
def setNext(self, next):
self._next = next
def getValue(self):
return self._data
def setValue(self, data):
self._data = data
class LinkedQ:
def __init__(self):
self._first = None
self._last = None
self._length = 0
def __str__(self):
s = ""
p = self._first
while p != None:
s = s + str(p.getValue())
p = p.getNext()
return s
def enqueue(self, kort):
ny = Node(kort)
if self._first == None:
self._first = ny
else:
self._last = self._first
while self._last.getNext():
self._last = self._last.getNext()
self._last.setNext(ny)
self._length += 1
def dequeue(self):
data = self._first.getValue()
self._first = self._first.getNext()
self._length = self._length - 1
return data
You're right about linked_list being a local variable, but just because a variable is local doesn't mean it can't reference something that isn't. In order for it to do what you expected, it would need to copy your entire linked list every time you pass it to a function, which wouldn't make sense.
Here's a simple example that illustrates the idea of a shared object. In this example, an empty list is created and assigned to a. Then a is assigned to b. This does not copy the list. Instead, there is a single list, referenced by both a and b. When it is modified, through either a or b, both a and b reflect the change:
>>> a = []
>>> b = a
>>> a.append("x")
>>> a
['x']
>>> b
['x']
>>>
The same thing is happening with your class objects. In fact, your linked lists wouldn't work at all if it didn't.

Creating Vectors with Python

I'm creating a vector class that has one parameter being the length of a vector. The length is automatically 0 if none is entered by user. If a vector is given a length, however, each number will be set to 0. For example: v(5) would be [0,0,0,0,0] and v() would be [].
This is the code i have thus far, but it's not quite working. Any advice?
class V:
def __init__(self, length = 0):
self.vector = [0]*length
def __str__(self):
print(self.vector)
def __len__(self):
return len(self.vector)
Then i plug in a = V() b = V(5) and when i print(a) and print(b) i get an TypeError. Any advice?
I'd probably cheat and go for sub-classing list:
class V(list):
def __init__(self, length=0):
super(V, self).__init__([0] * length)
This way you get the length, repr and other goodies for free.
class V:
def __init__(self, length = 0):
self.data = [0]*length
def __str__(self):
return '[{}]'.format(', '.join(str(d) for d in self.data))
def __len__(self):
return len(self.data)

Categories

Resources