automatically instantiating objects - python

players_list = [Ani, Paty, Felix, Alex]
class Player:
def __init__(self, name):
self.name = name
self.score = 0
self.vote = 0
self.player_hand = []
self.choice = ''
self.player_hand = []
def player_turn(self):
print(self.name, "'s turn")
def p_vote(self):
print(self.name, " voted")
I tried to iterate over the list, but it always gives me an error: NameError: name 'Ani' is not defined
for player in players_list:
player = Player(str(player))
But doing all the process manually work:
Ani = Player("Ani"), etc
Is there any way that i can automate this process?

First of all the thing you should know, the players_list that you have declared are not containing strings, they are being considered as variables which you have not defined anywhere, and therefore the NameError.
Now, if you want to correct this, and if you actually intend to store objects of Player in players_list, then you can do the following:
players_list = ["Ani", "Paty", "Felix", "Alex"]
class Player:
def __init__(self, name):
self.name = name
self.score = 0
self.vote = 0
self.player_hand = []
self.choice = ''
self.player_hand = []
def player_turn(self):
print(self.name, "'s turn")
def p_vote(self):
print(self.name, " voted")
for i in range(len(players_list)):
players_list[i]=Player(players_list[i])
This will store Player objects in the list you have declared just the thing that you expect to get.

You are having problems with the players not being defined. So players_list = [Ani, Paty, Felix, Alex] will throw an error because the objects Ani, Paty, Felizx, and Alex do not exist.
class Player:
def __init__(self, name):
self.name = name
self.score = 0
self.vote = 0
self.player_hand = []
self.choice = ''
self.player_hand = []
def player_turn(self):
print(self.name, "'s turn")
def p_vote(self):
print(self.name, " voted")
Now, we need to iterate through the list.
players_list = ['Ani', 'Paty', 'Felix', 'Alex']
players = [Player(player) for player in players_list]

Sounds like you're trying to dynamically create variables - write code that writes code.
You could try to use the exec built-in function.
players = ['Ani', 'Paty', 'Felix', 'Alex']
class Player:
def __init__(self, name):
self.name = name
def p_vote(self):
print(self.name + " voted.")
for player in players:
exec( "%s = Player( '%s' )" %(player, player) )
Ani.p_vote()
Although, general internet advice has two points to make:
Be cautious where you use exec.
The Pythonic way is to write out the variables, "explicit is better than implicit."

Related

Python Class. One def get for several attribute

I need help to be more clear how to make my code correctly. Now it's work but I still think the code logic not correct :)
I have one class with several attributes:
class Game:
def __init__(self, player1, player2, player3, player4, score_pair1, score_pair2):
self.player1 = player1
self.player2 = player2
self.player3 = player3
self.player4 = player4
self.score_pair1 = score_pair1
self.score_pair2 = score_pair2
self.Online_Players_Dict = []
self.Temp_Players_Dict = []
self.Temp_import_players = []
I have method inside of this class for work with all attributes:
def create_temp_players(self):
for i in ('player1', 'player2', 'player3', 'player4'):
temp = self.__getattribute__(i)
if not isinstance(temp, Player):
for ii in self.Temp_import_players:
if ii['name'] == self.__getattribute__(i):
self.__setattr__(i, Player(self.__getattribute__(i), ii['score'], ii['daily_score']))
b = self.__getattribute__(i)
a = dict(name=b.name, score=b.score, daily_score=b.daily_score)
self.Online_Players_Dict.append(a)
temp = self.__getattribute__(i)
if not isinstance(temp, Player):
self.__setattr__(i, Player(self.__getattribute__(i)))
b = self.__getattribute__(i)
a = dict(name=b.name, score=b.score, daily_score=b.daily_score)
self.Online_Players_Dict.append(a)
self.Temp_Players_Dict.append(a)
And everything work correct, but I think not right to use (getattribute) and (setattr) here. But I can't find other way to correct interaction attributes in the code.
Do you have any idea how to make it better?
PS: Class Player also has attribute:
class Player:
def __init__(self, name, score=500, daily_score=0):
self.name = name
self.score = score
self.daily_score = daily_score
I changed code like this
for player, i in zip(self.players, (0, 1, 2, 3)):
if not isinstance(self.players[i], Player):
for ii in self.Temp_import_players:
if ii['name'] == self.players[i]:
self.players[i] = Player(self.players[i], ii['score'], ii['daily_score'])
a = dict(name=self.players[i].name, score=self.players[i].score, daily_score=self.players[i].daily_score)
self.Online_Players_Dict.append(a)
if not isinstance(self.players[i], Player):
self.players[i] = Player(self.players[i])
a = dict(name=self.players[i].name, score=self.players[i].score, daily_score=self.players[i].daily_score)
self.Online_Players_Dict.append(a)
self.Temp_Players_Dict.append(a)
Later will refactoring all self.playerX to self.player[X]

Creating a class property using a function

I found this fantasy name generator here.
I am trying to adapt the code to suit my purpose. I want to create an NPC name automatically, using the function name_gen within the class NPC. With the NPC characteristics being:
class NPC:
def __init__(self, name, age, gender):
self.name = name_gen
self.age = 25
self.gender = M
The code from the name generator I need is the following:
from random import randrange
def line_appender(file_path, target):
file = open(file_path, "r")
splitfile = file.read().splitlines()
for line in splitfile:
target.append(line)
def name_selector(target_list):
selected = target_list[randrange(len(target_list))]
return selected
def name_builder(first_name_list_path, last_name_list_path):
first_name_list = []
last_name_list = []
line_appender(first_name_list_path, first_name_list)
line_appender(last_name_list_path, last_name_list)
first_name_selected = name_selector(first_name_list)
last_name_selected = name_selector(last_name_list)
name = first_name_selected+" "+last_name_selected
return name
Now the only thing I think I still need to do, is to generate the name from within the class NPC. I thought doing something like:
def name_gen
if gender == "M":
name = name_builder("first_name_male.txt", "last_name.txt")
elif gender == "F":
name = name_builder("first_name_female.txt", "last_name.txt")
But I don't understand how to make the name_gen function check the class NPC properties,
so that it generates the desired name.
Could someone perhaps help me out?
EDIT
Thank you for all the solutions! I am pretty new to Python; In order to test Samwises solution, I tried to run it as a separate script (in order to check whether I would get a name) with the code below. It does however not print anything. I'm putting this in an EDIT because I think it might be a trivial question. If it is worth posting a separate question, please let me know:
import random
running = True
npc_input_messsage = "npc = NPC(25, 'M')"
class NameChooser:
def __init__(self, file_path):
with open(file_path) as f:
self._names = f.read().splitlines()
def choice(self):
return random.choice(self._names)
first_choosers = {
"M": NameChooser("first_name_male.txt"),
"F": NameChooser("first_name_female.txt"),
}
last_chooser = NameChooser("last_name.txt")
def name_gen(gender):
return f"{first_choosers[gender].choice()} {last_chooser.choice()}"
class NPC:
def __init__(self, age, gender):
self.name = name_gen(gender)
self.age = age
self.gender = gender
while running:
npc = input(npc_input_messsage)
# I'm entering npc = NPC(25, "M")
print(npc)
Your name generator is a little over-complicated IMO. I'd suggest wrapping all the file reading and name selection stuff in a simple class so you can define it once and then instantiate it for each of your name lists. Putting the file reading part in __init__ means you only do it once per list instead of re-reading the file each time you need to pick a name.
import random
class NameChooser:
def __init__(self, file_path):
with open(file_path) as f:
self._names = f.read().splitlines()
def choice(self):
return random.choice(self._names)
Now you can define three NameChoosers and a name_gen function that picks among them:
first_choosers = {
"M": NameChooser("first_name_male.txt"),
"F": NameChooser("first_name_female.txt"),
}
last_chooser = NameChooser("last_name.txt")
def name_gen(gender):
return f"{first_choosers[gender].choice()} {last_chooser.choice()}"
And now you can define an NPC class that takes age and gender as arguments to the constructor, and picks a random name using name_gen():
class NPC:
def __init__(self, age, gender):
self.name = name_gen(gender)
self.age = age
self.gender = gender
def __str__(self):
return f"{self.name} ({self.age}/{self.gender})"
npc = NPC(25, "M")
print(npc) # prints "Bob Small (25/M)"
I think you're confused about OOP concepts.
First, let's edit your class:
class NPC:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
See, I have assigned parameter values to the attributes.
Now let's make changes to your function:
def name_gen(gender):
if gender == "M":
name = name_builder("first_name_male.txt", "last_name.txt")
elif gender == "F":
name = name_builder("first_name_female.txt", "last_name.txt")
return name
Here I have added a parameter to your function since you're using its value.
Now let's create an instance for your class.
npc = NPC("Vishwas", 25, "M") # Instance of the class
print(name_gen(npc.gender)) # Print generated name
A straightforward way to make happen automatically would be to simply call the name generator from with the NPC.__init__() method. In the code below it's been made a private method of the class by starting its name with an underscore character. Note that the call to it has to wait until all the instance attributes it references have been assigned value.
from random import randrange
class NPC:
def __init__(self, age, gender):
self.age = age
self.gender = gender
self.name = self._name_gen()
def _name_gen(self):
if self.gender == "M":
name = name_builder("first_name_male.txt", "last_name.txt")
elif self.gender == "F":
name = name_builder("first_name_female.txt", "last_name.txt")
return name
def line_appender(file_path, target):
file = open(file_path, "r")
splitfile = file.read().splitlines()
for line in splitfile:
target.append(line)
def name_selector(target_list):
selected = target_list[randrange(len(target_list))]
return selected
def name_builder(first_name_list_path, last_name_list_path):
first_name_list = []
last_name_list = []
line_appender(first_name_list_path, first_name_list)
line_appender(last_name_list_path, last_name_list)
first_name_selected = name_selector(first_name_list)
last_name_selected = name_selector(last_name_list)
name = first_name_selected+" "+last_name_selected
return name
if __name__ == '__main__':
npc1 = NPC(25, 'M')
print(f'{npc1.name!r}')
npc2 = NPC(21, 'F')
print(f'{npc2.name!r}')

How do I refer to an attribute of an object in a list, by using a string?

I'm writing a text adventure game and I'm trying to take an input for an object in a room, search for it in the objects list, then take that object and append it to the inventory (inv) list. I need to search for the object using the the input of its' name, which is one of the attributes.
class room():
def __init__(self, name):
self.objects = []
class player(room):
def __init__(self, name, inv):
self.name = name
self.inv = []
class things(room):
def __init__(self, name, is_weapon):
self.name = name
self.weapon = is_weapon
currentRoom = center
objLen = len(currentRoom.objects)
if currentRoom.objects:
for x in range(len(currentRoom.objects)):
print("Objects here: ",currentRoom.objects[x].name)
pickUp = input("Would you like to take any objects: ")
for a in range(0,objLen):
if pickUp.upper() == currentRoom.objects.name:
ind = currentRoom.objects.index(pickUp.upper().name)
Andy.inv.append(currentRoom.objects[ind])
currentRoom.objects.pop[ind]
else:
print("Object not found in this room!")
Got it.
for a in range(0,objLen):
if pickUp.upper() == currentRoom.objects[a].name:
Player.inv.append(currentRoom.objects[a])
currentRoom.objects.pop(a)

Competition registration program using classes

I have an assignment to create a code that would define 2 classes, a player and a team each of these having some parameters. Player is supposed to have a name, a number of skis, a number of sledges and a player index(number of games played by the player before).
I managed to define these attributes of the class but I'm having a hard time implementing the team class. Team is supposed to hold the name of the team and the number of players-the players cannot be just their names it must link to the class instance(player). I don't understand how to use the information provided in the player instance to implement team. Here's my code so far:
class Player:
def __init__(self, name, skis, index):
self.name = name
self.sledges = []
self.skis = []
self.index = index
pass
class Team:
def __init__(self, name, players):
self.name = name
self.players = [Player]
pass
def get_players_count()
def get_transport_capacity()
def get_average_index()
*Update
Thank you for your help, I have one more function to add, a function that would return the number of passengers a team could accommodate. I've tried something like this but I don't think the syntax is correct. The user inputs the number of places in each sledge so I need to iterate over the values in the list to get the number of places.
def get_transport_capacity(self):
skis = len(Player.skis)
for i in Player.sledges:
sledges += Player.sledges[i]
capacity = skis + sledges
return capacity
class Player:
def __init__(self, name, index):
self.name = name
self.sledges = []
self.skis = []
self.index = index
class Team:
def __init__(self, name, players):
self.name = name
self.players = players
def get_players_count(self):
return len(self.players)
def add_player(self, player):
self.players.append(player)
def get_average_index(self):
indexes = sum(list(map(lambda p: p.index, self.players)))
count = self.get_players_count()
return float(indexes) / count
Usage:
a = Player('AName', 2)
b = Player('BName', 11)
team = Team('TeamName', [a, b])
instead of
self.players = [Player]
why not:
self.players = []
And then have a method to add players to the team as in:
def add_player(self, player):
# ensure optionally that player is a PLayer instance
assert type(player) == Player
self.players += player

print object/instance name in python

I was wondering if there is a way to print the object name in python as a string. For example I want to be able to say ENEMY1 has 2 hp left or ENEMY2 has 4 hp left. Is there a way of doing that?\
class badguy:
def __init__(self):
self.hp = 4
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print (str(self.hp) + " hp left")
# creating objects
enemy1 = badguy()
enemy2 = badguy()
enemy1.attack()
enemy1.attack()
enemy1.still_alive()
enemy2.still_alive()
A much better design principle is not to rely on the specific name of the object as shown below:
class badguy(object):
def __init__(self):
pass
b = badguy()
print b
>>> <__main__.badguy object at 0x7f2089a74e50> # Not a great name huh? :D
This can lead to a whole wealth of issues with assignment binding, referencing, and most importantly does not allow you to name your objects per user or program choice.
Instead add an instance variable to your class called self._name (9.6 Classes - Private Variables) or self.name if you want to allow access outside the scope of the class (in this example, you can name it anything). Not only is this more Object-Oriented design, but now you can implement methods like __hash__ to be able to create a hash based on a name for example to use an object as a key (there are many more reasons why this design choice is better!).
class badguy(object):
def __init__(self, name=None):
self.hp = 4
self._name = name
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print ("{} has {} hp left.".format(self.name, self.hp))
Sample output:
b = badguy('Enemy 1')
print b.name
>>> Enemy 1
b.still_alive()
>>> Enemy 1 has 4 hp left.
b.name = 'Enemy One' # Changing our object's name.
b.still_alive()
>>> Enemy One has 4 hp left.
You'd have to first give them names. E.g.
class badguy:
def __init__(self, name):
self.hp = 4
self.name = name
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print (self.name + " has " + str(self.hp) + " hp left")
# creating objects
enemy1 = badguy('ENEMY1')
enemy2 = badguy('ENEMY2')
enemy1.attack()
enemy1.attack()
enemy1.still_alive()
enemy2.still_alive()
I have posted a complete solution here:
https://stackoverflow.com/a/49331683/7386061
It works without parameters. For example you could just do:
class badguy(RememberInstanceCreationInfo):
def __init__(self):
super().__init__()
self.hp = 4
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print (self.creation_name + " has " + str(self.hp) + " hp left")
enemy1 = badguy()
enemy2 = badguy()
enemy1.attack()
enemy1.attack()
enemy1.still_alive()
enemy2.still_alive()
out: hit
out: hit
out: enemy1 has 2 hp left
out: enemy2 has 4 hp left

Categories

Resources