Error comes when i call the display function using class object
What should i do to overcome this ??
class A:
def __init__(self, fname, lname, age):
self.fname = fname
self.lname = lname
self.age = age
def disply(self):
fp = open("abc","r")
for lines in fp:
temp = lines.split(", ")[-1]
fp.close()
print a
a = [A("Taylor","Launter",22), A("James","bond",40)]
a.display()
You have a list of instances called a. a isn't the instance/s, it's a list.
You probably meant to do:
for myobject in a:
myobject.disply() # Note "disply" instead of "display"
a = [A("Taylor","Launter",22), A("James","bond",40)]
a.display()
Now a is a list. Lists in python dont have display method.
What you might actually have wanted to do is to invoke display method of the object of A. If that is the case, you might want to do something like this
for currentObject in [A("Taylor","Launter",22), A("James","bond",40)]:
currentObject.display()
Edit Your display method doesnt make any sense to me.
Related
I have a class which I want to use to extract data from a text file (already parsed) and I want do so using dynamically created class methods, because otherwise there would be a lot of repetitive code. Each created class method shall be asociated with a specific line of the text file, e.g. '.get_name()' --> read a part of 0th line of text file.
My idea was to use a dictionary for the 'to-be-created' method names and corresponding line.
import sys
import inspect
test_file = [['Name=Jon Hancock'],
['Date=16.08.2020'],
['Author=Donald Duck']]
# intented method names
fn_names = {'get_name': 0, 'get_date': 1, 'get_author': 2}
class Filer():
def __init__(self, file):
self.file = file
def __get_line(cls):
name = sys._getframe().f_code.co_name
line = fn_names[name] # <-- causes error because __get_line is not in fn_names
print(sys._getframe().f_code.co_name) # <-- '__get_line'
print(inspect.currentframe().f_code.co_name) # <-- '__get_line'
return print(cls.file[line][0].split('=')[1])
for key, val in fn_names.items():
setattr(Filer, key, __get_line)
f = Filer(test_file)
f.get_author()
f.get_date()
When I try to access the method name to link the method to the designated line in the text file, I do get an error because the method name is always '__get_line' instead of e.g. 'get_author' (what I had hoped for).
Another way how I thought to solve this was to make '__get_line' accepting an additional argument (line) and set it by passing the val during 'the setattr()' as shown below:
def __get_line(cls, line):
return print(cls.file[line][0].split('=')[1])
and
for key, val in fn_names.items():
setattr(Filer, key, __get_line(val))
however, then Python complains that 1 argument (line) is missing.
Any ideas how to solve that?
I would propose a much simpler solution, based on some assumptions. Your file appears to consist of key-value pairs. You are choosing to map the line number to a function that processes the right hand side of the line past the = symbol. Python does not conventionally use getters. Attributes are much nicer and easier to use. You can have getter-like functionality by using property objects, but you really don't need that here.
class Filer():
def __init__(self, file):
self.file = file
for line in file:
name, value = line[0].split('=', 1)
setattr(self, name.lower(), value)
That's all you need. Now you can use the result:
>>> f = Filer(test_file)
>>> f.author
'Donald Duck'
If you want to have callable methods exactly like the one you propose for each attribute, I would one-up your proposal and not even have a method to begin with. You can actually generate the methods on the fly in __getattr__:
class Filer():
def __init__(self, file):
self.file = file
def __getattr__(self, name):
if name in fn_names:
index = fn_names[name]
def func(self):
print(self.file[index][0].split('=', 1)[1])
func.__name__ = func.__qualname__ = name
return func.__get__(self, type(self))
return super().__getattr__(name)
Calling __get__ is an extra step that makes the function behave as if it were a method of the class all along. It binds the function object to the instance, even through the function is not part of the class.
For example:
>>> f = Filer(test_file)
>>> f.get_author
<bound method get_author of <__main__.Filer object at 0x0000023E7A247748>>
>>> f.get_author()
'Donald Duck'
Consider closing over your keys and values -- note that you can see the below code running at https://ideone.com/qmoZCJ:
import sys
import inspect
test_file = [['Name=Jon Hancock'],
['Date=16.08.2020'],
['Author=Donald Duck']]
# intented method names
fn_names = {'get_name': 0, 'get_date': 1, 'get_author': 2}
class Filer():
def __init__(self, file):
self.file = file
def getter(key, val):
def _get_line(self):
return self.file[val][0].split('=')[1]
return _get_line
for key, val in fn_names.items():
setattr(Filer, key, getter(key, val))
f = Filer(test_file)
print("Author: ", f.get_author())
print("Date: ", f.get_date())
I am new to programming and self taught. I have used Stack Exchange to find answers to many of my questions without ever needing to ask (it is a great community), but I cannot seem to find the answer to this anywhere. I apologize if this is a duplicate.
I am trying to assign a method to a variable, but I want to save it to a text file for access later. I am using open() to access the text file and eval() to change it from a string when loading the information. I just cannot figure out how to do the opposite.
from random import randint
class Example (object):
def __init__(self):
self.name = ""
self.lucky_number = ""
def create_person(self):
self.name = input("What is your name?")
self.lucky_number = randint(1,10)
save_person = [self.name, self.lucky_number]
with open("example.txt", "w") as f:
for i in save_person:
f.write(i + '\n')
def load_person(self):
with open("example.txt", 'r') as f:
person_list = f.readlines()
if len(person_list) <= 1:
create_person()
else:
self.name = person_list[0].strip('\n')
self.lucky_number = eval(person_list[1].strip('\n'))
person = Example()
person.load_person()
I want to keep the randint(1,10) part because I want to reuse the function, but I may change the value to something else later depending on user selection (such as changing self.lucky_number = randint(1,10) to self.lucky_number = randint(1,30)).
I know I can just change it to self.lucky_number = randint(1,var) and then save the value of var instead, but it made me wonder if the way I'm trying is possible.
Thanks in advance for any assistance. I am using Python 3.5.
Edit: For clarification I am looking to store the actual function, i.e. randint(1,10), in the text file, not the value of the function.
EDIT 2: I am going to close this as answered because I found a way to do what I needed, but it is not a direct way.
I was able to find a way to accomplish what I was looking for, but it is a roundabout way. I changed the call to the function into a string, then created a new class variable that calls the variable with the function string. The other class variable meant to run the function now has eval() around it and calls the new class variable I created. I save the new class variable instead.
from random import randint
# Now a string instead of a function call
prog = "randint(1,10)"
class Example (object):
def __init__(self):
self.name = ""
"""Added self.temp to grab the string from outer
variable and will change self.temp to get the desired
functions as strings"""
self.temp = prog
"""self.lucky_number grabs new class variable and
eval() turns it into callable function"""
self.lucky_number = eval(self.temp)
def create_person(self):
self.name = input("What is your name?")
self.temp = prog
self.lucky_number = eval(self.temp)
""" Saves new class variable now and stores actual
function, eg randint(1,10)"""
save_person = [self.name, self.temp]
with open("example.txt", "w") as f:
for i in save_person:
f.write(str(i) + '\n')
def load_person(self):
with open("example.txt", 'r') as f:
person_list = f.readlines()
if len(person_list) <= 1:
self.create_person()
else:
self.name = person_list[0].strip('\n')
self.temp = person_list[1].strip('\n')
person = Example()
person.load_person()
Its roundabout, but gets the job done. I can change self.temp to whatever variable (formatted properly) I need and the code will work. If anyone can think of a direct way please let me know.
I'm not sure what's happening when I print my dictionary.
In Python 3, I have a dictionary of parse_blast objects called transSwiss. Each object's proteinID is the key with the entire object as the value.
I can print transSwiss in it's entirety and I can also print blasto.protein, but not when I combine them to get a dictionary value. I'm not sure what is happening when I use:
print(transSwiss[blasto.protein])
<__main__.parse_blast object at 0x000000373C5666A0>
Here is the code
class parse_blast(object):
def __init__(self, line):
#Strip end-of-line and split on tabs
self.fields = line.strip("\n").split("\t")
self.transcriptId, self.isoform = self.fields[0].split("|")
self.swissStuff = self.fields[1].split("|")
self.swissProtId = self.swissStuff[3]
self.percentId = self.fields[2]
def filterblast(self):
return float(self.percentId) > 95
class parse_matrix(object):
#Consider __init__ as a Constructor
def __init__(self, matrix_lines):
(self.protein,
self.Sp_ds,
self.Sp_hs,
self.Sp_log,
self.Sp_plat) = matrix_lines.strip("\n").split("\t")
def separate_tuples(one_tuple):
return "\t".join(one_tuple)
blastmap = map(parse_blast, blast_output.readlines())
filtered = filter(parse_blast.filterblast, blastmap)
matrixmap = map(parse_matrix, matrix_output.readlines()[1:])
transSwiss = {blasto.transcriptId:blasto for blasto in filtered}
for matrixo in matrixmap:
print(transSwiss[matrixo.protein])
Because your object is defined by you, you also need to tell python how you want it to print. You can do this by defining a function called "__str__" that returns how you want to print your object.
https://en.wikibooks.org/wiki/Python_Programming/Classes#str
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'))
I have a text file that looks something like this where the first column is a student's name, the second column is the number of credits, and the third is the number of points (grade times hours).
john 5 15
bill 9 30
ted 7 22
I want to create a class that extracts the relevant information and calculates gpa.
class Student:
def __init__(self, name, hours, qpoints):
self.name = name
self.hours = float(hours)
self.qpoints = float(qpoints)
def getName(self):
return self.name
def getHours(self):
return self.hours
def getQPoints(self):
return self.qpoints
def gps(self):
return self.qpoints/self.hours
used to make extract the data (based on the fact that there is a tab between each piece of information)
def makeStudent(info):
name, hours, qpoints = info.split("\t")
return Student(name, hours, qpoints)
here I use a for loop to create a list based on the data in the text file by appending the relevant information from each line to the list
def readStudents(filename):
infile = open(filename, 'r')
students = []
for line in infile:
students.append(makeStudent(line))
infile.close()
return students
the problem is that I get this error:
[<__main__.Student object at 0x01FA4AD0>, <__main__.Student object at 0x01FA4AF0>,
<__main__.Student object at 0x01FA4B10>, <__main__.Student object at 0x01FA4B50>,
<__main__.Student object at 0x01FA4B30>]
Any ideas on why this is happening?
This is not an error. It is regular output. You should override the __str__ and __repr__ methods of the Student class, to tell python how to print Student objects.
Some help on your code, this is much better:
def readStudents(filename):
with open(filename) as student_file:
return [Student(*line.split()) for line in student_file]
Like everyone says, not an error. Just implement __str__, __repr__ or __unicode__ on your Student class.
However, I have one minor suggestion. You should use the csv module to read your file.
Your readStudents function can also be re-written like this:
def readStudents(filename):
students = []
with open(filename) as infile:
for line in csv.reader(infile, delimiter='\t'): # or excel-tab if you want.
students.append(Student(**line))
return students
Isn't that pretty?
Don't forget to put a import csv at the beginning of your python file!
I strongly suggest using the csv module (import csv): it will do most of the work for you, be more flexible, more readable and less prone to bugs.
Also, to be a little more strict: what is your actual question? I just see a blurb of code and some output you do not understand. That is not an error message, by the way, it is a list of five instances of the Student class. The code seems to work as intended: you parse the file, create students, and then..? What do you want to do with them? The parsing is done, you want to move on to the handling of the data.
You don't get an error, but a list of student objects. What you need to do is implement a __str__ or a __repr__ method: Special method names
Getter and setter methods are usually frowned on unless they are doing something active (over and above just retrieving or setting a value).
import csv
class Student(object):
def __init__(self, name, hours, qpoints):
super(Student,self).__init__()
self.name = str(name)
self.hours = float(hours)
self.qpoints = float(qpoints)
#property
def gpa(self):
return self.qpoints/self.hours
#gpa.setter
def gpa(self, value):
raise SyntaxError('gpa property is read-only; update .qpoints or .hours instead')
def __str__(self):
return "{name:20} {hours:>6.2f} {qpoints:>6.2f} {gpa:>6.2f}".format(name=self.name, hours=self.hours, qpoints=self.qpoints, gpa=self.gpa)
def loadStudents(fname, *args, **kwargs):
with open(fname) as inf:
return [Student(*line) for line in csv.reader(inf, *args, **kwargs)]
def main():
students = loadStudents('students.csv', delimiter='\t')
for s in students:
print s
if __name__=="__main__":
main()
results in
john 5.00 15.00 3.00
bill 9.00 30.00 3.33
ted 7.00 22.00 3.14