Random walk generator - looking for optimizations (Python)

I just started learning Python and this is the first code I wrote. It's a Random Walk generator. I think I got it to work pretty well but I'm also sure there are more effective and less clunky ways to do this. Could you give me some tips on what to change to make the code shorter/more optimized and just objectively more "pythonian" and better?

# Random Walk in two dimensions

import random

steps = "a"
maximal = "a"
minimal = "a"
Xstep = 0
Ystep = 0
StepSize = 0
PosNeg = 0

def new_line():
print(" ")

def invalid_enter_number():
print("Invalid input! Enter a number.")
new_line()

def invalid_enter_positive():
print("Invalid input! Enter a positive number.")
new_line()

new_line()
print("Random Walk in two dimensions")
new_line()

while type(steps) != int:
try:
steps = int(input("How many steps should be done? "))
while steps <= 0:
invalid_enter_positive()
steps = int(input("How many steps should be done? "))
except:
steps = ValueError
invalid_enter_number()
continue

while type(maximal) != int:
try:
maximal = int(input("How big is the biggest possible step? "))
while maximal <= 0:
invalid_enter_positive()
maximal = int(input("How big is the biggest possible step? "))
except:
maximal = ValueError
invalid_enter_number()
continue

if maximal != 1:
while type(minimal) != int:
try:
minimal = int(input("How big is the smallest possible step? "))
while minimal <= 0 or minimal >= maximal:
if minimal <= 0:
invalid_enter_positive()
minimal = int(input("How big is the smallest possible step? "))
else:
print("Number must be smaller than the biggest possible step!")
new_line()
minimal = int(input("How big is the smallest possible step? "))
except:
minimal = ValueError
invalid_enter_number()
continue
else:
minimal = 1

new_line()
print("Number of steps:", steps)

if maximal != 1:
print("Step size range:", minimal, "-", maximal)
else:
print("Step size: 1")

new_line()
print("Steps:")

while steps > 0:
StepSize = random.randint(minimal, maximal)
PosNeg = random.randint(0, 1)
chance = random.randint(0, 1)
if chance == 0 and PosNeg == 0:
Xstep += StepSize
elif chance == 0 and PosNeg == 1:
Xstep -= StepSize
elif chance == 1 and PosNeg == 0:
Ystep += StepSize
else:
Ystep -= StepSize
print("X:", Xstep, " Y:", Ystep)
steps -= 1



Here's one suggestion; other readers will probably offer more. Several times, you need to get an integer from the user. You could create a function to handle such details. The code below shows what the function might look light and how you would use it.

def int_from_user(prompt):
while True:
try:
n = int(input(prompt + ' '))
if n > 0:
return n
else:
raise ValueError()
except ValueError:
print('Invalid input! Enter a positive number.')

steps = int_from_user('How many steps should be done?')
print(steps)

• Awesome, thanks! Just one question: What does the raise do? If the input value isn't > 0 but also isn't a string so it doesn't make a ValueError then this raise forces a ValueError? – Vojta Mar 11 at 21:15
• @Vojta Yes, try to convert to int, which can fail. Then check for positive-int and, on failure, raise any ValueError merely to trigger the except-clause. It's just a technique so we don't have to duplicate the printing logic. A reasonable alternative (maybe even a better one!) is to define the error message in a variable before the while-loop; then, in the else-clause, just print it -- no need for the semi-mysterious empty ValueError. But there probably are situations where the technique (raising to trigger your own except-clause) is still useful to know about. – FMc Mar 11 at 21:40

If your concern is speed, I would have some suggestions:

You use the randint function 3x per step, while you only need it once: Just use random.choice() or numpy.randint() to directly select from a range of positive or negative step-sizes. This also gets rid of the excessive if statements. The slowest part is the print! Instead of printing every step, you should only print whenever needed, i.e. every 1000th step. Also instead of the while loop, python is actually faster using for loops.

Here is an example of a 3d random walk with 500 particles in a cube. It's 3d because it generates 3 coordinates per particle. You can change the dimensionality yourself.

N = 500 #simulating 500 particels at once
simulation_length = 10**6
centers = np.random.randint(-500,500,N*3) #cube of length 1000

for i in range(simulation_length):
centers += np.random.randint(-2,3,N*3)
centers = np.clip(centers,-500,500) #cant go outside box, alternatively, you may want to create symetric boundary conditions

#here you would calculate something?

if i%10000 == 0:
print(i)


This code is not the best possible either; you would need to have a look at the validity of the simulation itself (is a strict grid valid?), and @performace it would surely benefit from multi-processing.

• N = 500 centers = np.random.randint(-500, 500, N*3) This just gives me 1500 random numbers between -500 and 500 right? How is that a cube of length 1000? Sorry for a dumb question, I think the jump from 2D to 3D is confusing me... – Vojta Mar 14 at 13:42
• If you want to describe a single particle in 2d space, then you would need to generate 2 random numbers, or start at (0,0). Here we describe 500 particles in 3d, hence 1500 numbers. – KaPy3141 Mar 15 at 10:05