python queue using embedded list - python

Write a class and implement a list using embedded python list.
Input like : 4 9 3 5
Output should be like: 3 4 5 9
I use this code for taking the input values and split it to the list
s = input()
numbers = map(int, s.split())
How can i build up a class for this listPQ that takes the lists values and put, get and check if the list is empty?
To try if your queue works:
q = ListPQ()
q.put(3)
q.put(4)
x = q.get()
y = q.get()
print(x,y) #it should print 3 4

class ListPQ():
def __init__(self):
self.pq = []
def put(self, val):
# Write code to put the number and keep it in sorted way, however you decide to
# you can use self.pq to access the list and add stuff to it... this instance
# of the class will have it saved.
self.pq.append(val)
self.pq.sort() # This is just for brevity, you can use your own algo for this
def get(self):
# likewise, use the self.pq to pop it out like,
return self.pq.pop(-1)
def is_empty(self):
return len(self.pq) == 0
def __repr__(self):
return "<ListPQ: %r>" % self.pq
Now you can go ahead and use print(instance_of_listpq) and this will print out the list as it's written in the __repr__ method.
Hope this helps now!

You could use the heapq module from the python standard library. Then it is even possible without a class.
Without class:
import heapq
h = []
heapq.heappush(h, 4)
heapq.heappush(h, 3)
heapq.heappush(h, 9)
heapq.heappush(h, 5)
print(heapq.heappop(h))
print(heapq.heappop(h))
print(heapq.heappop(h))
print(heapq.heappop(h))
the output would be (space instead of newline):
3 4 9 5
If you need a class you can do it as follows:
class ListPQ():
def __init__(self):
self.h = []
def put(self, item):
heapq.heappush(self.h, item)
def get(self):
return heapq.heappop(self.h)

Related

How to print the for loop in a class object?

Hi I am learning about OOP and classes and have some confusion regarding the implementation of classes. Below, I have two sets of identical codes with slight differences in the way I am trying to run them after defining the methods in the class. I am just unsure as to why the first code runs and the second one doesnt as I feel like I am doing the same thing? Also, upon running the first code I get 'None' after the loop has finished, any ideas why that takes place? In addition to this, I know that there are iterators that you can use but just wondering if the method used below to loop through stuff is incorrect or problematic?
class i:
def __init__(self,number):
self.number=number
def fun(self):
for i in range(self.number):
print(i)
kj=i(9)
print(kj.fun())
class i:
def __init__(self,number):
self.number=number
def fun(self):
for i in range(self.number):
print(i)
kj=i()
print(kj.fun(9))
In python, class names are typically capitalized. This avoids the problem here where you define a class with the same name are your index variable.
Also, if you want to print a result of a method, then have the method return a value rather than having it print each value.
Putting these concepts together, I would change
class i:
def __init__(self, number):
self.number = number
def fun(self):
for i in range(self.number):
print(i)
kj=i(9)
print(kj.fun())
to
class I:
def __init__(self, number):
self.number = number
def fun(self, number=None):
if not number:
number = self.number
return list(range(number))
kj = I(9)
numbers = kj.fun()
# if you want to print the list
print(numbers)
# if you want to print individual values
print(*numbers)
# if you want to print one number per line
print('\n'.join(numbers))
The following code illustrates the syntax better with type hint:
class i:
def __init__(self,number: int) -> "i":
self.number=number
def fun(self) -> None:
for i in range(self.number):
print(f"fun - i")
kj=i(9)
print(kj.fun())
The output
-> fun - 0
-> fun - 1
-> fun - 2
-> fun - 3
-> fun - 4
-> fun - 5
-> fun - 6
-> fun - 7
-> fun - 8
-> None
We see that the output 1 - 8 is from within the function
And None is because the fun() method has None return by default.
The second code will have the following error
TypeError: __init__() missing 1 required positional argument: 'number'
because to initialise the class it expects the number input. The fact that you want to pass the parameter on the 'fun' method call, it means to expect the number on class initialisation is redundant;
One can do the following instead:
class i:
def __init__(self):
pass
def fun(self, number: int):
for i in range(number):
print(i)
kj = i()
print(kj.fun(9))

Create objects in Python based on file

I'm coding a game in Python 3 and I need to create an unknown number of objects with each objects properties based on the contents of a file.
To explain, I'll dump some code here:
class attack(object):
def __init__(self, name, power):
self.name = name
self.element = int(power)
import getline from linecache
Attacks = []
count = 1
while 1==1:
line=getline("Attacks.txt", count)
line = line.rstrip()
if line == "":
break
else:
linelist = line.split()
#something involving "attack(linelist[1], linelist[2])"
Attacks.append(item)
count += 1
"Attacks.txt" contains this:
0 Punch 2
1 Kick 3
2 Throw 4
3 Dropkick 6
4 Uppercut 8
When the code is done, the list "Attacks" should contain 5 attack objects, one for each line of "Attacks.txt" with the listed name and power. The name is for the user only; in the code, each object will only be called for by its place in its list.
The idea is that the end user can change "Attacks.txt" (and other similar files) to add, remove or change entries; that way, they can modify my game without digging around in the actual code.
The issue is I have no idea how to create objects on the fly like this or if I even can. I already have working code that builds a list from a file; the only problem is the object creation.
My question, simply put, is how do I do this?
I had the same problem someday:
How to call class constructor having its name in text variable? [Python]
You obviously have to define classes which names are in file. I assume that is done. And you need to have them in current module namespace globals()
from somelib import Punch, Kick, Throw, Dropkick, Uppercut
globals()[class_name](x, y)
line = getline("Attacks.txt", count)
line = line.rstrip()
linelist = line.split()
class_name = linelist[1]
value = linelist[2]
class_object = globals()[class_name]
item = class_object(value)
# or shortly in one line:
# item = globals()[linelist[1]](linelist[2])
You could create a class like so providing overloading operators to support the operations:
class Operation:
def __init__(self, *header):
self.__dict__ = dict(zip(['attack', 'power'], header))
class Attack:
def __init__(self, *headers):
self.__dict__ = {"attack{}".format(i):Operation(*a) for i, a in enumerate(headers, start=1)}
def __setitem__(self, attack_type, new_power):
self.__dict__ = {a:Operation(attack_type, new_power) if b.attack == attack_type else b for a, b in self.__dict__.items()}
def __getitem__(self, attack):
return [b.power for _, b in self.__dict__.items() if b.attack == attack]
#property
def power_listings(self):
return '\n'.join(['{} {}'.format(*[b.attack, b.power]) for _, b in self.__dict__.items()])
with open('filename.txt') as f:
f = [i.strip('\n').split() for i in f]
a = Attack(*f)
print(a.power_listings)
a['Throw'] = 6 #updating the power of any occurrence of Throw
Output:
Throw 6
Kick 3
Punch 2
Uppercut 8
Dropkick 6

Class Variable Updating

I built a class to handle a lot of different functions that take common inputs. However, I just ran into the situation where one of the variables that's fed down through self needs to be changed. How do I do this? This is an example:
class Test:
def __init__(self, test_variable):
self.test_var = test_variable
#property
def some_function(self):
if self.test_var < 0:
self.test_var = 'New Output' #this is the line that I can't get
#get to work and I was hoping to update it here
#so I could use it in later functions
return self.test_var
Thank you!
You should drop the #property attribute. Then, you can set it by just doing x.test_var = 5. E.g.,
class Test:
def __init__(self, test_variable):
self.test_var = test_variable
def some_function(self):
if self.test_var < 0:
self.test_var = 'New Output' #this is the line that I can't get
#get to work and I was hoping to update it here
#so I could use it in later functions
return self.test_var
x = Test(-1)
print(x.some_function())
x.test_var = 5
print(x.some_function())
returns
New Output
5

Multiple Objects in Python

I want to create two objects of a class. Using these two objects i want to input some numbers into a list which is a member of the class. After inputting data it will display the content of the list. Simple code. But the output was not which i want.
class Demo:
arr = []
n = 0
def __init__(self,s):
self.n=s
def fill(self):
print("Enter elements in array ")
for i in range(self.n):
x=input()
self.arr.append(x)
def show(self):
for i in range(self.n):
print(self.arr[i])
obj1 = Demo(5)
obj2 = Demo(3)
obj1.fill()
obj2.fill()
print("Data from first Object")
obj1.show()
print("Data from second object")
obj2.show()
You should have:
def __init__(self,s):
self.n=s
self.arr = []
By creating arr in the body of the class (rather than in the initializer), it becomes part of the class itself - shared by all instances.

how to select an object from a list of objects by its attribute in python

Apologies if this question has already been asked but I do not think I know the correct terminology to search for an appropriate solution through google.
I would like to select an object from a list of objects by the value of it's attribute, for example:
class Example():
def __init__(self):
self.pList = []
def addPerson(self,name,number):
self.pList.append(Person(self,name,number))
class Person():
def __init__(self,name,number):
self.nom = name
self.num = number
a = Example()
a.addPerson('dave',123)
a.addPerson('mike',345)
a.pList #.... somehow select dave by giving the value 123
in my case the number will always be unique
Thanks for the help
One option is to use the next() built-in:
dave = next(person for person in a.pList if person.num == 123)
This will throw StopIteration if nothing is found. You can use the two-argument form of next() to provide a default value for that case:
dave = next(
(person for person in a.pList if person.num == 123),
None,
)
A slightly more verbose alternative is a for loop:
for person in a.pList:
if person.num == 123:
break
else:
print "Not found."
person = None
dave = person
If those nom's are unique keys, and all you are ever going to do is access your persons using this unique key you should indeed rather use a dictionary.
However if you want to add more attributes over time and if you like to be able to retrieve one or more person by any of those attributes, you might want to go with a more complex solution:
class Example():
def __init__(self):
self.__pList = []
def addPerson(self,name,number):
self.__pList.append(Person(name,number))
def findPerson(self, **kwargs):
return next(self.__iterPerson(**kwargs))
def allPersons(self, **kwargs):
return list(self.__iterPerson(**kwargs))
def __iterPerson(self, **kwargs):
return (person for person in self.__pList if person.match(**kwargs))
class Person():
def __init__(self,name,number):
self.nom = name
self.num = number
def __repr__(self):
return "Person('%s', %d)" % (self.nom, self.num)
def match(self, **kwargs):
return all(getattr(self, key) == val for (key, val) in kwargs.items())
So let's assume we got one Mike and two Dave's
a = Example()
a.addPerson('dave',123)
a.addPerson('mike',345)
a.addPerson('dave',678)
Now you can find persons by number:
>>> a.findPerson(num=345)
Person('mike', 345)
Or by name:
>>> a.allPersons(nom='dave')
[Person('dave', 123), Person('dave', 678)]
Or both:
>>> a.findPerson(nom='dave', num=123)
Person('dave', 123)
The terminology you need is 'map' or 'dictionnary' : this will lead you to the right page in the python doc.
Extremely basic example:
>>> a = {123:'dave', 345:'mike'}
>>> a[123]
'dave'
The missing underscore makes plist a public property. I don't think that's what you want, since it does not encapsulate the functionality and you could call a.plist.append instead of a.addPerson.
class Example():
...
def filter(self, criteria):
for p in self.plist:
if criteria(p):
yield p
def getByNum(self, num):
return self.filter(lambda p: p.num == num)
dave = next(a.getByNum(123))
If the numbers are unique, you may also consider using a dictionary that maps from number to name or person instead of a list. But that's up to your implementation.

Categories

Resources