Re-evaluating a function to get a new random value in python - 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.

Related

Python: Getting value from calling function

In Python, is there a simple way for an invoked function to get a value from the calling function/class ? I'm not sure if I'm phrasing that right, but I'm trying to do something like this:
class MainSection(object):
def function(self):
self.var = 47 # arbitrary variable
self.secondaryObject = secondClass() # Create object of second class
self.secondaryObject.secondFunction(3) # call function in that object
and
class secondClass(object):
def secondFunction(self, input)
output = input + self.var # calculate value based on function parameter AND variable from calling function
return output
#Access self.var from MainSection
This might be my lack of knowledge about Python, but I'm having a hard time finding a clear answer here. Is the best way to do that just passing the variable I want in as another second parameter to the second class?
These are in separate files, if that makes a difference.
Is the best way to do that just passing the variable I want in as another second parameter to the second class?
Yes, especially if there's only a transient relationship between the objects:
class secondClass(object):
def secondFunction(self, input, var_from_caller)
output = input + var_from_caller # calculate value based on function parameter AND variable from calling function
return output
You can even pass around the whole object if you like:
class secondClass(object):
def secondFunction(self, input, calling_object)
output = input + calling_object.var # calculate value based on function parameter AND variable from calling function
return output
If the relationship is more permanent, you could consider storing references to the related objects in instance variables:
class MainSection(object):
def function(self):
self.var = 47 # arbitrary variable
self.secondaryObject = secondClass(self) # Create object of second class
self.secondaryObject.secondFunction(3) # call function in that object
...
class secondClass(object):
def __init__(self, my_friend):
self.related_object = my_friend
def secondFunction(self, input)
output = input + self.related_object.var # calculate value based on function parameter AND variable from calling function
return output
#Access self.var from MainSection

Getting a random number each time in a script

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.

Using an argument from one Function in a separate function

I have a function:
def create_discs(noDiscs):
which when called creates a specified number of discs, so for example:
create_discs(5)
will create 5 discs.
I then want to use the integer inputted into the create_discs function in a separate function:
def hanoi(disc_int):
In other words I would like disc_int to equal 5 (or whatever number is inputted)
Can anyone help me?
If you want two functions to share state like this, they should be defined as methods of a class.
class Hanoi(object):
def __init__(self, num_discs):
self.num_discs = num_discs
def create_discs(self):
# use value of self.num_discs
def hanoi(self):
# use value of self.num_discs
h = Hanoi(5)
h.create_discs()
h.hanoi()
If you're passing 5 to create_discs, can you do:
num = 5
create_discs(num)
hanoi(num)
You could make a closure:
def create_discs(num):
# create some discs
def hanoi_closure():
# now num is available within this function
# do hanoi stuff
return
return hanoi_closure
hanoi = create_discs(5)
hanoi()
In this case, create_discs defined your hanoi function within itself so that num was within its scope (automatically, no need to store anything in a global or a class!) and it returned the inner function so you could call it later.
If create_discs was already supposed to return something, then you could just return a tuple with what it was returning plus the inner function:
def create_discs(num):
# ...
return what_it_normally_returns, hanoi_closure
create_discs_result, hanoi = create_discs(5)
hanoi()

FastQ programming error

So I'm trying to parse a FastQ sequence, but I'm a beginner to Python, and I'm a little confused as to why my code isn't working. This is what the program is supposed to carry out:
if I enter the FASTQ seqname line...
#EAS139:136:FC706VJ:2:2104:15343:197393
...then the program should output:
Instrument = EAS139
Run ID = 136
Flow Cell ID = FC706VJ
Flow Cell Lane = 2
Tile Number = 2104
X-coord = 15343
Y-coord = 197393
Here's my unfinished code thus far:
class fastq:
def __init__(self,str):
self.str = inStr.replace ('#',' ').split (':')
def lists (self,parameters):
self.parameters = ("Instrument","Run ID","Flow Cell ID","Flow Cell Lane","Tile Number","X-coordinates","y-coordinates")
def zip (self,myZip,zippedTuple):
self.Zip = zip(self.parameters,self.transform)
self.zippedTuple = tuple(myZip)
print (tuple(myZip))
def main():
seq = input('Enter FastQ sequence:')
new_fastq = fastq(str)
new_fastq.lists()
new_fastq.zip()
main()
The reason that your code isn't working is that it's more-or-less entirely wrong. To address your errors in the order we reach them when trying to run the program:
main:
new_fastq = fastq(str) does not pass the seq we just input, it passes the built-in string type;
__init__:
Calling the argument to fastq.__init__ str is a bad idea as it masks the very built-in we just tried to pass to it;
But whatever you call it, be consistent between the function definition and what is inside it - where do you think inStr is coming from?
lists:
Why is this separate to and not even called by __init__?
Why don't you pass any arguments?
What is the argument parameters even for?
zip:
Rather than define a method to print the object, it is more Pythonic to define fastq.__str__ that returns a string representation. Then you can print(str(new_fastq)). That being said;
Again, you mask a built-in. On this occasion, it's more of a problem because you actually try to use the built-in inside the method that masks it. Call it something else;
Again, you put unnecessary arguments in the definition, then don't bother to pass them anyway;
What is self.transform supposed to be? It is never mentioned anywhere else. Do you mean self.str (which, again, should be called something else, for reasons of masking a built-in and not actually being a string)?
myZip is one of the arguments you never passed, and I think you actually want self.Zip; but
Why would you create x = tuple(y) then on the next line print(tuple(y))? print(x)!
Addressing those points, plus some bonus PEP-008 tidying:
class FastQ:
def __init__(self, seq):
self.elements = seq.replace ('#',' ').split (':')
self.parameters = ("Instrument", "Run ID", "Flow Cell ID",
"Flow Cell Lane", "Tile Number",
"X-coordinates", "y-coordinates")
def __str__(self):
"""A rough idea to get you started."""
return "\n".join(map(str, zip(self.parameters, self.elements)))
def main():
seq = input('Enter FastQ sequence: ')
new_fastq = FastQ(seq)
print(str(new_fastq))
main()

Python OOP: functions from a dictionary do not affect class instance variables

I am new to Python but write programs for a hobby, so I have moderate knowledge of OOP and computer programming in general. I have started working on an simple animal simulator. In what might very well be a heathen move, I am trying to store all of the 'action functions' of the animal in a dictionary, so that each function is accessible by a string. For example, dict['SLEEP']() calls the sleep function.
I could find no examples of what I am trying to accomplish, and frankly am not sure how to intelligently describe my problem. See the bare-bones code below:
class Animal:
def __init__(self):
self.health = 100
self.actions = {} # dictionary of functions
self.initializeAnimal()
def initializeAnimal(self):
self.actions['SLEEP'] = self.initializeSleep() # add sleep function
def initializeSleep(self):
RESTORED_HEALTH = 20
# other constants
def sleep(self):
self.health += RESTORED_HEALTH
# utilize other constants
return sleep
Then, the animal handler would perform something along the following lines:
for animal in animalList:
animal.actions['SLEEP']()
I'd of course like the animal's health to increase by 20 when the sleep function is called. Instead, nothing happens. After some research and experimenting, I see that the self passed to the sleep() function apparently refers to initializeSleep() rather than the animal class.
I am at somewhat of a loss as to how I would change the health of the animal when calling functions in this manner. Do I have to somehow make use of super-class calls?
edit: clarify syntax
Python does some maneuvers so that functions defined in a class body actually behave as "methods" - and thus, get the "self" parameter added authomatically.
It is not hard to understand how that is done - and to emulate it for an explicit dictionary as you plan - but first, consider that you can retrieve a method name using a string, without resorting to storing them in dictionaries as you plan - you can simply do:
class Animal(object):
...
def sleep(self, ...):
...
my_cow = Animal()
function = getattr(my_cow, "sleep")
function ( )
# and of course, the two preceeding lines can be in a single expression:
getattr(a, "sleep")()
Now, let's see for the dicionary -
since you defien the actual "sleep" function as a nested function, it will "see" the "self" variable as it exists in the invocation of initializeSleep() - which means what you are doing should just work - as soons as you fix the call to initializeSleep() by prefixing it with the self. , as in:
def initializeAnimal(self):
self.actions['SLEEP'] = self.initializeSleep() # add sleep function
And remove the "self" parameter from the actual "sleep" function - it does not need it,
as it will "see" the nonlocal self variable in the enclosing scope:
def initializeSleep(self):
RESTORED_HEALTH = 20
# other constants
def sleep():
self.health = RESTORED_HEALTH
# utilize other constants
return sleep
(The other constants defined inside the initializeSLeep will also be visible inside sleep as nonlocal variables)
You don't need to put the self attribute into the sleep function.
Its perfectly valid to do the following:
class Animal:
def __init__(self):
self.health = 100
self.actions = {} # dictionary of functions
self.initializeAnimal()
def initializeAnimal(self):
self.actions['SLEEP'] = self.initializeSleep() # add sleep function
def initializeSleep(self):
RESTORED_HEALTH += 20
# other constants
def sleep():
self.health += RESTORED_HEALTH
# utilize other constants
return sleep
a = Animal()
print(a.health)
a.actions['SLEEP']()
print(a.health)
Output:
100
120
As stated, you forogt the += in self.health = RESTORED_HEALTH.
You also missed the self in self.initializeSleep()

Categories

Resources