1

I have a function that generates a random integer number between 1 and 6 and calls a function based on the number.

I have 6 other functions from another class which have names ending in numbers from 1 to 6.

I want to call the function corresponding to the random number I generate each time, because I want to reduce the repeating lines of if statements.

Is it possible to replace the ending number of a function with the random number?

Not sure if this will work though, I have imagined something like this:

sense.set_pixels(self.dice_(self.number)())

This is my current code:

def roll(self):
    sense = SenseHat()
    self.number = random.randint(1,6)

    if self.number == 1:
        sense.set_pixels(self.dice_1())
    elif self.number == 2:
        sense.set_pixels(self.dice_2())
    elif self.number == 3:
        sense.set_pixels(self.dice_3())
    elif self.number == 4:
        sense.set_pixels(self.dice_4())
    elif self.number == 5:
        sense.set_pixels(self.dice_5())
    elif self.number == 6:
        sense.set_pixels(self.dice_6())
0

4 Answers 4

2

If the method names follow a specific pattern as you say, you can use the getattr function to get the method based on a calculated name:

def roll(self):
    sense = SenseHat()
    self.number = random.randint(1,6)
    getattr(self, 'dice_%d' % self.number)()

But in this case it's more likely that you can combine your dice_# methods into one method that makes use of the dice number of the instance instead, resulting in more elegant code:

def roll(self):
    sense = SenseHat()
    self.number = random.randint(1,6)
    self.dice()

def dice(self):
    print(self.number)
    # so something with self.number
Sign up to request clarification or add additional context in comments.

5 Comments

In anything but toy projects using getattr will make it very difficult to find out where a function is used.
@mkrieger1 Yes, but the getattr approach makes sense sometimes, as can be seen in standard library modules such as cmd and unittest.TestCase.
Sure, but I guess it's used there because no better solution exists (unlike here).
@mkrieger1 It does exist. For example, cmd can instead be implemented by requiring the developer to use a class method to register the custom command methods into a class variable list. This is the approach taken by, for example, Django's custom filter registration.
Thanks for the comment everyone. (y) I will definitely have a look on getattr, sounds right.
2

You could also do this:

dice = [self.dice_1, self.dice_2, self.dice_3, self.dice_4, self.dice_5, self.dice_6]
random.choice(dice)()

random.choice given a sequence returns a random element. If the sequence is empty it raises IndexError.

Comments

1

You can use a tuple:

def roll(self):
    sense = SenseHat()
    self.number = random.randint(1,6)

    dice_functions = (None, self.dice_1, self.dice_2, self.dice_3,
                      self.dice_4, self.dice_5, self.dice_6)

    dice_functions[self.number]()

Or event more compact:

def roll(self):
    sense = SenseHat()

    (self.dice_1, self.dice_2, self.dice_3,
     self.dice_4, self.dice_5, self.dice_6)[random.randint(0, 5)]()

Comments

1

I think that this is not the right approach and I would prefer to encapsulate all the dice function to one which behaves according to it's input BUT if you insist on your solution, you can do the following:

sense = SenseHat()
sense.set_pixels(getattr(self,f"dice_{self.number}")())

where getattr allows you to get dynamically a member of a class by it's name.

2 Comments

That's the one I am looking for, thanks, it makes sense now~
If it helped you, please accept it as the answer in order to help other people struggling with the same issue :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.