Why does this print the memory location of an object rather than what I want? - python

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

Related

How to get the list text from an class object having string and list in python

i got a question about how to get the list text from an class object having string and list in python.
I try to use str() to get the string value from the list, but it just shows me the empty string and the reference of the list.
Here is my class:
class ContentTranslation(object):
def __init__(self, language):
self.language = language
self.contentTranslationList=[]
def addContentTranslation(self, contentTranslation):
self.contentTranslationList = contentTranslation
def getLanguage(self):
return self.language
def getContentTranslation(self):
return self.contentTranslationList
for j in range(1,noOfSessions):
aContentList.append("a")
contentTranslation = ContentTranslation(language)
contentTranslation.addContentTranslation(aContentList)
listOfTranslationContent.append(ContentTranslation(contentTranslation))
for i in range(len(listOfTranslationContent)):
print(str(listOfTranslationContent[i].getLanguage()))
print(str(listOfTranslationContent[i].getContentTranslation()))
In the first for loop, you are passing an object to the constructor. Like so:
listOfTranslationContent.append(ContentTranslation(contentTranslation))
Instead change the body of first loop to this:
for j in range(1,noOfSessions):
aContentList.append("a")
# create object
contentTranslation = ContentTranslation(language)
contentTranslation.addContentTranslation(aContentList)
# append to list
listOfTranslationContent.append(contentTranslation)

Can dynamically created class methods know their 'created' name at runtime?

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())

How do I run two or more methods in a class like a chain?

I'm trying to learn OOP but I'm getting very confused with how I'm supposed to run the methods or return values. In the following code I want to run read_chapters() first, then sendData() with some string content that comes from read_chapters(). Some of the solutions I found did not use __init__ but I want to use it (just to see/learn how i can use them).
How do I run them? Without using __init__, why do you only return 'self'?
import datetime
class PrinceMail:
def __init__(self):
self.date2 = datetime.date(2020, 2, 6)
self.date1 = datetime.date.today()
self.days = (self.date1 - self.date2).days
self.file = 'The_Name.txt'
self.chapter = '' # Not sure if it would be better if i initialize chapter here-
# or if i can just use a normal variable later
def read_chapters(self):
with open(self.file, 'r') as book:
content = book.readlines()
indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
indexes = indexes[self.days:]
heading = content[indexes[0]]
try:
for i in (content[indexes[0]:indexes[1]]):
self.chapter += i # can i use normal var and return that instead?
print(self.chapter)
except IndexError:
for i in (content[indexes[0]:]):
self.chapter += i
print(self.chapter)
return self????? # what am i supposed to return? i want to return chapter
# The print works here but returns nothing.
# sendData has to run after readChapters automatically
def sendData(self):
pass
#i want to get the chapter into this and do something with it
def run(self):
self.read_chapters().sendData()
# I tried this method but it doesn't work for sendData
# Is there anyother way to run the two methods?
obj = PrinceMail()
print(obj.run())
#This is kinda confusing as well
Chaining methods is just a way to shorten this code:
temp = self.read_chapters()
temp.sendData()
So, whatever is returned by read_chapters has to have the method sendData. You should put whatever you want to return in read_chapters in a field of the object itself (aka self) in order to use it after chaining.
First of all, __init__ has nothing to do with what you want to achieve here. You can consider it as a constructor for other languages, this is the first function that is called when you create an object of the class.
Now to answer your question, if I am correct you just want to use the output of read_chapters in sendData. One of the way you can do that is by making the read_chapters a private method (that is if you don't want it to use through the object) using __ in the starting of the name like __read_chapters then make a call to the function inside the sendData function.
Another point to consider here is, when you are using self and don't intend to use the function through the object you don't need to return anything. self assigns the value to the attribute of the current instance. So, you can leave the function read_chapters at self.chapter = i and access the same in sendData.
Ex -
def sendData(self):
print(self.chapter)
I'm not an expert but, the reason to return self is because it is the instance of the class you're working with and that's what allows you to chain methods.
For what you're trying to do, method chaining doesn't seem to be the best approach. You want to sendData() for each iteration of the loop in read_chapters()? (you have self.chapter = i which is always overwritten)
Instead, you can store the chapters in a list and send it after all the processing.
Also, and I don't know if this is a good practice but, you can have a getter to return the data if you want to do something different with (return self.chapter instead of self)
I'd change your code for:
import datetime
class PrinceMail:
def __init__(self):
self.date2 = datetime.date(2020, 2, 6)
self.date1 = datetime.date.today()
self.days = (self.date1 - self.date2).days
self.file = 'The_Name.txt'
self.chapter = []
def read_chapters(self):
with open(self.file, 'r') as book:
content = book.readlines()
indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
indexes = indexes[self.days:]
heading = content[indexes[0]]
try:
for i in (content[indexes[0]:indexes[1]]):
self.chapter.append(i)
except IndexError:
#not shure what you want to do here
for i in (content[indexes[0]:]):
self.chapter.append(i)
return self
# sendData has to run after readChapters automatically
def sendData(self):
pass
#do what ever with self.chapter
def get_raw_chapters(self):
return self.chapter
Also, check PEP 8 Style Guide for naming conventions (https://www.python.org/dev/peps/pep-0008/#function-and-variable-names)
More reading in
Method chaining - why is it a good practice, or not?
What __init__ and self do on Python?

Adding a new object to a class with user-input(input) in python

I am trying to add new objects to a class(emne) but the new instances of the class needs to be created using user input. So i need a way to be able to chose the name for the object and set some of the values of the objects with user input.
I have already tried to create a function that passes the value of the user input into a x = emner(x) to create it but it only returns:
AttributeError: 'str' object has no attribute 'fagKode'
so i think my issue is that the value of the input is created as a string so that it is not understood as a way to create the function
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne():
nyttEmne = input("test:")
nyttEmne=Emne(nyttEmne)
expected result is that the code creates a new instance of the class.
If by choosing a name you mean your fagKode attribute, what you need is:
fagKode = input('Enter code: ')
Emne(fagKode)
You're adding the instances of Enme to the list in the constructor, so you don't need to save them to a variable.
Alternatively, you can handle that in the function:
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
def leggTilEmne():
nyttEmne = input("test:")
enme.append(Emne(nyttEmne))
I'm not sure what exactly you are asking, since you haven't responded to the comments. So,
emne=[]
class Emne:
def __init__(self,fagKode):
self.fagKode = fagKode
self.karakter = ""
emne.append(self)
def leggTilEmne(self, value): # <--- is this what you want
self.nyttEmne= Emne(value)
This is an example of when to use a class method. __init__ should not be appending to a global variable, though. Either 1) have the class method append to a class attribute, or 2) have it return the object and let the caller maintain a global list.
emne = []
class Emne:
emne = []
def __init__(self, fag_kode):
self.fag_kode = fag_kode
self.karakter = ""
#classmethod
def legg_til_emne_1(cls):
nytt_emne = input("test:")
cls.emne.append(cls(nytt_emne))
#classmethod
def legg_til_emne_2(cls):
nyttEmne = input("test:")
return cls(nyttEmne)
Emne.legg_til_emne_1() # Add to Emne.emne
e = Emne.legg_til_emne_2()
emne.append(e)

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