Python: Using code to write code - For a beginner - python

The issue I'm having right now is loading a bunch of sound files as their own objects in Pygame. You load a sound with this syntax:
sound1 = pygame.mixer.Sound('file.wav')
Say I have seven files, and I want them loaded and named sound1 - sound7. And I didn't want to load them each individually. If I didn't know it was flawed, I would try something like this:
for i in range(1, 8):
new = 'sound' + str(i)
new = pygame.mixer.Sound(str(new) + 'wav')
How would I go about making 'new' it's own variable, and not a string? I've read about getattr, but it's confusing. I would really like to know how to use functions and loops to dynamically create code, but so far I can't find anything useful to a beginner like myself. Using this as an example, would anybody like to explain in a simple way the ways you could go about creating code inside of code and turn strings into usable variables/objects?
Thank you!

sounds = [] # list
for i in range(1, 8):
sounds.append(pygame.mixer.Sound('sound' + str(i) + 'wav'))
Or
sounds = {} # dictionary
for i in range(1, 8):
sounds[i] = pygame.mixer.Sound('sound' + str(i) + 'wav')
At first it seems you use the dictionary approach the same as the list approach, e.g. sounds[1] sounds[2] and so on, but you can also do this:
sounds = {} # dictionary
for i in range(1, 8):
sounds['sound' + str(i)] = pygame.mixer.Sound('sound' + str(i) + 'wav')
And now sounds["sound1"] and so on work, for example.

You can use arrays for this:
sound = []
for i in range(1,8):
sound.append (pygame.mixer.Sound("sound%d.wav" % i))
# Now use sound[0..6] to reference sound[1..7].wav
That will load the files sound1.wav through sound8.wav - if your files are named differently, you just change the range and/or string formatting.

There are 2 kinds of loops in python the for-loop and the while-loop. The for-loop is used to repeat something n number of times. The while-loop is used to repeat until something happens. For-loops are useful for game programming as they often handle the frames the game displays. Each frame runs one time through a loop. The way you store a for-loop is with a list. Here is an example of a basic loop you can familiarize yourself with:
he_count = [1, 2, 3, 4, 5]
fruits = ['apples', 'oranges', 'pears', 'apricots']
change = [1, 'pennies', 2, 'dimes', 3, 'quarters']
# this first kind of for-loop goes through a list
for number in the_count:
print "This is count %d" % number
# same as above
for fruit in fruits:
print "A fruit of type: %s" % fruit
# also we can go through mixed lists too
# notice we have to use %r since we don't know what's in it
for i in change:
print "I got %r" % i
# we can also build lists, first start with an empty one
elements = []
# then use the range function to do 0 to 5 counts
for i in range(0, 6):
print "Adding %d to the list." % i
# append is a function that lists understand
elements.append(i)
# now we can print them out too
for i in elements:
print "Element was: %d" % i
You can learn more about loops and game programming in python here:
programarcadegames.com/index.php?lang=en&chapter=loops

Related

How do you convert the quotient of a division of two polynomials to a standard polynomial instead of a tuple in Python [duplicate]

I would like to know if there is a better way to print all objects in a Python list than this :
myList = [Person("Foo"), Person("Bar")]
print("\n".join(map(str, myList)))
Foo
Bar
I read this way is not really good :
myList = [Person("Foo"), Person("Bar")]
for p in myList:
print(p)
Isn't there something like :
print(p) for p in myList
If not, my question is... why ? If we can do this kind of stuff with comprehensive lists, why not as a simple statement outside a list ?
Assuming you are using Python 3.x:
print(*myList, sep='\n')
You can get the same behavior on Python 2.x using from __future__ import print_function, as noted by mgilson in comments.
With the print statement on Python 2.x you will need iteration of some kind, regarding your question about print(p) for p in myList not working, you can just use the following which does the same thing and is still one line:
for p in myList: print p
For a solution that uses '\n'.join(), I prefer list comprehensions and generators over map() so I would probably use the following:
print '\n'.join(str(p) for p in myList)
I use this all the time :
#!/usr/bin/python
l = [1,2,3,7]
print "".join([str(x) for x in l])
[print(a) for a in list] will give a bunch of None types at the end though it prints out all the items
For Python 2.*:
If you overload the function __str__() for your Person class, you can omit the part with map(str, ...). Another way for this is creating a function, just like you wrote:
def write_list(lst):
for item in lst:
print str(item)
...
write_list(MyList)
There is in Python 3.* the argument sep for the print() function. Take a look at documentation.
Expanding #lucasg's answer (inspired by the comment it received):
To get a formatted list output, you can do something along these lines:
l = [1,2,5]
print ", ".join('%02d'%x for x in l)
01, 02, 05
Now the ", " provides the separator (only between items, not at the end) and the formatting string '02d'combined with %x gives a formatted string for each item x - in this case, formatted as an integer with two digits, left-filled with zeros.
To display each content, I use:
mylist = ['foo', 'bar']
indexval = 0
for i in range(len(mylist)):
print(mylist[indexval])
indexval += 1
Example of using in a function:
def showAll(listname, startat):
indexval = startat
try:
for i in range(len(mylist)):
print(mylist[indexval])
indexval = indexval + 1
except IndexError:
print('That index value you gave is out of range.')
Hope I helped.
I think this is the most convenient if you just want to see the content in the list:
myList = ['foo', 'bar']
print('myList is %s' % str(myList))
Simple, easy to read and can be used together with format string.
I recently made a password generator and although I'm VERY NEW to python, I whipped this up as a way to display all items in a list (with small edits to fit your needs...
x = 0
up = 0
passwordText = ""
password = []
userInput = int(input("Enter how many characters you want your password to be: "))
print("\n\n\n") # spacing
while x <= (userInput - 1): #loops as many times as the user inputs above
password.extend([choice(groups.characters)]) #adds random character from groups file that has all lower/uppercase letters and all numbers
x = x+1 #adds 1 to x w/o using x ++1 as I get many errors w/ that
passwordText = passwordText + password[up]
up = up+1 # same as x increase
print(passwordText)
Like I said, IM VERY NEW to Python and I'm sure this is way to clunky for a expert, but I'm just here for another example
Assuming you are fine with your list being printed [1,2,3], then an easy way in Python3 is:
mylist=[1,2,3,'lorem','ipsum','dolor','sit','amet']
print(f"There are {len(mylist):d} items in this lorem list: {str(mylist):s}")
Running this produces the following output:
There are 8 items in this lorem list: [1, 2, 3, 'lorem', 'ipsum',
'dolor', 'sit', 'amet']
OP's question is: does something like following exists, if not then why
print(p) for p in myList # doesn't work, OP's intuition
answer is, it does exist which is:
[p for p in myList] #works perfectly
Basically, use [] for list comprehension and get rid of print to avoiding printing None. To see why print prints None see this
To print each element of a given list using a single line code
for i in result: print(i)
You can also make use of the len() function and identify the length of the list to print the elements as shown in the below example:
sample_list = ['Python', 'is', 'Easy']
for i in range(0, len(sample_list)):
print(sample_list[i])
Reference : https://favtutor.com/blogs/print-list-python
you can try doing this: this will also print it as a string
print(''.join([p for p in myList]))
or if you want to a make it print a newline every time it prints something
print(''.join([p+'\n' for p in myList]))

for loops in Python - how to modify i inside the loop

This code was written in Python 3.6 in Jupyter Notebooks. In other languages, I am pretty sure I built loops that looked like this:
endRw=5
lenDF=100 # 1160
for i in range(0, lenDF):
print("i: ", i)
endIndx = i + endRw
if endIndx > lenDF:
endIndx = lenDF
print("Range to use: ", i, ":", endIndx)
# this line is a mockup for an index that is built and used
# in the real code to do something to a pandas DF
i = endIndx
print("i at end of loop", i)
In testing though, i does not get reset to endIndx and so the loop does not build the intended index values.
I was able to solve this problem and get what I was looking for by building a while loop like this:
endRw=5
lenDF=97 # 1160
i = 0
while i < lenDF:
print("i: ", i)
endIndx = i + endRw
if endIndx > lenDF:
endIndx = lenDF
print("Range to use: ", i, ":", endIndx)
# this line is a mockup for an index that is built and used
# in the real code to do something to a pandas DF
i = endIndx
print("i at end of loop: ", i)
Question: is there a way to modify the i from inside the for loop in python? Is there a way to do what I did with the while loop using a for loop in Python?
Solved the problem with while but just curious about this.
You can modify the loop variable in a for loop, the problem is that for loops in Python are not like "old-style" for loops in e.g. Java, but more like "new-style" for-each loops.
In Python, for i in range(0, 10): does not behave like for (int i = 0; i < 10; i++) {, but like for (int i : new int[] {0, 1, ..., 10}}.
That is, in each iteration of the loop, the loop head will not modify the loop variable (e.g. increment it), but assign a new value to it, i.e. the next value from the given iterable (a range in your case). Thus, any modification that you did in the previous iteration are overwritten.
If you want to loop a known number of iterations or for every item in an iterable, use a for loop, but if you want to loop until a certain condition (no longer) holds, as in your case, use while.
for loops operate on iterables. In for i in range(0, lenDF), i is assigned the next value in the range on each round of the loop regardless of how it is used in the loop. The question then, is whether there is a clean way to write an iterable that does what you want. In this case, all you want is to advance by a fixed step and adjust the final step length to account for the end of data.
endRw=5
lenDF=97 # 1160
for i in range(0, lenDF, endRw):
endIndx = min(i+endRw, lenDF)
print("Range to use: ", i, ":", endIndx)
This answer is unlikely to be useful, but since you were just curious:
The closest I think to what you want to do would be using a generator and its send method:
>>> def jumpable_range(start, stop):
... i = start
... while i <= stop:
... j = yield i
... i = i + 1 if j is None else j
...
>>> R = jumpable_range(2, 10)
>>>
>>> for i in R:
... if i==5:
... i = R.send(8)
... print(i)
...
2
3
4
8
9
10
>>>
Taking the original question literally:
#Tobias_k provides a good explanation of when to use while versus for loops, and the use case of this question fits while better (at least for Python). In short: you cannot directly modify the i in for i in because of how this code works under the covers in Python. So while should be used for a use case where you need to change your counter inside a loop (in Python).
#tdelaney provides a good answer in terms of refactoring the code using a Python for loop given the way Python behaves (the accepted answer to this question).
#PaulPanzer provides concepts that, while over-complicated, are useful to students to explore new concepts; but the answer solves the for loop problem by using a while loop inside an iterator and calling that into the for loop.
Even so, the concepts explored that play to the use of yield and iterators are worth exploring. If we take these concepts and attempt to re-write the original code to exploit them, this is what that code would look like:
def jumpable_range(start, stop):
i = start
while i <= stop:
j = yield i
i = i + 1 if j is None else j
endRw=5
lenDF=97 # 1160
Q = jumpable_range(0,lenDF)
for i in Q:
print("i: ", i)
endIndx = i + endRw
if endIndx > lenDF:
endIndx = lenDF
if i == endIndx: break
print("Range to use: ", i, ":", endIndx)
# this line is a mockup for an index that is built and used
# in the real code to do something to a pandas DF
i = Q.send(endIndx-1)
print("i at end of loop", i)
You always can set the value of i in a for loop. The problem is your setting value statement is before the implicit for loop setting value statement and covered by latter. You cannot change the rule to make latter statement useless. You shouldn't do this even you can. Just change to use proper conditional variable.

Function to reverse text characters

I am trying to make a reverse function which takes an input (text) and outputs the reversed version. So "Polar" would print raloP.
def reverse(text):
list = []
text = str(text)
x = len(text) - 1
list.append("T" * x)
for i in text:
list.insert(x, i)
x -= 1
print "".join(list)
reverse("Something")
As others have mentioned, Python already provides a couple of ways to reverse a string. The simple way is to use extended slicing: s[::-1] creates a reversed version of string s. Another way is to use the reversed function: ''.join(reversed(s)). But I guess it can be instructive to try implementing it for yourself.
There are several problems with your code.
Firstly,
list = []
You shouldn't use list as a variable name because that shadows the built-in list type. It won't hurt here, but it makes the code confusing, and if you did try to use list() later on in the function it would raise an exception with a cryptic error message.
text = str(text)
is redundant. text is already a string. str(text) returns the original string object, so it doesn't hurt anything, but it's still pointless.
x = len(text) - 1
list.append("T" * x)
You have an off-by-one error here. You really want to fill the list with as many items as are in the original string, this is short by one. Also, this code appends the string as a single item to the list, not as x separate items of one char each.
list.insert(x, i)
The .insert method inserts new items into a list, the subsequent items after the insertion point get moved up to make room. We don't want that, we just want to overwrite the current item at the x position, and we can do that by indexing.
When your code doesn't behave the way you expect it to, it's a Good Idea to add print statements at strategic places to make sure that variables have the value that they're supposed to have. That makes it much easier to find where things are going wrong.
Anyway, here's a repaired version of your code.
def reverse(text):
lst = []
x = len(text)
lst.extend("T" * x)
for i in text:
x -= 1
lst[x] = i
print "".join(lst)
reverse("Something")
output
gnihtemoS
Here's an alternative approach, showing how to do it with .insert:
def reverse(text):
lst = []
for i in text:
lst.insert(0, i)
print "".join(lst)
Finally, instead of using a list we could use string concatenation. However, this approach is less efficient, especially with huge strings, but in modern versions of Python it's not as inefficient as it once was, as the str type has been optimised to handle this fairly common operation.
def reverse(text):
s = ''
for i in text:
s = i + s
print s
BTW, you really should be learning Python 3, Python 2 reaches its official End Of Life in 2020.
You can try :
def reverse(text):
return text[::-1]
print(reverse("Something")) # python 3
print reverse("Something") # python 2
Easier way to do so:
def reverse(text):
rev = ""
i = len(text) - 1
while i > -1:
rev += text[i]
i = i - 1
return rev
print(reverse("Something"))
result: gnihtemoS
You could simply do
print "something"[::-1]

Searching for a character or string of characters in a list (like the find function on websites)

My first post here.
I'd like to create a search function, searching a list for any raw_input entered.
So far, I've been able to call a path on computer and append each item to a list.
I know I can list.index() for a complete file name, but I'd like it to search for
simply any character(s) one might want to input.
Here's what I've got so far:::
import os
list1 = []
x = "/Users/User/temp"
vec = os.listdir(x)
for p in vec:
list1.append(p)
for line in list1:
print line
o = raw_input("search>>> ")
print list.index(o)
Now, with this code, the filename has to be typed in exactly...
So, it'll take my path(users/user/temp) and make a list from it, search
the list for the filename and return the index at which it lies.
How can I search for say.. (you) in the list and bring up a result that
might be (youarewonderful.txt).
Thanks, I'm very new to Python, so any insight or code improvements are welcome
as well.
-peer
This gives a list of indices:
[i for i, x in enumerate(vec) if "you" in x]
This is called a list comprehension, and it uses the enumerate function to keep track of the indices. If you aren't familiar with these, I recommend the official python tutorial here
I've got a lead!
Next, I added:::
for p in vec:
if 'yo' in p:
print p
print list1.index(p)
Sorry Patrick, this is more along the lines of what I wanted to do. Thanks anyways! -although I don't quite get what you were getting at. I'd like to know, though.
Here is completed program, don't know how I got here:::
import os
list1 = []
x = "/Users/User/temp"
vec = os.listdir(x)
for p in vec:
list1.append(p)
for line in list1:
print line
b = raw_input('search for item in list/path>>> ')
for p in vec:
if str(b) in p:
print p
print list1.index(p)
Woo Hoo
-peer

Python - making counters, making loops?

I am having some trouble with a piece of code below:
Input: li is a nested list as below:
li = [['>0123456789 mouse gene 1\n', 'ATGTTGGGTT/CTTAGTTG\n', 'ATGGGGTTCCT/A\n'], ['>9876543210 mouse gene 2\n', 'ATTTGGTTTCCT\n', 'ATTCAATTTTAAGGGGGGGG\n']]
Using the function below, my desired output is simply the 2nd to the 9th digits following '>' under the condition that the number of '/' present in the entire sublist is > 1.
Instead, my code gives the digits to all entries. Also, it gives them multiple times. I therefore assume something is wrong with my counter and my for loop. I can't quite figure this out.
Any help, greatly appreciated.
import os
cwd = os.getcwd()
def func_one():
outp = open('something.txt', 'w') #output file
li = []
for i in os.listdir(cwd):
if i.endswith('.ext'):
inp = open(i, 'r').readlines()
li.append(inp)
count = 0
lis = []
for i in li:
for j in i:
for k in j[1:] #ignore first entry in sublist
if k == '/':
count += 1
if count > 1:
lis.append(i[0][1:10])
next_func(lis, outp)
Thanks,
S :-)
Your indentation is possibly wrong, you should check count > 1 within the for j in i loop, not within the one that checks every single character in j[1:].
Also, here's a much easier way to do the same thing:
def count_slashes(items):
return sum(item.count('/') for item in items)
for item in li:
if count_slashes(item[1:]) > 1:
print item[0][1:10]
Or, if you need the IDs in a list:
result = [item[0][1:10] for item in li if count_slashes(item[1:]) > 1]
Python list comprehensions and generator expressions are really powerful tools, try to learn how to use them as it makes your life much simpler. The count_slashes function above uses a generator expression, and my last code snippet uses a list comprehension to construct the result list in a nice and concise way.
Tamás has suggested a good solution, although it uses a very different style of coding than you do. Still, since your question was "I am having some trouble with a piece of code below", I think something more is called for.
How to avoid these problems in the future
You've made several mistakes in your approach to getting from "I think I know how to write this code" to having actual working code.
You are using meaningless names for your variables which makes it nearly impossible to understand your code, including for yourself. The thought "but I know what each variable means" is obviously wrong, otherwise you would have managed to solve this yourself. Notice below, where I fix your code, how difficult it is to describe and discuss your code.
You are trying to solve the whole problem at once instead of breaking it down into pieces. Write small functions or pieces of code that do just one thing, one piece at a time. For each piece you work on, get it right and test it to make sure it is right. Then go on writing other pieces which perhaps use pieces you've already got. I'm saying "pieces" but usually this means functions, methods or classes.
Fixing your code
That is what you asked for and nobody else has done so.
You need to move the count = 0 line to after the for i in li: line (indented appropriately). This will reset the counter for every sub-list. Second, once you have appended to lis and run your next_func, you need to break out of the for k in j[1:] loop and the encompassing for j in i: loop.
Here's a working code example (without the next_func but you can add that next to the append):
>>> li = [['>0123456789 mouse gene 1\n', 'ATGTTGGGTT/CTTAGTTG\n', 'ATGGGGTTCCT/A\n'], ['>9876543210 mouse gene 2\n', 'ATTTGGTTTCCT\n', 'ATTCAATTTTAAGGGGGGGG\n']]
>>> lis = []
>>> for i in li:
count = 0
for j in i:
break_out = False
for k in j[1:]:
if k == '/':
count += 1
if count > 1:
lis.append(i[0][1:10])
break_out = True
break
if break_out:
break
>>> lis
['012345678']
Re-writing you code to make it readable
This is so you see what I meant in the beginning of my answer.
>>> def count_slashes(gene):
"count the number of '/' character in the DNA sequences of the gene."
count = 0
dna_sequences = gene[1:]
for sequence in dna_sequences:
count += sequence.count('/')
return count
>>> def get_gene_name(gene):
"get the name of the gene"
gene_title_line = gene[0]
gene_name = gene_title_line[1:10]
return gene_name
>>> genes = [['>0123456789 mouse gene 1\n', 'ATGTTGGGTT/CTTAGTTG\n', 'ATGGGGTTCCT/A\n'], ['>9876543210 mouse gene 2\n', 'ATTTGGTTTCCT\n', 'ATTCAATTTTAAGGGGGGGG\n']]
>>> results = []
>>> for gene in genes:
if count_slashes(gene) > 1:
results.append(get_gene_name(gene))
>>> results
['012345678']
>>>
import itertools
import glob
lis = []
with open('output.txt', 'w') as outfile:
for file in glob.iglob('*.ext'):
content = open(file).read()
if content.partition('\n')[2].count('/') > 1:
lis.append(content[1:10])
next_func(lis, outfile)
The reason you digits to all entries, is because you're not resetting the counter.

Categories

Resources