Getting a random number each time in a script - python

I'm having trouble with the following bit of code:
from random import randint
class character():
__init__(self):
#init stuff here
def luck(self, Luck = randint(0, 3)):
return Luck
I have to call this method multiple times in my script, for multiple instances, to get a different number each time. The problem that I'm having is that whenever i call this method, no matter from what instance, I always to get the same result. For example, in the following code:
Foo = character()
Bar = character()
for foobar in range(3):
print(Foo.luck(), Bar.luck())
I'd get as my output:
1 1
1 1
1 1
By the way, in my code, I used randint(0, 3) as an argument for the luck() method because, in some specific situations, I'd like to assign values to it myself.
Back to the point, how can I get a different number each time?

This is a definition for the luck function. If the user specifies a number it will be returned. If instead no argument is given, Luck will be set from randint and that random value returned.
def luck(self, Luck = None):
if Luck is None:
Luck = randint(0,3)
return Luck

In python, the default expressions that set the default values for function arguments are only executed once. This means that once you define the luck method, whatever value randint() spit out the first time will stay for all invocations.
To get a new random number every time the method is called, you need to call it inside the body of the method:
class Character(object):
#staticmethod # required if you're not accepting `self`
def luck():
return randint(0, 3)
This will work as expected.

You can use None or something for a default argument, check if you got None and if you did - call randint() (if not just return what you did get).
If you use randint() in the function deceleration it will randomize it only once.

Related

using random to choose a function to run (50/50 chance needed)

code being run(apart from modules and functions)
random.choice(frontright(),frontleft())
error raised:
TypeError: Random.choice() takes 2 positional arguments but 3 were given
random.choice expects a sequence to choose from. That's not what you passed it.
Functions are objects, so you can put them in a sequence and then choose from that. But if you use parens you aren't using the function itself; you are actually calling all of the functions, then passing their return values to random.choice
This code might demonstrate the difference.
import random
def frontright():
print ('frontright was called')
return 'frontright result'
def frontleft():
print ('frontleft was called')
return 'frontleft result'
my_functions = (frontright, frontleft)
fn = random.choice(my_functions)
print('calling one function')
fn()
print()
print('collection of results')
my_choice = random.choice((frontright(), frontleft()))
print('chosen result was:', my_choice)
You're actually passing 2 when it expects 1 sequence, but internally it is calling an instance method, and at that point it's really 3 instead of 2, if you include self.
You might need to do this random.choice([frontright(), frontleft()])
https://www.w3schools.com/python/ref_random_choice.asp

How to write a function keeping return the maximum value while calling it repeatedly

I am learning Python and practice some problem on the book.
The problem asks me to write a function keeping the max value.
The function (foo) works like below:
if call foo(1) then print 1
call foo(5) print 5
call foo(3) print 5
call foo(10) print 10
call foo(8) print 10
I don't know what is the key point of this problem.
Another way (and much more correct in terms of encapsulation for the production code) to complete the task is to use classes instead of functions and global variables:
class MaxPositiveValue:
def __init__(self):
self.max_value = 0
def __call__(self, new_value):
'''
This magic method will emulate function call
:param new_value: new value to compare
:return: max value
'''
if new_value > self.max_value:
self.max_value = new_value
return self.max_value
foo = MaxPositiveValue()
print(foo(1)) # Will print "1"
print(foo(5)) # Will print "5"
print(foo(2)) # Will print "5"
print(foo(10)) # Will print "10"
print(foo(4.6)) # Will print "10"
print(foo(12.8)) # Will print "12.8"
And if you want to properly compare both positive and negative numbers, you may use next code:
class MaxValue:
def __init__(self):
self.max_value = None
def __call__(self, new_value):
'''
This magic method will emulate function call
:param new_value: new value to compare
:return: max value
'''
if (self.max_value is None) or (new_value > self.max_value):
self.max_value = new_value
return self.max_value
foo = MaxValue()
print(foo(-10.4)) # Will print "-10.4"
print(foo(-30.1)) # Will print "-10.4"
print(foo(1)) # Will print "1"
print(foo(5.6)) # Will print "5.6"
print(foo(2)) # Will print "5.6"
print(foo(10)) # Will print "10"
In mathematics, if a function is given certain input, it always returns the same value. That is what pure(sorry about being vague in wording) functions do. It means, your function will forget every information it used once it's done its job. In this case, your functions is not likely to remember previous max value and you will not be able to solve your problem, right? That's why other people suggested somewhat complex solutions like global variables or class. They do different jobs but they are all about keeping previous state(or what happened in the past). I would suggest one more method to achieve your goal. This may seem harder for now, but you will appreciate this later.
# written in Python3, not Python2
def function_factory():
prev_max = None
def print_max(num):
nonlocal prev_max
# prev_max is None or smaller than num
if not (prev_max and prev_max > num):
prev_max = num
print(prev_max)
return print_max
# make an instacne of print_max and bind that
# new function to the name, my_func
my_func = function_factory()
my_func(3) # >> 3
my_func(5) # >> 5
my_func(3) # >> 5
I used what's called a closure, and if you are interested you can study functional programming. It's a bit involved but makes your code succinct.
Your question is about global variables. It is saying to create a variable that is not dependent upon that instance of the function. Instance is used (in this case) to describe when that function is being used. Setting the variable as a global keeps it as that value irrespective of being in a different time the function has been called.
This code would be the solution:
glob_max = 0 #This variable needs to be set before the function
#(assuming you're just using natural numbers otherwise set a smaller number)
def foo(numbr):
if numbr > glob_max: #This find if it is the max or not
glob_max = numbr #Sets the variable
global glob_max #Makes the variable global to remember it for other functions
print(glob_max) #Print the number as required

Passing values through functions in Python

I am trying to pass a list of two integers created from one function so that I can manipulate them in succeeding functions.
def rollDie(number):
throw = []
for i in range(number):
roll = random.randint(1,6)
throw.append(roll)
return throw
So I have created another function game() that calls the rollDie() results:
def game(self,number):
if self.rollDie[0] != 1 or self.rollDie[1] != 1:
round_score = self.rollDie[0] + self.rollDie[2]
return round_score
But when I call the function game() it does not pull the two integers from rollDie():
print(game(2))
it returns error:
TypeError: game() missing 1 required positional argument: 'number'
I have researched here, here, here among other places inside stackoverflow. I am hoping someone can help. Many thanks for your patience.
The way you have defined the function, you have made it a non-static reference, i.e. it has to be called on an object.
You have to call game on whatever object you have defined. For example, instantiate your class as game1 and then call game1.game(2).
As #AAA pointed out, the way you are defining game() makes it look like a class function (you can read about classes here) but it does not look like you have defined a class anywhere. If you have defined a class elsewhere, then we need to see that code. If you didn't mean to create a class, then you need to take out the self references.
Also, I am not sure how self.rollDie[0] is supposed to work. Are you trying to reference a class list called rollDie? If so, I do not see that defined. If you are trying to call your def rollDie(number): function, then you need to do it like so: self.rollDie(). If you want to access the list indices, it would be best to make that equal to something: self.roll_list = self.rollDie(1) which you can then access by self.roll_list[0]
One thing to keep in mind is that lists are mutable objects, so if you are going to use your lists in multiple functions and you do not intend to create a class, thenit may be less confusing to initiate it on its own, outside of a function, as you can access it from any function.
I did a similar program:
Dice statistics 14.11.2015
from random import sample
result = [0, 0, 0, 0, 0, 0]
tosses = 10000
for i in range(tosses):
dice = sample(range(0, 6), 1)
new = str(dice).strip('[]')
result[int(new)] += 1
for i in range(0, 6):
print(i + 1, ' ====> ', result[i])

How to tell when a method is called for first time of many

I would like to be able to tell when a method has been called for the first time. I primarily need this for when I am printing out to a delimited file, and if it is the first iteration, I would like to print a header before the actual information. This is what I normally do:
def writeFile(number, count):
if count == 1:
print('number')
print(str(count))
else:
print(str(count))
count = 1
for i in range(10):
writeFile(i, count)
count += 1
This provides the following output:
number
1
2
3
4
5
6
7
8
9
10
Though this achieves the goal I am after, I am curious as to if there is a better/more efficient way of doing this. Is there some way to detect if a method has been called for the first time without having to pass an additional argument to it?
Thank you,
There are multiple ways to do this. Here are three.
First:
firstRun=True
def writeFile(number):
global firstRun
if firstRun:
print('number')
firstRun=False
print(str(number))
for i in range(10):
writeFile(i)
Second:
def writeFile(number):
print(str(number))
for i in range(10):
if not i:
print('number')
writeFile(i)
Third:
for i in range(10):
print(('' if i else 'number\n')+str(i))
I'm assuming this is just a test problem meant to indicate cases where function calls initialize or reset data. I prefer ones that hide the information from the calling function (such as 1). I am new to Python, so I may be using bad practices.
You could write the header to the file before you call the function. That would negate your need for the if statements. I'm a basic level programmer, but this seems logical to me. For example:
def writeFile(count):
print(str(count))
print('number')
for i in range(10):
writeFile(i)
This is a bit more deep respect to the other answers but I prefer it since it uses the OOP-ness of Python, the idea is to assign to the function itself the "called" variable: this can be done since everything in Python is an object (even a function inside its own scope).
The concept can be extended also to functions defined in other scopes - besides class scope - as well.
class SampleClass:
def sample(self, *args, **kwargs):
try:
if self.__class__.sample.called:
# do what you have to do with the method
print("normal execution")
except AttributeError:
# do what you have to do with the first call
print("first call")
self.__class__.sample.called = True
self.__class__.sample(self, *args, **kwargs)
Example:
>>>SampleClass().sample()
first call
normal execution
>>>SampleClass().sample()
normal execution

Re-evaluating a function to get a new random value in python

here is the code that I am having a problem with(simplified to make it clearer). It is for a text based game just to help learn things.
class Character(object):
def __init__(self):
self.level = 5
self.moveset = [None,None,None,None]
def movesetleveling(self):
if self.level > 4:
self.moveset[0] = Punch(self.level)
def punch(level):
damagedealt = random.randint(0,5)**level
return damagedealt
I would like to know how I can make self.moveset[0] = Punch() rather than being equal to the output of Punch() in this block of code. So that everytime i run it in a while loop it will re-evaluate the output of Punch() rather than evaluating Punch() once and assigning that to the 0th index of self.moveset[0].
You could assign a function to self.moveset[0] instead of its result (using functools.partial()):
from functools import partial
self.moveset[0] = partial(punch, self.level)
Then later, in your while loop, just call it:
while True:
new_punch_every_time = self.moveset[0]() #note: parentheses
self.moveset[0]() calls punch function with level parameter set to self.level (its value at the time of partial call).
It works because functions, methods are first class citizens in Python. You can pass them as parameters to other functions, return from functions, bind to a different name, append to a list, etc.

Categories

Resources