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())
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Yitasha
  • 127
  • 1
  • 8

4 Answers4

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.

Rafael
  • 7,002
  • 5
  • 43
  • 52
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
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • In anything but toy projects using `getattr` will make it very difficult to find out where a function is used. – mkrieger1 Apr 01 '20 at 16:31
  • @mkrieger1 Yes, but the `getattr` approach makes sense sometimes, as can be seen in standard library modules such as `cmd` and `unittest.TestCase`. – blhsing Apr 01 '20 at 16:35
  • Sure, but I guess it's used there because no better solution *exists* (unlike here). – mkrieger1 Apr 01 '20 at 16:37
  • @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. – blhsing Apr 01 '20 at 16:40
  • 1
    Thanks for the comment everyone. (y) I will definitely have a look on getattr, sounds right. – Yitasha Apr 01 '20 at 16:50
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)]()
Omer Tuchfeld
  • 2,886
  • 1
  • 17
  • 24
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.

Gabio
  • 9,126
  • 3
  • 12
  • 32