4

Say I have a class called Person, which will have only the person's name and gender.

The gender should be randomly selected from Male and Female. To do that, I import the random.randint() function. The random gender is determined according to the random int.

import random class Person: alias = random.randint(1, 3) if alias == 2: gender = 'Male' else: gender = 'Female' def __init__(self, name): self.name = name r = Person('rachel') s = Person('Stanky') print(r.gender) print(s.gender) 

However, the result I get for different person from this class all have the same gender. My understanding is the randint is fixed once been generated. My question is how to make it different for each class instance.

1
  • Code on the top level of the class is run only once (at import time). If you want to make the choice for every instance put the code in the __init__ method. Commented May 16, 2017 at 2:31

4 Answers 4

1

The reason your never getting a different gender is because the gender attribute is a class variable. Once Python creates your class object Person, the value of gender is never computed again. You need to make the gender variable an instance attribute. That means the gender will be computed on a per instance basis, instead of per class definition. eg:

import random class Person: def __init__(self, name): self.name = name alias= random.randint(1, 3) if alias == 2: self.gender = 'Male' else: self.gender = 'Female' r= Person('rachel') s= Person('Stanky') print(r.gender) print(s.gender) 

Which outputs

Female Male 

On a side note, I think a much better choice for your task would be to use random.choice() to select a random gender from a list of genders(male or female):

from random import choice class Person: genders = ('Male', 'Female', 'Female') def __init__(self, name): self.name = name self.gender = choice(Person.genders) rachel = Person('Rachel') stanky = Person('Stanky') print(rachel.gender) print(stanky.gender) 

Notice in my example above, Person.genders is a class variable. This is on purpose. Because we only need to create a list of genders once, we can make the list a class level variable.

Sign up to request clarification or add additional context in comments.

6 Comments

One other thing worth mentioning: this can be made a lot simpler using self.gender = random.choice(['Male', 'Female']).
@Mac I was just about to add an edit saying the exact same thing. Great minds think alive, eh? ;-)
you should definetly put the choice approach at the top. That's the right way to solve the problem!
@MSeifert While I most certainly agree, it seems to me that it would be better to answers the OP's original question first(see this meta discussion for more info). But your right, I'll add a comment saying the using the choice method is a better way.
You're right. It could also be intended that the female to male ratio is 2:1 (randint includes end points). In that case the choice approach needs to be choice(['male', 'female', 'female'])... Better to have randint at the top as long as the intention isn't clearly stated.
|
1

It seems you already guessed the reason correctly why the gender doesn't change. To solve this you could use a property for gender:

import random class Person(object): def __init__(self, name): self.name = name @property def gender(self): try: # If it has been defined for the instance, simply return the gender return self._gender except AttributeError: # If it's not defined yet, define it, and then return it self._gender = random.choice(['male', 'female']) return self._gender r = Person('rachel') s = Person('Stanky') print(r.gender) print(s.gender) 

2 Comments

is this different with : def __init__(self, name): self.name = name self.gender = random.choice(['Male','Female']) ? Cuz what I see here is if no gender variable is declared, then we declare a new gender variable. However, this class only have a variable, which is name. That means no gender local variable will be defined for sure, isn't it?
You're right, it is different. The _gender variable is undefined as long as you don't access the property gender. But as soon as you access the property it will be defined. So it's a different implementation but for most purposes it will behave exactly like the __init__ solutions.
0

You should put random gender generation under __init__, so that it would be randomly generated for each class instance.

import random class Person: def __init__(self, name): self.name = name alias= random.randint(1, 3) if alias == 2: self.gender = 'Male' else: self.gender = 'Female' r= Person('rachel') s= Person('Stanky') print(r.gender) print(s.gender) 

Three times of results:

$ python classRandom.py Male Female $ python classRandom.py Female Female $ python classRandom.py Female Male 

Comments

0

The gender variable is currently a class variable, that's why it stays the same for all the instance created. You will need to change them into a instance's attribute.

Side note: random.randint(1, 3) will either return 1, 2 or 3 not just 1 or 2. It is not the same as indexing, in which the ending is ignored. Right now, there's a higher chance to be a Female since it could be 1 or 3, so random.randint(1,2) makes more sense. I mentioned this just in case it was not done on purpose. You can also use random.choice, which will choose a random selection from a list.

import random class Person: def __init__(self, name): self.name = name self.gender= random.choice(["Male", "Female"]) # or random.choice(["Male", "Female", "Female"]) if you want a higher chance of being a female r= Person('rachel') s= Person('Stanky') print(r.gender) print(s.gender) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.