Class import from another .py file - python

This is my first question here so please don't roast me if it seems obvious or stupid ;)
I've started learning Python two months ago and I'm trying to get my head wrapped around some basic functions of this language.
I've created a script that creates a basic blockchain and generates a QR code at the end. I've created the following class:
class BlobChang:
def __init__(self, string=None, rand=None, conc=None, ha=None, blobchang=''):
self.string = string
self.rand = rand
self.conc = conc
self.ha = ha
self.blobchang = blobchang
def input(self):
self.string = input('Input: ')
def h(self):
self.rand = str(random.randrange(1, 1000))
self.conc = self.string + self.rand
self.ha = hashlib.sha256(self.string.encode('utf-8')).hexdigest()
self.blobchang = self.blobchang + self.ha
print(self.blobchang)
I've named that script BlobChang.py. In the same directory I've created a new Python file import_test.py and I've imported the BlobChang class:
from BlobChang import BlobChang
I've created an instance of this class named test:
test = BlobChang()
and it worked fine. I did test.input() and it worked, then test.h() and this worked as well but then something weird happened. The script instead of finishing started executing the remainder of the original code from BlobChang.py! It looks like this:
check_continue = input('Want to create a BlobChang? (Y/N): \n')
while if_yes(check_continue):
x.input()
x.h()
check = input('Want to continue? (Y/N): \n')
check_qr = input('Do you want to create a QR Code? (Y/N): \n')
if if_yes(check_qr) == True:
filename = str(input("Enter file name: "))+".png"
qrcode.make(x.blobchang).save(filename)
print("Your file name is: ", filename)
print('Thank you for working with BlobChang!')
However, it stopped only at the first conditional statement and went into a loop. Why did that happen?

The variable check_continue is never updated that's why the condition in while if_yes(check_continue): always remains true and the code goes into an infinite loop, maybe you want check_continue = input('Want to continue? (Y/N): \n') in line 5

Related

if statement won't execute all of the commands in its indentation level

I am working on a stupid yet funny practice program to improve my understanding of OOP in Python.
The program is meant to randomly generate some band names from a randomly selected adjective and another randomly selected noun - producing a lot of hilarious band names.
For the most part, the program works fine, but for some reason, there are some problems with the if-statements and the while loop in the menu(self)- method all the way down in the BandList class.
My hypothesis is that there is something wrong with the nesting of the else-if statements, or that the loop doesn't manage to advance the loop when I call on the self._generateBand() method in line 60 due to some technicality I'm not aware of. Either way, I'm not sure.
However, my question is:
Why does my loop stop at the line self._writeBand() and not continue executing the code that follows? (As shown below)
done = False
while done != True:
print("\n=============== BAND NAME GENEREATOR ==================")
start = input("\nDo you want to generate a list of bandnames? (y/n): ")
if start.lower() == "y":
self._generateBand()
self._writeBand() #The loop stops here for some reason and asks the same question over and over.
#The program won't execute this part of the code.
inp = ("\nDo you want to save these band names? (y/n): ")
if inp.lower() == "y":
outfile = input("What do you want to name the file?: ")
self._saveBand(f"{oufile}.txt")
If anyone can help me fix this, I would be super grateful.
In advance: Thank you for your help.
The complete program is pasted in below
import random
class Band:
def __init__(self, name):
self._Bandname = name
def __str__(self):
return f"{self._Bandname}"
def hentName(self):
return self._Bandname
class BandList:
def __init__(self):
self._BandList = []
def _readFile(self, filename1, filename2):
with open(filename1) as infile1, open(filename2) as infile2:
lineAdjective = infile1.read().splitlines()
lineNoun = infile2.read().splitlines()
adjective = random.choice(lineAdjective)
noun = random.choice(lineNoun)
return f"{adjective} {noun}"
def _saveBand(self, filename):
with open(filename, "w") as outfile:
for j, i in enumerate(self._BandList):
outfile.write(f"Nr: {j}\t-{i}\n")
def _generateBand(self):
num = int(input("\nHow many band names would you like to generate?: "))
for i in range(num):
bandname = f"The {self._readFile('adjective.txt', 'noun.txt')}s"
self._BandList.append(Band(name= bandname))
def _writeBand(self):
print("\n========= Genererte bandname =========")
for i in self._BandList:
print(i)
#print(i.hentName())
def _deleteBand(self):
self._BandList.clear()
def _writeGoodbyeMsg(self):
print("\n============ PROGRAM TERMINATING ================")
print("\t- thanks for using the program, goodbye!")
def menu(self):
done = False
while done != True:
print("\n=============== BAND NAME GENEREATOR ==================")
start = input("\nDo you want to generate a list of bandnames? (y/n): ")
if start.lower() == "y":
self._generateBand()
self._writeBand() #This is probably where the bug is...
inp = ("\nDo you want to save these band names? (y/n): ")
if inp.lower() == "y":
utfil = input("What do you want to name the file?: ")
self._saveBand(f"{utfil}.txt")
elif inp.lower() == "n":
self._deleteBand()
inp2 = input("Do you want to generate more band names? (y/n)?: ")
if inp2.lower() == "y":
self._generateBand()
elif inp2.lower() == "n":
done = True
self._writeGoodbyeMsg()
else:
print("Unknown command, please try again")
else:
self._writeGoodbyeMsg()
done = True
if __name__ == '__main__':
new = BandList()
new.menu()
You're missing an input call on your 2nd question for saving the band names. It should be:
inp = input("\nDo you want to save these band names? (y/n): ")
It does work. You just haven't given any values in self._BandList.
Its returning "BandList": null.

Start() is not defined

Hey I am trying to create a simple text based slot machine with the view to convert it into a graphical one latter.
I have started by it prompting a menu which works fine. However when the user enters the required 'p' to continue it won't call the next function because I haven't defined it yet.... I have?
from time import sleep
from random import shuffle
#Creates the class
class Machine():
#This is the constructor full of attributes
def __init__(self):
self.reel1 = ["Lemon", "Bell", "Cherry"]
self.reel2 = ["Lemon", "Bell", "Cherry"]
self.reel3 = ["Lemon", "Bell", "Cherry"]
firstSlide = self.reel1
secondSlide = self.reel2
thirdSlide = self.reel3
self.currentFunds = "10"
funds = self.currentFunds
f = open('score.txt', 'w')
f.write(funds)
#Dictates all the funds and checks if the user has enough money or needs to add money
def Funds(self):
if self.currentFunds == "0":
print("You are out of credits! :( \n")
Menu()
#Starts the spinning and randomizes the lists
def Start(self, firstSlide, secondSlide, thirdSlide):
shuffle(firstSlide, secondSlide, thirdSlide)
print(firstSlide[0], secondSlide[1], thirdSlide[3])
#Intro Menu to give player stats and options
def Menu(self):
play = ""
m = Machine()
print('*****************\n')
print(' WELCOME! \n')
print('*****************\n')
print('Current Credits: ', m.currentFunds)
if input("Press P to play \n") == "P" or "p":
machine = Start()
machine.Start()
machine = Machine()
while True:
machine.Menu()
Any ideas?
You have Start as a member function of the Machine class. You need to replace machine = Start() with self.Start().
It actually looks like this is the case with a number of the variables you seem to be trying to use. For example, I would expect that Start would rely on self.start, but it is relying on parameters (which you are not passing in).
As a general comment on this code, I'm wondering if you really need/want to have this be structured this way. You seem to be creating the object recursively and I think you might be better off restructuring a bit.

Nosetests - Guess The Number Game

I am trying to write a few tests for a random input number game but not too sure how to proceed on.
I am following the Python Game from http://inventwithpython.com/chapter4.html
Started the tests with a file test_guess.py
from unittest import TestCase
import pexpect as pe
import guess as g
class GuessTest(TestCase):
def setUp(self):
self.intro = 'I have chosen a number from 1-10'
self.request = 'Guess a number: '
self.responseHigh = "That's too high."
self.responseLow = "That's too low."
self.responseCorrect = "That's right!"
self.goodbye = 'Goodbye and thanks for playing!'
def test_main(self):
#cannot execute main now because it will
#require user input
from guess import main
def test_guessing_hi_low_4(self):
# Conversation assuming number is 4
child = pe.spawn('python guess.py')
child.expect(self.intro,timeout=5)
child.expect(self.request,timeout=5)
child.sendline('5')
child.expect(self.responseHigh,timeout=5)
child.sendline('3')
child.expect(self.responseLow,timeout=5)
child.sendline('4')
child.expect(self.responseCorrect,timeout=5)
child.expect(self.goodbye,timeout=5)
def test_guessing_low_hi_4(self):
# Conversation assuming number is 4
child = pe.spawn('python guess.py')
child.expect(self.intro,timeout=5)
child.expect(self.request,timeout=5)
child.sendline('3')
child.expect(self.responseLow,timeout=5)
child.sendline('5')
child.expect(self.responseHigh,timeout=5)
child.sendline('4')
child.expect(self.responseCorrect,timeout=5)
child.expect(self.goodbye,timeout=5)
and the guess.py file with
intro = 'I have chosen a number from 1-10'
request = 'Guess a number: '
responseHigh = "That's too high."
responseLow = "That's too low."
responseCorrect = "That's right!"
goodbye = 'Goodbye and thanks for playing!'
def main():
print(intro)
user_input = raw_input(request)
print(responseHigh)
print(request)
user_input = raw_input(request)
print(responseLow)
user_input = raw_input(request)
print(responseCorrect)
print(goodbye)
if __name__ == '__main__':
main()
Not sure How to proceed on with writing a few more tests with if statement to test if the value is low or high. I was told to try a command line switch like optparse to pass the number but not sure how to do that either.
Somewhat of a new person with Python, any guidance or assistance would be appreciated.
In order to do command line parsing in nosetests, you'll have to do something similar to this (at least that's what I had to do), i.e. create a plugin that will give you access to the command line parameter in nosetests. Once you had the plugin added which gave you the command line parameter, it would be pretty easy to create a test that would take advantage of that passed in parameter.
from test_args import case_options
class GuessTest(TestCase):
...
def test_guessing(self):
# Conversation assuming number is 4
if case_options.number < 4:
# Do something
elif case_option.number > 4:
# Do some other test
else:
# Do the final test
Does that make sense? I might be misunderstanding what you are trying to do so if I am, just let me know and hopefully we can clear it up.

Python custom modules - error with example code

I am reading the book "Python Programming for the Absolute Beginner (3rd edition)". I am in the chapter introducing custom modules and I believe this may be an error in the coding in the book, because I have checked it 5 or 6 times and matched it exactly.
First we have a custom module games.py
class Player(object):
""" A player for a game. """
def __init__(self, name, score = 0):
self.name = name
self.score = score
def __str__(self):
rep = self.name + ":\t" + str(self.score)
return rep
def ask_yes_no(question):
""" Ask a yes or no question. """
response = None
while response not in ("y", "n"):
response = input(question).lower()
return response
def ask_number(question, low, high):
""" Ask for a number within a range """
response = None
while response not in range (low, high):
response = int(input(question))
return response
if __name__ == "__main__":
print("You ran this module directly (and did not 'import' it).")
input("\n\nPress the enter key to exit.")
And now the SimpleGame.py
import games, random
print("Welcome to the world's simplest game!\n")
again = None
while again != "n":
players = []
num = games.ask_number(question = "How many players? (2 - 5): ", low = 2, high = 5)
for i in range(num):
name = input("Player name: ")
score = random.randrange(100) + 1
player = games.Player(name, score)
players.append(player)
print("\nHere are the game results:")
for player in players:
print(player)
again = games.ask_yes_no("\nDo you want to play again? (y/n): ")
input("\n\nPress the enter key to exit.")
So this is exactly how the code appears in the book. When I run the program I get the error IndentationError at for i in range(num):. I expected this would happen so I changed it and removed 1 tab or 4 spaces in front of each line from for i in range(num) to again = games.ask_yes_no("\nDo you want to play again? (y/n): ").
After this the output is "Welcome to the world's simplest game!" and that's it.
I was wondering if someone could let me know why this is happening?
Also, the import games module, is recognized in Eclipse after I added the path to PYTHONPATH.
I actually have this book myself. And yes, it is a typo. Here is how to fix it:
# SimpleGame.py
import games, random
print("Welcome to the world's simplest game!\n")
again = None
while again != "n":
players = []
num = games.ask_number(question = "How many players? (2 - 5): ", low = 2, high = 5)
for i in range(num):
name = input("Player name: ")
score = random.randrange(100) + 1
player = games.Player(name, score)
players.append(player)
print("\nHere are the game results:")
for player in players:
print(player)
again = games.ask_yes_no("\nDo you want to play again? (y/n): ")
input("\n\nPress the enter key to exit.")
All I did was indent num 4 spaces and lined it up with the first for-loop.
You have an infinite loop here:
again = None
while again != "n":
players = []
If this is exactly the way it's printed in the book, the book does have an error.
You've got these two lines:
num = games.ask_number(question = "How many players? (2 - 5): ", low = 2, high = 5)
for i in range(num):
The second one is more indented than the first. That's only legal if the first one is a block-introducer like a for or while or if. Since it's not, this is an IndentationError. And that's exactly what Python is telling you.
(It's possible that you've copied things wrong. It's also possible that you're mixing tabs and spaces, so it actually looks right in your editor, but it looks wrong to Python. But if neither of those is true, the book is wrong.)
So, you attempted to fix it by dedenting everything from that for loop on.
But when you do that, only one line is still left under the while loop:
while again != "n":
players = []
There's nothing that can possibly change again to "n", so this will just spin forever, doing nothing, and not moving on to the rest of the program.
So, what you probably want to do is to indent the num = … line to the same level as the for i… line, so both of them (and all the stuff after) ends up inside the while loop.

python: using a class to keep track of data used by another class

I'm learning Python via book and internet. I'm trying to keep score of a game in a separate class. In order to test my idea, i've constructed a simple example. It looks too complicated for some reason. Is there a simpler/better/more Pythonic way to do this?
My code is as follows:
import os
class FOO():
def __init__(self):
pass
def account(self, begin, change):
end = float(begin) + float(change)
return (change, end)
class GAME():
def __init_(self):
pass
def play(self, end, game_start):
os.system("clear")
self.foo = FOO()
print "What is the delta?"
change = raw_input('> ')
if game_start == 0:
print "What is the start?"
begin = raw_input('> ')
else:
begin = end
change, end = self.foo.account(begin, change)
print "change = %r" % change
print "end = %r" % end
print "Hit enter to continue."
raw_input('> ')
self.play_again(end, game_start)
def play_again(self, end, game_start):
print "Would you like to play again?"
a = raw_input('> ')
if a == 'yes':
game_start = 1
self.play(end, game_start)
else:
print "no"
exit(0)
game = GAME()
game.play(0, 0)
Here's how I would format your code:
import os
class Game(object):
def play(self, end, game_start=None):
os.system("clear")
change = input('What is the delta? ')
# Shorthand for begin = game_start if game_start else end
begin = game_start or end
end = float(begin + change)
print "change = {}".format(change)
print "end = {}".format(end)
self.play_again(end, game_start)
def play_again(self, end, game_start):
raw_input('Hit enter to continue.')
if raw_input('Would you like to play again? ').lower() in ['yes', 'y']:
self.play(end, game_start)
else:
exit(0)
if __name__ == '__main__':
game = Game()
game.play(0, 0)
And a few tips:
I wouldn't create a new class that contains only code to perform one specific task. If the class doesn't take arguments or doesn't simplify your code, don't create it. Your Game class is an exception, however, as you would probably add more code to it.
In Python, classes are written in CamelCase. Global constants are usually written in UPPERCASE.
raw_input() returns a string. input() returns the string evaluated into a Python object.
I asked the question a better way and got what I was looking for here:
python: how do I call a function without changing an argument?

Categories