Python 3.3 Serial key generator list problems - python

I am making a serial key generator for a school exercise, and I am running into a small problem. When I run the program, and type in I want to make 20 serial keys, the program will make twenty of the same keys. The cause of this is in the for loop making variables every time it passes by. (The v{0} thing)
I can not figure out how to use another method to read all the values in a list, and create variables out of them.
My code:
import random, sys
class Application:
def __init__(self):
global i
i = int(input("How many serial codes do you want to create?\n"))
print("")
self.main(i)
def main(self, i):
seq = "ABCDFGHJIKLMNOPQRSTUVWXYZ1234567890"
store = []
for z in range(0, i):
for x in range(0, 5):
first = random.choice(seq)
second= random.choice(seq)
third = random.choice(seq)
fourth =random.choice(seq)
fifth = random.choice(seq)
serial = first + second + third + fourth + fifth
store.append(serial)
for y, item in enumerate(store):
setattr(sys.modules[__name__], 'v{0}'.format(y), item)
create = v0 + "-" + v1 + "-" + v2 + "-" + v3 + "-" + v4
print(create)
print("\nCreated", i, "serial keys!")
if __name__ == '__main__':
app = Application()

You are doing some very funky stuff there that is totally not necessary.
This loop is your problem:
for y, item in enumerate(store):
setattr(sys.modules[__name__], 'v{0}'.format(y), item)
You are setting the same 5 global variables over and over again, overwriting the previous version. Your use of setattr(sys.modules[__name__], ..) is totally not needed when you have the globals() function giving you the global namespace as a dictionary. But setting global variables to solve a simple problem is like using a shotgun to catch one gnat.
Your code could be vastly simplified:
def main(self, count):
seq = "ABCDFGHJIKLMNOPQRSTUVWXYZ1234567890"
for i in range(count):
print('-'.join(''.join(random.choice(seq) for _ in range(5)) for _ in range(5)))
print("\nCreated {} serial keys!".format(count))
Sample printed output for count set to 5:
LWLGX-F6MNR-9YIZC-H23TK-TIGB9
YALYY-4ZARO-8H9BV-YMHVD-HFFGP
JNA5R-65GT1-TZ3BM-PNMZI-56NM3
39VCY-MLZ98-SU1PP-PYMX7-RZJQZ
76LGC-VF5MG-LK7C4-XPUSO-H0B97

You may find it useful to print store at the end for debugging purposes. You continually append to the list, but only ever read the first five elements.
The use of global variables is a bit odd to me, but the underlying problem is the way you're using the list.

Related

python - modifying an item inside an array using a function

I am new to python. Can someone please explain to me how this works in python?
How to change the value of item in the main function?
def calc(arr = []):
index = 0
for item in arr:
item = item + 1
arr[index] = item
index += 1
if __name__ == '__main__':
item = 1
calc([item])
print("item is => ", item)
If your aim is to change an immutable value in some way, this would be best:
def add_one(value):
return value + 1
def main():
# your code moved to a function, to avoid these variables inadvertently becoming globals
item = 1
# update item with the function result
item = add_one(item)
print("item is => ", item)
if __name__ == '__main__':
main()
From your example, it appears you want to update a list with each item in the list incremented by 1, you can do that the same way:
def add_one_all(values):
return [values + 1 for values in values]
def main():
items = [1, 4, 9]
# update items with the function result
items = add_one_all(items)
print("items are => ", items)
if __name__ == '__main__':
main()
However, since a list is mutable, you can update it from inside a function, by making the changes to the list in-place:
def add_one_all_inplace(values: list = None):
if values is not None:
for i in range(len(values)):
values[i] += 1
def main():
items = [1, 4, 9]
# update the content of items
add_one_all_inplace(items)
print("items are => ", items)
if __name__ == '__main__':
main()
The advantage of the latter solution is that no new list is created, which may be preferable if you need to be very frugal with space, or are only making a few changes to a very large list - your example would probably be better served with the second solution though.
Note that the way you called the function still wouldn't work in the latter case:
def main():
item = 1
add_one_all_inplace([item])
The list containing item would be changed to be [2], but that doesn't affect item itself. The list passed to add_one_all_inplace will just contain the value of item, not a reference to it.
you can do with the global keyword in python which allows us to use a non-global variable as global if we get an error like 'UnboundLocalError: local variable '' referenced before assignment' in that case we also use the global keyword I have done the same code with proper assignment in the below image
as you have declared variable in the wrong place because that would only be accessible inside the if block only so you have to place the variable at the upper level and what will happen if I don't use the global keyword see the below image
you can see the difference
and if you like my answer please follow me and upvote my answer

Setting up a simple function in Python

I'm trying to write a function which takes my input as amount of dicerolls, gets a random number between 1,6 for that amount of dicerolls, and then appends these to a list.
I've tried different return messages, but I can't seem to to make it append to a list, and can't really think of what else I can do with my code.
terninger = []
def terning_kast(antal_kast = int(input("Hvor mange terningekast? "))):
for x in range(antal_kast, 0, -1):
resultat = random.randint(1, 6)
terninger.append(resultat)
return resultat
print(terninger)
I'm expecting the code to append the random number 1,6 into my list above (terninger), but I'm only receiving an empty list.
you forgot to call your function => terning_kast()
terninger = []
def terning_kast(antal_kast = int(input("Hvor mange terningekast? "))):
for x in range(antal_kast, 0, -1):
resultat = random.randint(1, 6)
terninger.append(resultat)
return resultat
print('before', terninger)
terning_kast() # this is the line which you have missed
print('after', terninger)
There are few points that you need to correct in your logic. Meantime, following is probably that you want.
import random as rnd
def terning_kast(count):
terninger = []
for x in range(count, 0, -1):
resultat = rnd.randint(1, 6)
terninger.append(resultat)
return terninger
if __name__ == "__main__":
cnt = input("Hvor mange terningekast? ")
if cnt.isdigit():
print(terning_kast(int(cnt)))
else:
print("Invalid entry")
In order to use the random module, first you need to import it into your module.
Though you are appending the generated random number to list, you never attempt to return that list. What you are returning is the last instance of result from the randint(x,y) function call.
You are defining your function as part of your module/script. In order to execute that function, you must either call it within module or import it to some other module. If you look at my example the if __name__ == "__main__": instruct the python interpreter to run your script if you were to execute from same module. If you were to consume this module (importing) from some other then you don't need to mentioned this if __name__ == "__main__":

How to globally declare this Python list

import concurrent.futures
import urllib.request
import json
myurls = {}
for x in range(1, 15):
for y in range(1, 87):
strvar1 = "%s" % (x)
strvar2 = "%s" % (y)
with open("C:\\Python33\\NASDAQ Stock Strings\\NASDAQ_Config_File_{}_{}.txt".format(x,y),"r") as f:
myurls[x,y] = f.read().replace('\n', '')
print("myurls_" + str(strvar1) + "_" + str(strvar2) + "=", myurls[x,y])
def myglob():
global myurls
URLS = [myurls2_1_1,myurls2_1_2,myurls2_1_3,myurls2_1_4,myurls2_1_5 ETC>>>ETC >>>]
The code below here works fine. The idea is:
Define multiple strings from multiple source .txt files into a dictionary.
Pass these multiple variables to the URLS = [] statement at the same time so that they may be processed in parallel using the concurrent.futures module for python.
You say
def myglob():
global myurls
works syntax wise but the list of variables I then want to use i.e. myurls2_1_1, myurls2_1_2 etc are throwing up an error saying that they are not defined.
That is right. But you are quite close: just access them exactly the way you defined them: as myurls[1,1] or how you defined them.
Defining variables in a dynamic way is almost never the way to go; normally you can achieve that by any dict key or list index access.
As you now provided an example, I can exactly show how you'd do:
myurls = {}
for x in range(1, 15):
for y in range(1, 87):
strvar1 = "%s" % (x) # you can omit these.
strvar2 = "%s" % (y)
with open("C:\\Python33\\NASDAQ Stock Strings\\NASDAQ_Config_File_{}_{}.txt".format(x,y),"r") as f: # This is NOT the right place to put an application-specific config file.
myurls[x,y] = f.read().replace('\n', '')
print("myurls[%d,%d] = %s" % (x, y, myurls[x,y]))
def myglob(): # this function is completely pointless.
global myurls
# Construct your urls list only after you have everything that belongs in it, i. e. on the correct indentation level:
urls = [myurls[1,1], myurls[1,2], myurls[1,3], myurls[1,4], ...]
This would be one way to go. It looks very complicated and weird, this last, very long line.
But you can shorten it with a list comprehension:
urls = [myurls[x,y] for x in range(1, 15) for y in range(1, 87)]
But then, you might be asked: "Why not construct it on the way already?"
Well, here we go:
myurls = {}
urls = []
for x in range(1, 15):
for y in range(1, 87):
with open("C:\\Python33\\NASDAQ Stock Strings\\NASDAQ_Config_File_{}_{}.txt".format(x,y), "r") as f:
thisfile = f.read().replace('\n', '')
myurls[x,y] = thisfile
urls.append(thisfile)
print("myurls[%d,%d] = %s" % (x, y, thisfile))
and there you are.
There is no need to put them all at once into the list, as this has nothing to do with parallelization, which only seems to come later.
All that counts is that you have the urls present at the start of the parallelization. If this happens at once or item by item does not matter.

I am getting the error "Can't assign to Operator"

I am not sure why it is giving me this error... the part it says is giving me the error is the previousFirst + previousSecond = previousSecond. If you are wondering the goal is to print out as many fibonnaci numbers that the user wants to print out.
def fibbonaci():
fibbNumber = input("How many Fibonacci numbers should I print for you?")
fibbNumber = int(fibbNumber)
global counter
counter = 0
global previousFirst
previousFirst = 0
global previousSecond
previousSecond = 1
global previousSaved
previousSaved = 1
while (counter < fibbNumber):
previousSaved = previousSecond
previousFirst + previousSecond = previousSecond
print (previousFirst)
print (previousSecond)
counter += 1
fibbonaci()
1. You have the assignment turned around. The format is
<i>variable</i> = <i>new value</i>
so make that:
previous_second = previous second + previous_first
2. A more normal (non-Python) way to do this is:
next = current + previous
previous = current
current = next
where "next" is a temporary variable to compute the next in sequence.
3. Python has the ability to do multiple assignments, eliminating the need for temporary variables in this an many other cases. You can do all of the above with:
current, previous = current+previous, current
Both computations on the right are done before any assigning happens. The new value of current is the sum of the old values current+previous, and the new value of previous is the old value of current. Put that in a "for xyz in range(n):" loop, after initializing current=0, previous=1, and you get a loop that works for all non-negative n (including 0). The final value of current is your result.
4. Its "Fibonacci", not "Fibbonaci", and the guy's real name was Leonardo.
The left hand side of an assignment statement must be a valid name, not an expression. (The + is an operator, which means its included in expressions)
This is the line of the culprit,
previousFirst + previousSecond = previousSecond
Also, your code does have a little bit of formatting issues, namely the indentation is bad for the first function. Normally you can get away with this, but being Python, it's part of the language syntax. It also might just be how you copied and pasted it to Stack, take a look at the tips in How to Edit and How to Format bars, when editing your post.
The line should be
previousSecond = previousFirst + previousSecond
That's the problem
UPDATE:
There are some logic error to calculate fibbonaci number, the while part coule be:
while (counter < fibbNumber):
previousSaved = previousSecond
previousSecond = previousFirst + previousSecond
previousFirst = previousSaved
print (previousFirst)
print (previousSecond)
counter += 1

Python Lambda Count/Loop Function

I'm sorry if this is a question answered elsewhere. Searching through Google and Stackforum I didn't find anything from which I could extrapolate the answers; but I feel like part of that is me.
I'm trying to work out lambdas as a concept, and as part of that I'm kinda looking for ways to use it.
SO, if this is a colossally stupid thing to do with lambda from a function standpoint, feel free to let me know and explain. But either way, I still want to know the answer/still want to know how to do this with the python language.
So, for testing purposes I have:
my_test = 'test_name'
testlist = ['test_name', 'test_name_dup', 'test_name_dup_1', 'test_name_dup_3']
I'm looking to use lambda to create one function that loops through and returns the first test_name_# that isn't in the testlist. The functionality will eventually be applied to filenames, but for testing purposes I had to get away from actually reading the filenames--gave me too many more ways to mess something up.
But my_test has to be able to change, and the test list will be a list of filepaths.
So, I'm looking for a function like:
new_name = lambda x: my_test + '_' + str(x)
But the initial value should be x = 1, and it should continue until new_name is not in testlist. Seems like:
bool(new_name not in testlist)
might be something work with.
But I can't figure out a way to set the initial x to 1, and have it loop through with (x+1) until the bool is true.
I know this is possible as I've found some CRAZY lambda examples out there that are looping through lines in a file. I just couldn't quite make sense of them (and didn't have any way to play with them as they were dealing with things outside my programming level.
On a related note, could I add values to the beginning of this loop? (i.e. can I have it check for test_name, then test_name_dup, then test_name_dup_#)?
Thanks in advance for the help! Lambdas (while very cool) totally mess with my head.
Lambdas are just another way of defining a function
def foo(x):
return x + x
is the same as
foo = lambda x: x + x
So let's start with a function to do what you want:
def first_missing(items, base):
for number in itertools.count():
text = base + '_' + str(number)
if text not in items:
return text
The first thing to note is that you can't use loops inside a lambda. So we'll need to rewrite this without a loop. Instead, we'll use recursion:
def first_missing(items, base, number = 0):
text = base + '_' + str(number)
if text not in items:
return text
else:
return first_missing(items, base, number + 1)
Now, we also can't use an if/else block in a lambda. But we can use a ternary expression:
def first_missing(items, base, number = 0):
text = base + '_' + str(number)
return text if text not in items else first_missing(items, base, number + 1)
We can't have local variables in a lambda, so we'll use a trick, default arguments:
def first_missing(items, base, number = 0):
def inner(text = base + '_' + str(number)):
return text if text not in items else first_missing(items, base, number + 1)
return inner()
At this point we can rewrite inner as a lambda:
def first_missing(items, base, number = 0):
inner = lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1)
return inner()
We can combine two lines to get rid of the inner local variable:
def first_missing(items, base, number = 0):
return (lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1))()
And at long last, we can make the whole thing into a lambda:
first_missing = lambda: items, base, number = 0: (lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1))()
Hopefully that gives you some insight into what you can do. But don't ever do it because, as you can tell, lambdas can make your code really hard to read.
There's no need to use a lambda in this case, a simple for loop will do:
my_test = 'test_name_dup'
testlist = ['test_name', 'test_name_dup','test_name_dup_1', 'test_name_dup_3']
for i in xrange(1, len(testlist)):
if my_test + '_' + str(i) not in testlist:
break
print my_test + '_' + str(i)
> test_name_dup_2
If you really, really want to use a lambda for this problem, you'll also have to learn about itertools, iterators, filters, etc. I'm gonna build on thg435's answer, writing it in a more idiomatic fashion and explaining it:
import itertools as it
iterator = it.dropwhile(
lambda n: '{0}_{1}'.format(my_test, n) in testlist,
it.count(1))
print my_test + '_' + str(iterator.next())
> test_name_dup_2
The key to understanding the above solution lies in the dropwhile() procedure. It takes two parameters: a predicate and an iterable, and returns an iterator that drops elements from the iterable as long as the predicate is true; afterwards, returns every element.
For the iterable, I'm passing count(1), an iterator that produces an infinite number of integers starting from 1.
Then dropwhile() starts to consume the integers until the predicate is false; this is a good opportunity for passing an in-line defined function - and here's our lambda. It receives each generated integer in turn, checking to see if the string test_name_dup_# is present in the list.
When the predicate returns false, dropwhile() returns and we can retrieve the value that made it stop by calling next() on it.
You can combine a lambda with itertools.dropwhile:
import itertools
n = itertools.dropwhile(lambda n: 'test_name_dup_%d' % n in testlist, range(1, len(testlist))).next()
As to your last question, you can write a generator for names, like:
def possible_names(prefix):
yield prefix
yield prefix + '_dup'
n = 0
while True:
n += 1
yield '%s_dup_%d' % (prefix, n)
and then use this generator with dropwhile:
unique_name = itertools.dropwhile(lambda x: x in testlist, possible_names('test_name')).next()
print unique_name
You are a bit off the track. Lambdas are nothing but "simple" functions, often used for their fast syntax in functional programming. They are the perfect companion built-in functions "map", "reduce", "filter" but also for more complicated functions defined into itertools. Therefore the most useful thing to do with them is to generate/manipulate iterable objects (especially lists). Note that lambdas will slow down your code in most of the cases if compared to list comprehensions/normal loops and will make it harder to be read. Here is an example of what you want to do with lambdas.
>>> filter(lambda i: i!=(0 if len(testlist[i].split("_"))==3 else int(testlist[i].split("_")[-1])), range(len(testlist)))[0]
2
Or you could use more complicated functions with itertools. Anyhow I strongly suggest you not to use lambdas for this kind of assignments, as the readability is terrible. I'd rather use a well structured for loop, which is also faster.
[Edit]
To prove that lambdas+builtins are not faster than list comprehensions: consider a simple problem, for x in range(1000) create a list of x shifted by 5.
$ python -m timeit 'map(lambda x: x>>5, range(1000))' 1000 loops, best of 3: 225 usec per loop
$ python -m timeit '[x>>5 for x in range(1000)]'10000 loops, best of 3: 99.1 usec per loop
You have a >100% performance increase without lambdas.
I prefer the list comprehension or iterator method. Makes for easy one liners that I feel are pretty easy to read and maintain. Quite frankly, lambdas belong some places, here I believe its less elegant a solution.
my_test = 'test_name'
prefix = 'test_name_dup_'
testlist = ['test_name','test_name_dup','test_name_dup_1','test_name_dup_3']
from itertools import count
print next('%s%d' % (prefix, i) for i in count(1) if '%s%d' % (prefix, i) not in testlist)
This returns the first not-found instance in the sequence, which I think is the cleanest.
Of course, if you prefer a list from a definite range, you can modify it to become a list comprehension:
print ['%s%d' % (prefix, i) for i in xrange(0,5) if '%s%d' % (prefix, i) not in testlist]
returns:
['test_name_dup_0', 'test_name_dup_2', 'test_name_dup_4']

Categories

Resources