Create objects in Python based on file - python

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

Related

Search for a string inside a text document

I'm new to python and was wondering what am i missing in my code.
I want to build a class that receives 3 letter airport destination and origin, and prints out if it's in the text file
I appreciate your help !
class departure:
def __init__(self, destfrom, destto):
self.destfrom = destfrom
self.destto = destto
def verdest(self,dest):
flag = 0
destinations = ["JFK","AMS"]
for i in destinations:
if i == dest:
flag = i
return flag
if verdest() in open('airportlist.txt').read():
print("true")
There are a few changes you need to make. if i == dest: is checking if JFK is equal to the file contents, you probably mean in. Then you have a class but you never initialize it.
class departure:
def __init__(self, destfrom, destto):
self.destfrom = destfrom
self.destto = destto
def verdest(self,dest):
flag = 0
destinations = ["JFK","AMS"]
for i in destinations:
if i in dest: # change to in
flag = i
return flag
d = departure(['BWI'],['AMS'])
f = open('airportlist.txt','r')
flag = d.verdest(f.read()) #find last airport that was in file, could modify this to return list
if flag:
print("true" + flag)
else:
print('false')
f.close() #close the file
read reads the lines of a file into a single string.
If you use readlines instead you will get a list of lines in the file.
Then you can see if an individual code is in these lines.
Without a class, like this:
def verdest(self, dest):
flag = 0 # note - not used!
destinations = open('airportlist.txt').readlines()
return dest in destinations
if verdest("LGW"):
print("true")
If you want to store the two airport names in the class and look them up in a file later one, save the three letter codes as you do, but pass the filename contents to the checking function?
class departure:
def __init__(self, destfrom, destto):
self.destfrom = destfrom
self.destto = destto
def verdest(self, destinations):
return self.destfrom in destinations and self.destto in destinations
Then make a class and use it:
places = departure("JFK","AMS")
#This makes your class, and remembers the variables in member variables
if places.verdest(open('airportlist.txt').readlines()):
#In this member function call, places remembers the member variable set up above
print("true")
Now, you could read the file in the __init__ method of the class, rather than every time you want to check.
You are missing an argument in verdest() function call.

python queue using embedded list

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)

How to deal with large csv file in python?

I have CSV file that contains a data of 40k rows.
My each function open csv file and works with it and then close it.
Is there a way that I can open the file once and then close it and I can work with it whenever I want? I tried to put each field in a separate list and work whit it whenever I call it or in dictionary but both methods works good up to 1k row if more then it takes long time to processes it, I found a way to speed up by filtering them, but not sure how to apply it.
sample of my codes.
files=open("myfile.csv","r")
def spec_total():
total = 0.0
files.readline() # skip first row
for line in files:
field=line.strip().split(",") #make Into fields
tall=float(field[0])
if tall >= 9.956:
total +=tall
print("The sum is: %0.5f" % (total))
spec_total()
files.close()
other function
files=open("3124749c.csv","r")
def code():
match= 0
files.readline() # skip first row
for row in files:
field=row.strip().split(",") #make Into fields
code=(field[4])
import re
if re.search(r'\[[A-Za-z][0-9]+\][0-9]+[A-Za-z]{2}[0-9]+#[0-9]+', code) is None:
match += 1
print("The answer that do not match code is :",match)
code()
files.close()
and there is plenty more functions that opens each time the csv file and split them into field in order to recognise which field I am referring to.
If I understand correctly try:
import csv
total = 0.0
for row in csv.reader(open("myfile.csv")):
tall = float(row[0])
if tall >= 9.956:
total += tall
print("The sum is: %0.5f" % total)
More complex version - create calculation classes for processing each row.
class Calc(object):
def process(self,row):
pass
def value(self):
pass
class SumColumn(Calc):
def __init__(self, column=0,tall=9.956):
self.column = column
self.total = 0
def process(self, row):
tall = float(row[0])
if tall >= self.tall:
self.total += tall
def value(self):
return self.total
class ColumnAdder(Calc):
def __init__(self, col1, col2):
self.total = 0
self.col1 = col1
self.col2 = col2
def process(self, row):
self.total += (row[self.col1] + row[self.col2])
def value(self):
return self.total
class ColumnMatcher(Calc):
def __init__(self, col=4):
self.matches = 0
def process(self, row):
code = row[4]
import re
if re.search(r'\[[A-Za-z][0-9]+\][0-9]+[A-Za-z]{2}[0-9]+#[0-9]+', code) is None:
self.match += 1
def value(self):
return self.matches
import csv
col0_sum = SumColumn()
col3_sum = SumColumn(3, 2.45)
col5_6_add = ColumnAdder(5,6)
col4_matches = ColumnMatcher()
for row in csv.reader(open("myfile.csv")):
col0_sum.process(row)
col3_sum.process(row)
col5_6_add.process(row)
col4_matches.process(row)
print col0_sum.value()
print col3_sum.value()
print col5_6_add.value()
print col4_matches.value()
This code was typed into SO, which was a tedious affair - so bare with on syntax etc.
For illustration purposes only - not to be taken too literally.
All is object in Python: that means functions too.
So there is no need to define special classes to craft functions as instances of these classes as sotapme does, since every function we define is already an object in the sense of 'instance of a class'.
Now, if someone needs to create several functions of the same type, for example each of them adds all the values of a precise CSV file's column, that's right that it's interesting to create these many functions by a repeating process.
At this point, raises the question: using function factory or class ?
Personnaly, I prefer the function factory way because it is less verbose.
I also discovered in the Theran's answer HERE that it's also faster.
In the following code, I use a trick with globals() to give a particular name to each function created by means of a function factory. Some will say it's bad, but I don't know why. If there's another way to do the same , I will be happy to learn it.
In the code, 3 functions are build by a function factory, and I let one defined by plain normal definition (op3).
Python is fantastic!
import csv
import re
# To create a CSV file
with open('Data.csv','wb') as csvhandle:
hw = csv.writer(csvhandle)
hw.writerows( ((2,10,'%%',3000,'-statusOK-'),
(5,3,'##',500,'-modo OOOOKKK-'),
(1,60,'**',700,'-- anarada-')) )
del hw
# To visualize the content of the CSV file
with open(r'Data.csv','rb') as f:
print "The CSV file at start :\n "+\
'\n '.join(map(repr,csv.reader(f)))
def run_funcs_on_CSVfile(FUNCS,CSV):
with open(CSV,'rb') as csvhandle:
for f in FUNCS:
# this is necessary for functions not created via
# via a function factory but via plain definition
# that defines only the attribute col of the function
if 'field' not in f.__dict__:
f.field = f.col - 1
# columns are numbered 1,2,3,4,...
# fields are numbered 0,1,2,3,...
for row in csv.reader(csvhandle):
for f in FUNCS:
f(row[f.field])
def SumColumn(name,col,start=0):
def g(s):
g.kept += int(s)
g.kept = start
g.field = col -1
g.func_name = name
globals()[name] = g
def MultColumn(name,col,start=1):
def g(s):
g.kept *= int(s)
g.kept = start
g.field = col - 1
g.func_name = name
globals()[name] = g
def ColumnMatcher(name,col,pat,start = 0):
RE = re.compile(pat)
def g(s,regx = RE):
if regx.search(s):
g.kept += 1
g.kept = start
g.field = col - 1
g.func_name = name
globals()[name] = g
SumColumn('op1',1)
MultColumn('op2',2)
ColumnMatcher('op4',5,'O+K')
def op3(s):
s = int(s)
if s%2:
op3.kept += (2*s)
else:
op3.kept += s
op3.kept = 0
op3.col = 4
print '\nbefore:\n ' +\
'\n '.join('%s.kept == %d'
% (f.func_name, f.kept)
for f in (op1,op2,op3,op4) )
# The treatment is done here
run_funcs_on_CSVfile((op2,op3,op4,op1),r'Data.csv')
# note that the order of the functions in the tuple
# passed as argument can be any either one or another
print '\nafter:\n ' +\
'\n '.join('%s(column %d) in %s.kept == %d'
% (f.func_name, f.field+1, f.func_name, f.kept)
for f in (op1,op2,op3,op4) )
.
result
.
The CSV file at start :
['2', '10', '%%', '3000', '-statusOK-']
['5', '3', '##', '500', '-modo OOOOKKK-']
['1', '60', '**', '700', '-- anarada-']
before:
op1.kept == 0
op2.kept == 1
op3.kept == 0
op4.kept == 0
after:
op1(column 1) in op1.kept == 8
op2(column 2) in op2.kept == 1800
op3(column 4) in op3.kept == 4200
op4(column 5) in op4.kept == 2

How to input actual data into classes

Okay, so I have a module I created and have imported it into my main program. I guess I'm still trying to understand classes and I'm not sure how to actually enter my data into my class. This is in Python 3. Here is the module:
class Movie:
def __init__(self, Title = '', Ratings = []):
self.Movie = Title
self.Ratings = Ratings
self.TotalRatings = 0
self.minusFive = 0
self.minusThree = 0
self.one = 0
self.three = 0
self.five = 0
self.ValidRatings = [-5,-3,1,3,5]
def __str__(self):
return '{0} has {1} total ratings with an average rating of {3}.'.format(self.title, self.totalRatings, self.AvgRating)
def __repr__(self):
return self.__str__()
def AddRating(self, rating):
for num in self.Ratings:
if num in self.ValidRatings:
self.totalRatings += 1
else:
continue
def AvgRating(self):
return sum (self.totalRatings)/len(self.totalRatings)
Below is the beginning of my main program:
import Movie
def ReadFile(FileName):
F = open(FileName)
return F.readlines()
File = ReadFile('Ratings.txt')
File2 = open('Prog5Titles.txt').read() #open movie titles file
movie1 = Movie("The Avengers", [5,5,5]) #this is just a sample to help me understand
When I run this, I am getting the error message: 'module' object is not callable. Can anyone help me understand how to correctly input my data into this?
The problem is that you have a file Movie.py that contains a class named, by coincidence, Movie. If you just import Movie, then the python name Movie refers to the contents of the file Movie.py and to refer to the class tucked away in there, you need to write:
movie1 = Movie.Movie("The Avengers", [5,5,5])
Alternatively, you can do your import like this:
from Movie import Movie
and now the python name Movie refers to something different — the "thing" (in this case, a class) named Movie inside the file Movie.py.
This would be a little clearer if you named the file containing class Movie with a name different from the class defined inside the file. Maybe movie_stuff.py or something. Consider that you'll have additional classes in the project (Actor, Studio) and those classes will probably be defined in the same file as class Movie.

Error accessing class objects in python

I am having some problem accessing class instances. I am calling the class from a procedure, name of instance is defined in some variable. I want the instance name to be created of that value and then want to access it, but when i access it is giving error. Can some one please help to resolve this issue.
class myclass:
def __init__(self,object):
self.name = object
def mydef():
global a1
b = "a1"
b = myclass(b)
mydef()
print a1.name
Second Problem:
In my actual script, I have to create a large number of such instances from this function (around 100). So defining their name as global would be painful, is there a way i could access those instances outside function without having to declare them as global.
Modification:
class myclass:
def __init__(self,object,typename):
self.name = object
self.typeid = typename
def mydef():
file_han = open(file,"r")
while True:
line = file_han.readline()
if not line:
break
start = line.find('"')
end = line.find('"',start+1)
string_f = line[start+1:end]
myclass(string_f,'a11')
mydef(file)
print def.name
print def.typeid
File Contents are :
a11 "def"
a11 "ghi"
a11 "eff"
Here's how I'd do it. I don't know why you're messing around with globals, if you'd care to explain, I'll update my answer.
class Myclass(object):
def __init__(self, name):
self.name = name
def mydef():
return Myclass("a1")
a1 = mydef()
print a1.name
Gather your instances in a list:
instances = []
for x in range(1000):
instances.append(Myclass("Instance {0}".format(x)))
print instance[42].name
Note the changes:
Class names should be capitalized
Use object as the base class of your classes (since python 2.2, but no longer necessary in 3.x)
Don't shadow the built-in object with your parameter name
Just use the string "a1" directly as a parameter instead of assigning it to a variable
Return something from the function instead of passing the result by global variable
RE: Comment
You haven't said anything about the format of these files, so I'll just give an example where the file to be read contains one class name per line, and nothing else:
def mydef(filename):
ret = []
with open(filename) as f:
for line in f:
# Call `strip` on line to remove newline and surrounding whitespace
ret.append(Myclass(line.strip()))
return ret
So if you have several files and wish to add all your instances from all your files to a large list, do it like this:
instances = []
for filename in ["myfile1", "myfile2", "myfile3"]:
instances.extend(mydef(filename))
RE: OP Edit
def mydef(filename):
ret = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret.append(Myclass(string_f))
return ret
i = mydef("name_of_file")
RE: Comment
Oh, you want to access them by name. Then return a dict instead:
def mydef(filename):
ret = {}
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret[string_f] = Myclass(string_f)
return ret
i = mydef("name_of_file")
print i["ghi"].name # should print "ghi"
RE: Comment
If I understand you correctly, you want to have it both ways -- index by both line number and name. Well then why don't you return both a list and a dictionary?
def mydef(filename):
d = {}
L = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
instance = Myclass(string_f)
d[string_f] = instance
L.append(instance)
return L, d
L, d = mydef("name_of_file")
print d["ghi"].name
print L[3]
print L.index(d["ghi"])
You could use class as repository for your instances, for example
class Named(object):
def __init__(self,name):
self.name = name
def __new__(cls,name):
instance = super(type,cls).__new__(cls,name)
setattr(cls,name,instance)
return instance
def __repr__(self):
return 'Named[%s]'%self.name
Named('hello')
Named('x123')
Named('this is not valid attribute name, but also working')
print(Named.hello,Named.x123,getattr(Named,'this is not valid attribute name, but also working'))

Categories

Resources