FastQ programming error - python

So I'm trying to parse a FastQ sequence, but I'm a beginner to Python, and I'm a little confused as to why my code isn't working. This is what the program is supposed to carry out:
if I enter the FASTQ seqname line...
#EAS139:136:FC706VJ:2:2104:15343:197393
...then the program should output:
Instrument = EAS139
Run ID = 136
Flow Cell ID = FC706VJ
Flow Cell Lane = 2
Tile Number = 2104
X-coord = 15343
Y-coord = 197393
Here's my unfinished code thus far:
class fastq:
def __init__(self,str):
self.str = inStr.replace ('#',' ').split (':')
def lists (self,parameters):
self.parameters = ("Instrument","Run ID","Flow Cell ID","Flow Cell Lane","Tile Number","X-coordinates","y-coordinates")
def zip (self,myZip,zippedTuple):
self.Zip = zip(self.parameters,self.transform)
self.zippedTuple = tuple(myZip)
print (tuple(myZip))
def main():
seq = input('Enter FastQ sequence:')
new_fastq = fastq(str)
new_fastq.lists()
new_fastq.zip()
main()

The reason that your code isn't working is that it's more-or-less entirely wrong. To address your errors in the order we reach them when trying to run the program:
main:
new_fastq = fastq(str) does not pass the seq we just input, it passes the built-in string type;
__init__:
Calling the argument to fastq.__init__ str is a bad idea as it masks the very built-in we just tried to pass to it;
But whatever you call it, be consistent between the function definition and what is inside it - where do you think inStr is coming from?
lists:
Why is this separate to and not even called by __init__?
Why don't you pass any arguments?
What is the argument parameters even for?
zip:
Rather than define a method to print the object, it is more Pythonic to define fastq.__str__ that returns a string representation. Then you can print(str(new_fastq)). That being said;
Again, you mask a built-in. On this occasion, it's more of a problem because you actually try to use the built-in inside the method that masks it. Call it something else;
Again, you put unnecessary arguments in the definition, then don't bother to pass them anyway;
What is self.transform supposed to be? It is never mentioned anywhere else. Do you mean self.str (which, again, should be called something else, for reasons of masking a built-in and not actually being a string)?
myZip is one of the arguments you never passed, and I think you actually want self.Zip; but
Why would you create x = tuple(y) then on the next line print(tuple(y))? print(x)!
Addressing those points, plus some bonus PEP-008 tidying:
class FastQ:
def __init__(self, seq):
self.elements = seq.replace ('#',' ').split (':')
self.parameters = ("Instrument", "Run ID", "Flow Cell ID",
"Flow Cell Lane", "Tile Number",
"X-coordinates", "y-coordinates")
def __str__(self):
"""A rough idea to get you started."""
return "\n".join(map(str, zip(self.parameters, self.elements)))
def main():
seq = input('Enter FastQ sequence: ')
new_fastq = FastQ(seq)
print(str(new_fastq))
main()

Related

How to change a string in a function when calling a function?

I'm not sure if this is possible but is there a way to change a string that a function prints while calling it from another function? I want to do something like this:
def string():
print ("This cat was scared.")
def main():
for words in string():
str.replace("cat", "dog")
# Print "The do was scared."
main()
By popular demand (well, one person's curiosity…), here's how you actually could change the string in a function before calling that function.
You should never do this in practice. There are some use cases for playing around with code objects, but this really isn't one of them. Plus, if you do anything less trivial, you should use a library like bytecode or byteplay instead of doing it manually. Also, it goes without saying that not all Python implementations use CPython-style code objects. But anyway, here goes:
import types
def string():
print ("This cat was scared.")
def main():
# A function object is a wrapper around a code object, with
# a bit of extra stuff like default values and closure cells.
# See inspect module docs for more details.
co = string.__code__
# A code object is a wrapper around a string of bytecode, with a
# whole bunch of extra stuff, including a list of constants used
# by that bytecode. Again see inspect module docs. Anyway, inside
# the bytecode for string (which you can read by typing
# dis.dis(string) in your REPL), there's going to be an
# instruction like LOAD_CONST 1 to load the string literal onto
# the stack to pass to the print function, and that works by just
# reading co.co_consts[1]. So, that's what we want to change.
consts = tuple(c.replace("cat", "dog") if isinstance(c, str) else c
for c in co.co_consts)
# Unfortunately, code objects are immutable, so we have to create
# a new one, copying over everything except for co_consts, which
# we'll replace. And the initializer has a zillion parameters.
# Try help(types.CodeType) at the REPL to see the whole list.
co = types.CodeType(
co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
co.co_stacksize, co.co_flags, co.co_code,
consts, co.co_names, co.co_varnames, co.co_filename,
co.co_name, co.co_firstlineno, co.co_lnotab,
co.co_freevars, co.co_cellvars)
string.__code__ = co
string()
main()
If that's not hacky enough for you: I mentioned that code objects are immutable. And of course so are strings. But deep enough under the covers, they're just pointer to some C data, right? Again, only if we're using CPython, but if we are…
First, grab my superhackyinternals project off GitHub. (It's intentionally not pip-installable because you really shouldn't be using this except to experiment with your local build of the interpreter and the like.) Then:
import ctypes
import internals
def string():
print ("This cat was scared.")
def main():
for c in string.__code__.co_consts:
if isinstance(c, str):
idx = c.find('cat')
if idx != -1:
# Too much to explain here; see superhackyinternals
# and of course the C API docs and C source.
p = internals.PyUnicodeObject.from_address(id(c))
assert p.compact and p.ascii
length = p.length
addr = id(c) + internals.PyUnicodeObject.utf8_length.offset
buf = (ctypes.c_int8 * 3).from_address(addr + idx)
buf[:3] = b'dog'
string()
main()
As a guess:
You wanted string() to return a value the caller can use, instead of just printing something to the screen. So you need a return statement instead of a print call.
You want to loop over all of the words in that returned string, not all the characters, so you need to call split() on the string.
You want to replace stuff in each word, not in the literal "cat". So, you need to call replace on word, not on the str class. Also, replace doesn't actually change the word, it returns a new one, which you have to remember.
You want to print out each of those words.
If so:
def string():
return "This cat was scared."
def main():
for word in string().split():
word = word.replace("cat", "dog")
print(word, end=' ')
print()
main()
That fixes all of your problems. However, it can be simplified, because you don't really need word.replace here. You're swapping out the entire word, so you can just do this:
def main():
for word in string().split():
if word == "cat": word = "dog"
print(word, end=' ')
print()
But, even more simply, you can just call replace on the entire string, and you don't need a loop at all:
def main():
print(string().replace("cat", "dog"))
What I think you may actually be looking for, is the ability to call your function with a default argument:
def string(animal='cat'):
print("This {} was scared.".format(animal))
>>> string()
This cat was scared.
>>> string('dog')
This dog was scared.
If you pass nothing to string, the default value is assumed. Otherwise, the string prints with the substring you explicitly passed.

code runs else statement repeatedly

every time the below code runs, it goes straight through to the first else statement, then runs the next else statement four times. what is going on and how do I fix it so it calls the movement() module?
class square(object):
def __init__(self,updown,leftright,residence,name):
self.updown = updown
self.leftright = leftright
self.residence = bool
self.name = name
a1 = square(1,1,True,"a1")
a2 = square(2,1,False,"a2")
b1 = square(1,2,False,"b1")
b2 = square(2,2,False,"b2")
square_dict = {a1:"a1",a2:"a2",b1:"b1",b2:"b2"}
movement_select()
def movement_select():
response = raw_input("where would you like to move?")
if response in square_dict:
moveTo = square_dict[response]
else:
print "this runs once"
for a in square_dict:
if a.residence == True:
moveFrom = a
movement(moveFrom,moveTo)
else:
print "this runs four times"
movement_select()
Look at how you're defining residence:
self.residence = bool
So, for any square a, a.residence will be the type bool, never the boolean value True (or anything else). So this test will always fail:
if a.residence == True:
To fix it, change that first line to:
self.residence = residence
While we're at it, you rarely need == True, so you can also change the second line to:
if a.residence:
But that isn't a necessary fix, just a way of simplifying your code a bit.
Meanwhile, your squares_dict is a bit odd. I'm not sure whether it's incorrect or not, but let's take a look:
It maps from square objects to their names. That could be a useful thing to do. It means you can iterate over the dict and get all the squares—as you correctly do in your code. And if you later had a square and wanted to get its name, you could use square_dict for that. Then again, you could probably get the same benefit with just a square_list, and using the name already available as an attribute of the square objects (unless you need the same square to have different names in different contexts).
And meanwhile, a mapping in this direction can't be used for looking up squares_dict[response], because response is a name, not a square. So, you definitely need a mapping in the opposite direction, either in addition to or instead of this one.
If you scrap the square-to-name mapping and only keep the name-to-square mapping, you can still iterate over the squares; you'd just have to do for square in squares_dict.values(): instead of just for square in squares_dict:.
First problem: your dictionary appears to be backwards: you want to look up the square objects from their locations, rather than the other way around. This is why your first conditional is never true. You also might as well strip() the response to ensure that you don't have any hidden whitespace in there.
square_dict = {"a1":a1, "a2":a2, "b1":b1, "b2":b2}
# Later...
response = raw_input("where would you like to move?").strip()
# Later still...
for a in square_dict.values(): # Because we switched the dictionary around!
If you don't want to silently strip off the whitespace, I'd suggest that you at least echo their input back to them (print('"{}"'.format(response))) in the case that it's not found in your dictionary, so they (you) can be sure that at least the input was correct.
The second problem is because of how you define residence. You set the variable equal to bool, which is not what you want at all. Line five ought to read:
self.residence = residence
Finally, some other thoughts on your code! You check whether a value is True by checking if a.residence == True:. The preferred form of this comparison is the simpler version:
if a.residence:
Your methods could also be named more descriptively. Generally speaking, it's always nice to begin a function or method name with a verb, to improve readability. This is of course a question of style, but for instance, the two functions we see, movement_select and movement aren't extremely clear as to their function. It would be much easier to read if they used a standardized form, e.g. choose_move and perform_move.
self.residence = bool
should be
self.residence = residence
You don´t set residence right, this is wrong:
class square(object):
def __init__(self,updown,leftright,residence,name):
self.updown = updown
self.leftright = leftright
self.residence = bool
self.name = name
it has to be
class square(object):
def __init__(self,updown,leftright,residence,name):
self.updown = updown
self.leftright = leftright
self.residence = residence # not bool!!
self.name = name
Your response contains \n symbol, just strip() it
You should also swap places between keys and values in your dictionary

Re-evaluating a function to get a new random value in python

here is the code that I am having a problem with(simplified to make it clearer). It is for a text based game just to help learn things.
class Character(object):
def __init__(self):
self.level = 5
self.moveset = [None,None,None,None]
def movesetleveling(self):
if self.level > 4:
self.moveset[0] = Punch(self.level)
def punch(level):
damagedealt = random.randint(0,5)**level
return damagedealt
I would like to know how I can make self.moveset[0] = Punch() rather than being equal to the output of Punch() in this block of code. So that everytime i run it in a while loop it will re-evaluate the output of Punch() rather than evaluating Punch() once and assigning that to the 0th index of self.moveset[0].
You could assign a function to self.moveset[0] instead of its result (using functools.partial()):
from functools import partial
self.moveset[0] = partial(punch, self.level)
Then later, in your while loop, just call it:
while True:
new_punch_every_time = self.moveset[0]() #note: parentheses
self.moveset[0]() calls punch function with level parameter set to self.level (its value at the time of partial call).
It works because functions, methods are first class citizens in Python. You can pass them as parameters to other functions, return from functions, bind to a different name, append to a list, etc.

Why is my instance counter display 0 in this Python code?

I made a simple code to demonstrate and understand classes - however when I run this, my lists show that they are empty, containing "None" values instead of the strings that the user enters as names.
#Static methods do not require the object to be initiated. Can be remotely accessed from outside the function .
#Counting critters and remote access.
class Orc (object):
total = 0
def get_score (self):
print "The number of orcs the orc factory has made is",Orc.total
def __init__ (self):
Orc.total += 1
name = raw_input ("I am a critter by the name of:\n")
#Creating 10 Orcs
list = []
for i in range (4): list[i] = list.append(Orc.get_score(Orc()))
print "You have created 4 Orcs!" print "The name of your first orc is",list[0] print "The name of your fourth orc is", list[3]
There are a few errors in your code. First in the way you use lists. Second, in the way you call methods on your objects. The combination of errors explains why you have a list of None at the end.
List name
list = []
Don't name a list list. It is already the name of, well..., the list class, i.e. in Python you can do my_list = [] or my_list = list() with the exact same effect.
You want to call your list something meaningful, like orc_list
List Insertion
for i in range (4):
orc_list[i] = orc_list.append(...)
orc_list.append does what it says: it appends an element to the given list. However, it does not return anything. So what your code is doing is
taking an empty list
setting i to 0
inserting what you pass to append at the end of the list
inserting None at index i and thus overriding what you did in 3.
incrementing i
going back to 3.
You want to simply use orc_list.append(...)
Method Call
Orc.get_score(Orc())
I imagine you are getting confused by the self argument. In a class, Python will automatically pass the instance you are working on as the self argument. You don't need to provide that argument.
You want to write
Orc().get_score()
This creates an Orc object, and then calls get_score on it. Python 'injects' the Orc instance you have created into get_score for you.
Method Return
We're now down to
orc_list.append(Orc().get_score())
which is equivalent to
score = Orc().get_score()
orc_list.append(score)
The problem is that there is no return statement in get_score. This means that python will return None when you call that method. Which means that you are appending None to your list.
You want to have
def get_score(self):
print "The number of orcs the orc factory has made is", Orc.total
return Orc.total
Static behaviour
If you really wanted to have a method not bound to an instance of the Orc class, you could use either a class method or a static method.
In your case, you do not need to do anything to the class object, so your choice would be to use a static method.
You would declare
#staticmethod
def get_score():
print "The number of orcs the orc factory has made is", Orc.total
You would then call that method using Orc.get_score()
To define a class method in Python, use classethod decorator and call the first parameter cls
class Orc(object):
total = 0
#classmethod # this will make the method a class method
def get_score (cls): # convention is then to call the 1st param 'cls'
print "The number of orcs the orc factory has made is", cls.total
def __init__ (self):
Orc.total += 1
# use self is you want' to register a name
# however putting a raw_input in an __init__ is NOT recommanded
# you should pass name as a parameter
# and call the raw_input in the for loop
self.name = raw_input ("I am a critter by the name of:\n")
orcs = [] # don't call your lists 'list' because `list` is standard Python function
for i in range(4): # put this on two lines for clarity or use a comprehension list
orcs.append(Orc())
print "You have created 4 Orcs!"
print "The name of your first orc is", orcs[0].name # if you don't use `name`, you will see the reference of the object
print "The name of your fourth orc is", orcs[3].name
A cleaner version (something you should aim for):
class Orc(object):
total = 0
#classmethod #
def get_instances_count(cls):
"""
Return the number or orcs that have been instanciated
"""
# ^ Put some documentation below your method
# these are called "docstring" and are detected by Python
# you should return values in method rather than print
# there are rare cases when you do want print, but when you'll
# encounter them, you won't need me to correct your code anymore
return cls.total
def __init__ (self, name):
Orc.total += 1
self.name = name # we get the name as a parameter
l = []
for i in range(4): # put this on two lines for clarity or use a comprehension list
orc = Orc(raw_input("Enter a name:\n"))
l.append(orc)
print "You have created %s Orcs!" % Orc.get_instances_count()
print "The name of your first orc is", l[0].name #
print "The name of your fourth orc is", l[3].name
Now the more Pythonic version (something you should be able to do once used to Python):
class Orc(object):
total = 0
# you don't need accessors in Python: most things are public anyway
# and you got property
def __init__ (self, name):
Orc.total += 1
self.name = name # we get the name as a parameter
def __str__(self):
# this will be call when printing an orc
return self.name
# list comprehension are quick and clean ways to create lists
# give a real name to your list
orcs = [Orc(raw_input("Enter a name:\n")) for i in range(4)]
# using parenthesis for `print` is a good habit to take with then incoming Python 3
print("You have created %s Orcs!" % Orc.total)
for i, orc in enumerate(orcs):
print("Orc #%s is %s" % (i, orc))
list.append returns a None value, so it essentially never makes sense to assign its result to anything. You call append for the side-effects, i.e., to have it put a value at the end of the list. Like this:
for i in range (4):
list.append(Orc.get_score(Orc()))
I don't think the Orc.get_score(Orc()) is what you want, either: it also returns None instead of a score and the method call is technically correct but unlikely to be what you really intend.
Why should there be something in your list?
you do:
list.append(Orc.get_score(Orc())
which is equivalent to:
item_to_add = Orc.get_score(Orc())
list.append(item_to_add)
Your method Orc.get_score has no return statement, so it returns None. therefore, item_to_add will be None, and None will be appended to your list.
As a side note: python is not java. Dont use classes just to use classes. Use classes, when you want to follow OO-Pradigma, i.e. sending messages to objects.

Python Newbie: Returning Multiple Int/String Results in Python

I have a function that has several outputs, all of which "native", i.e. integers and strings. For example, let's say I have a function that analyzes a string, and finds both the number of words and the average length of a word.
In C/C++ I would use # to pass 2 parameters to the function. In Python I'm not sure what's the right solution, because integers and strings are not passed by reference but by value (at least this is what I understand from trial-and-error), so the following code won't work:
def analyze(string, number_of_words, average_length):
... do some analysis ...
number_of_words = ...
average_length = ...
If i do the above, the values outside the scope of the function don't change. What I currently do is use a dictionary like so:
def analyze(string, result):
... do some analysis ...
result['number_of_words'] = ...
result['average_length'] = ...
And I use the function like this:
s = "hello goodbye"
result = {}
analyze(s, result)
However, that does not feel right. What's the correct Pythonian way to achieve this? Please note I'm referring only to cases where the function returns 2-3 results, not tens of results. Also, I'm a complete newbie to Python, so I know I may be missing something trivial here...
Thanks
python has a return statement, which allows you to do the follwing:
def func(input):
# do calculation on input
return result
s = "hello goodbye"
res = func(s) # res now a result dictionary
but you don't need to have result at all, you can return a few values like so:
def func(input):
# do work
return length, something_else # one might be an integer another string, etc.
s = "hello goodbye"
length, something = func(s)
If you return the variables in your function like this:
def analyze(s, num_words, avg_length):
# do something
return s, num_words, avg_length
Then you can call it like this to update the parameters that were passed:
s, num_words, avg_length = analyze(s, num_words, avg_length)
But, for your example function, this would be better:
def analyze(s):
# do something
return num_words, avg_length
In python you don't modify parameters in the C/C++ way (passing them by reference or through a pointer and doing modifications in situ).There are some reasons such as that the string objects are inmutable in python. The right thing to do is to return the modified parameters in a tuple (as SilentGhost suggested) and rebind the variables to the new values.
If you need to use method arguments in both directions, you can encapsulate the arguments to the class and pass object to the method and let the method use its properties.

Categories

Resources