Local variable is not defined within the function, but it is defined outside and above it - python-3.7

I havent ran into this before, if i take the code out of triangle() and put it under the while loop everything works great. if I add triangle(input_argument) it then runs but never exits the while loop even if you type a string.
...
def main():
# Defining initial conditions.
input_argument = input("Enter a number or done: ")
triangle_list = []
def triangle():
input_argument = int(input_argument)
triangle_number = (input_argument*(input_argument+1)//2)
triangle_list.append(triangle_number)
print("Your number of", input_argument, "has a triangle number of",
str(triangle_number) + ".")
input_argument = input("Enter a new number or done: ")
# Test function for input between int or anything else.
def num_test():
try:
int(input_argument)
return True
except ValueError:
return False
while num_test() is True:
triangle()
num_test()
print(triangle_list)
main()
...
EDIT:
def num_test(input_argument):
try:
int(input_argument)
return True
except ValueError:
return False
def triangle(input_argument, triangle_list):
input_argument = int(input_argument)
triangle_number = (input_argument*(input_argument+1)//2)
triangle_list.append(triangle_number)
print("Your number of", input_argument, "has a triangle number of",
str(triangle_number) + ".")
input_argument = input("Enter a new number or done: ")
return
def main():
input_argument = input("Enter a number or done: ")
triangle_list = []
while num_test(input_argument) is True:
triangle(input_argument, triangle_list)
num_test(input_argument)
print(triangle_list)
main()

There's a bunch of elementary mistakes here, so let's run through a fixed version instead:
def get_input():
try:
value = input('Enter a number or done:')
return int(value)
except ValueError:
return False
def triangle(input, list):
triangle_number = (input*(input+1)//2)
list.append(triangle_number)
print(f"Your number of {input} has a triangle number of {str(triangle_number)}.")
def main():
triangle_list = []
while True:
value = get_input()
if value is False:
break
triangle(value, triangle_list)
print(triangle_list)
main()
Let's start with main, which is conceptually really simple:
we set up a list,
then we fill it,
then we print it.
How do we fill it? We loop our input aggregation:
get a value from the user. That'll either be a number, or False
if it's False, immediately stop looping.
if it's not, call our triangle function, with the current value, and the list of previous values
How do we get a value from the user? We use input(), and then try to return the int-cast version of that input. If that fails, we know the input was number a number, but otherwise we just return a number: exactly what we needed.
What does our triangle function do? It takes the current value and list of previous values, calculates some number, adds the current value to the list of previous values, prints, and exits.
Also not the Python 3 version of formatted strings: don't use string concatenation if you want a string with values-from-variables (or even values-from-other-code-calls). Use formatted strings, they're great.

Related

Filling in desired lines in Scala

I currently have a value of result that is a string which represents cycles in a graph
> scala result
String =
0:0->52->22;
5:5->70->77;
8:8->66->24;8->42->32;
. //
. // trimmed to get by point across
. //
71:71->40->45;
77:77->34->28;77->5->70;
84:84->22->29
However, I want to have the output have the numbers in between be included and up to a certain value included. The example code would have value = 90
0:0->52->22;
1:
2:
3:
4:
5:5->70->77;
6:
7:
8:8->66->24;8->42->32;
. //
. // trimmed
. //
83:
84:84->22->29;
85:
86:
87:
88:
89:
90:
If it helps or makes any difference, this value is changed to a list for later purposes, such like
list_result = result.split("\n").toList
List[String] = List(0:0->52->22;, 5:5->70->77;, 8:8->66->24;8->42->32;, 11:11->26->66;11->17->66;
My initial thought was to insert the missing numbers into the list and then sort it, but I had trouble with the sorting so I instead look here for a better method.
Turn your list_result into a Map with default values. Then walk through the desired number range, exchanging each for its Map value.
val map_result: Map[String,List[String]] =
list_result.groupBy("\\d+:".r.findFirstIn(_).getOrElse("bad"))
.withDefault(List(_))
val full_result: String =
(0 to 90).flatMap(n => map_result(s"$n:")).mkString("\n")
Here's a Scastie session to see it in action.
One option would be to use a Map as an intermediate data structure:
val l: List[String] = List("0:0->52->22;", "5:5->70->77;", "8:8->66->24;8->42->32;", "11:11->26->66;11->17->66;")
val byKey: List[Array[String]] = l.map(_.split(":"))
val stop = 90
val mapOfValues = (1 to stop).map(_->"").toMap
val output = byKey.foldLeft(mapOfValues)((acc, nxt) => acc + (nxt.head.toInt -> nxt.tail.head))
output.toList.sorted.map {case (key, value) => println(s"$key, $value")}
This will give you the output you are after. It breaks your input strings into pseudo key-value pairs, creates a map to hold the results, inserts the elements of byKey into the map, then returns a sorted list of the results.
Note: If you are using this in anything like production code you'd need to properly check that each Array in byKey does have two elements to prevent any nullPointerExceptions with the later calls to head and tail.head.
The provided solutions are fine, but I would like to suggest one that can process the data lazily and doesn't need to keep all data in memory at once.
It uses a nice function called unfold, which allows to "unfold" a collection from a starting state, up to a point where you deem the collection to be over (docs).
It's not perfectly polished but I hope it may help:
def readLines(s: String): Iterator[String] =
util.Using.resource(io.Source.fromString(s))(_.getLines)
def emptyLines(from: Int, until: Int): Iterator[(String)] =
Iterator.range(from, until).map(n => s"$n:")
def indexOf(line: String): Int =
Integer.parseInt(line.substring(0, line.indexOf(':')))
def withDefaults(from: Int, to: Int, it: Iterator[String]): Iterator[String] = {
Iterator.unfold((from, it)) { case (n, lines) =>
if (lines.hasNext) {
val next = lines.next()
val i = indexOf(next)
Some((emptyLines(n, i) ++ Iterator.single(next), (i + 1, lines)))
} else if (n < to) {
Some((emptyLines(n, to + 1), (to, lines)))
} else {
None
}
}.flatten
}
You can see this in action here on Scastie.
What unfold does is start from a state (in this case, the line number from and the iterator with the lines) and at every iteration:
if there are still elements in the iterator it gets the next item, identifies its index and returns:
as the next item an Iterator with empty lines up to the latest line number followed by the actual line
e.g. when 5 is reached the empty lines between 1 and 4 are emitted, terminated by the line starting with 5
as the next state, the index of the line after the last in the emitted item and the iterator itself (which, being stateful, is consumed by the repeated calls to unfold at each iteration)
e.g. after processing 5, the next state is 6 and the iterator
if there are no elements in the iterator anymore but the to index has not been reached, it emits another Iterator with the remaining items to be printed (in your example, those after 84)
if both conditions are false we don't need to emit anything anymore and we can close the "unfolding" collection, signalling this by returning a None instead of Some[(Item, State)]
This returns an Iterator[Iterator[String]] where every nested iterator is a range of values from one line to the next, with the default empty lines "sandwiched" in between. The call to flatten turns it into the desired result.
I used an Iterator to make sure that only the essential state is kept in memory at any time and only when it's actually used.

Try and Except statement - Automate The Boring Stuff {collatz() program}

I have been trying to complete a task from automate the boring stuff.
This is the task."Write a function named collatz() that has one parameter named number. If number is even, then collatz() should print number // 2 and return this value. If number is odd, then collatz() should print and return 3 * number + 1.
Then write a program that lets the user type in an integer and that keeps calling collatz() on that number until the function returns the value 1.Add try and except statements to the previous project to detect whether the user types in a noninteger string."
def collatz(num):
ev_odd = num % 2 #detecs whether number is odd or even
if ev_odd == 1:
num = num * 3 + 1
else:
num = num//2
print(num)
global number
number = num
#the program
print('enter an integer')
number = int(input())
collatz(number)
while number != 1:
collatz(number)
i made this code it is working fine.But I am unable to use try and except statement to this..Help me out. Other recommendation to improve this code are requested.
Regards

Python program continuing to run after encountering an error

I'm in the process of creating a program for my linear algebra class with vector and matrix classes, but I'm having trouble with stringifying my matrix class to print it. What's causing the problem is an if statement that adds a comma after an entry in the matrix if it's not the last entry in a row. What's curious about this is I've isolated the problem to the part of my program that assigns a variable to the index of the entry at hand, but when I added a line after that that printed that variable to try and figure out what was happening, running the program printed the variable AND THEN gave the error from the line before. Here's the code:
import copy
class vector:
def __init__(self, entries):
if type(entries) == list:
self.elements = []
self.dimensionality = len(entries)
for entry in entries:
self.elements.append(entry)
if type(entries) == vector:
self.elements = entries.elements
def __str__(self):
buff = "("
for e in self.elements:
buff += str(e)
if self.elements.index(e) < len(self.elements) - 1:
buff += ", "
buff += ")"
return buff
def __getitem__(self,index):
return self.elements[index]
def __len__(self):
return len(self.elements)
def __mul__(self, otherVector):
if self.dimensionality != otherVector.dimensionality:
raise RuntimeError("Cannot multiply vectors of different dimensions")
else:
product = 0
for e in self.elements:
product += e * otherVector.elements[self.elements.index(e)]
return product
def __eq__(self, otherVariable):
return size(self) == size(otherVariable)
def size(x):
return (x * x)**(1/2)
class matrix:
def __init__(self, entries):
for i in entries:
if len(entries[0]) != len(i):
raise RuntimeError("All rows of matrix must contain the same number of entries")
self.elements = []
for row in entries:
self.elements.append(vector(row))
def __str__(self):
buff = "("
for row in self.elements:
buff += str(row)
a = self.elements.index(row) #this is the line that prompts the error
b = len(self.elements) - 1
print (a) #but this line executes before the error cuts off the rest of the program
print(b)
print(a<b)
if a < b :
buff += ", "
buff += ")"
return buff
print(matrix([[1,2],[2,3]]))
and here's the error it gives me:
Traceback (most recent call last):
File "/Users/sebpole/Documents/vectors.py", line 127, in <module>
print(matrix([[1,2],[2,3]]))
File "/Users/sebpole/Documents/vectors.py", line 83, in __str__
a = self.elements.index(row)
File "/Users/sebpole/Documents/vectors.py", line 38, in __eq__
return size(self) == size(otherVariable)
NameError: name 'size' is not defined
I fixed that specific error by skipping a definition of the function 'size()' and just writing it in to the definition of vector equality. Since it was short that wasn't a problem and the program runs fine after that tweak, but I have the following two conceptual questions:
1) What's going on with the line after the error executing before the error did?
2)What was the problem exactly? Why did the program have a problem with calling a function I defined a little later? Why did taking the index of a row of a matrix call the definition of equality for that row (a vector)?
Use self.save to refer function defined in your class
The error is coming from the call to print in line 127, and the entire line is not being executed. Did you really see printed output in the console, other than the stack trace?
Conceptually, the line in question, print(matrix([[1,2],[2,3]])) does this:
the matrix instance is created successfully
print calls __str__ on that matrix instance
__str__ calls index on the list of vector instances
index needs to look through the list to find a matching value, and calls __eq__ on each member of the list to find the match
your original __eq__ code calls a missing function named size (which you noticed, and fixed)
I am surprised that this produced any output, other than the error.

Python use of class to create and manipulate a grid

Still trying to understand how to use class. I have now written the following:
`import random
class Grid():
def __init__(self, grid_row, grid_column):
self.__row = grid_row
self.__col = grid_column
self.__board=[]
def make_board(self):
for row in range(self.__row):
self.__board.append([])
for col in range(self.__col):
self.__board[row].append('0')
return self.__board
def change_tile(self):
choices = (0,1,2)
x = random.choice(choices)
y= random.choice(choices)
self.__board[x][y] = str(2)
def __repr__(self):
for row in self.__board:
print( " ".join(row))
g = Grid(3,3)
g.make_board()
g.change_tile()
print(g)
Firstly when I run this I get a grid printed followed by:
TypeError: __str__ returned non-string (type NoneType)
I don't understand why this happens. Second question. If I want to return the self.board, __str only returns the last row (0,0,0).With 'print' all three rows and columns are printed. Is there a way around the issue with 'return'?Is it an issue ( apart from the fact that I want to 'see' what I am doing)?
How would one call Grid(3,3) and get a grid with a randomly placed 2 without having to call each function separately as I have done in my example? Lastly why can I not use the integers 0 or 2, but have to convert everything to a string?. I hope that I have not exceeded the goodwill that exists on this forum by asking so many dumb questions!
The special methods __repr__ and __str__ are required to return a string. If there is no __str__ implementation given, the __repr__ will be used for the string conversion too.
Now in your case, __repr__ prints something instead of returning a string. It actually returns nothing, so None is implicitely returned. You have to change it to return a string. For example like this:
def __repr__(self):
return '\n'.join([' '.join(row) for row in self.__board])

Boolean expressions with strings and numbers

I have two variables in my pre block, and I need a third (a boolean) that identifies whether certain properties hold of those two:
str = "some string from a datasource";
qty = 15; //Also from a datasource
The third variable, valid, needs to be true when str is not empty and qty is greater than 0. How do I do that?
Oh! I just figured it out:
valid = not (str eq "") && (qty > 0);
I had some syntax errors in the rest of my ruleset; that's where the trouble was coming from.