Using user input to select a variable to modify? - python

I am trying to modify a variable based on user input. For example if the user wanted to change their strength variable they would type in "strength" and then that variable (tied to a player object so in this example player.strength) would be reassigned the new value.
I have attempted using dictionaries to hold the variable name as this is what I've used to call functions/methods as well but after browsing here a bit have realized this will not work due to it being immutable.
My current attempt looks like this:
skill_dict = {"Swords": self.swords}
answer = input("Which skill would you like to be proficient in?")
skill_dict[answer] += 10
print(skill_dict[answer])
print(self.swords)
The output however shows that this not work with the dictionary value being changed to 10 while the actual variable value remaining unchanged.
Is there a way to do this?

Use a dict to contain all the player's stats, like this:
class Player:
def __init__(self, swords, strength):
self.skills = {'swords': swords, 'strength': strength}
def become_proficient(self):
answer = input("Which skill would you like to be proficient in? ")
self.skills[answer] += 10
print(self.skills[answer])
Example run:
>>> player = Player(5, 6)
>>> player.become_proficient()
Which skill would you like to be proficient in? swords
15
>>> player.become_proficient()
Which skill would you like to be proficient in? strength
16
>>> player.skills
{'swords': 15, 'strength': 16}
On the other hand, if you need to use attributes, you can use setattr() and getattr(), but this allows the user access to any attributes, which is generally a bad idea.
answer = input("Which skill would you like to be proficient in? ")
setattr(self, answer) = getattr(self, answer) + 10

Related

How do you replace method/attribute with variable that stores it Python [duplicate]

This question already has answers here:
How to access (get or set) object attribute given string corresponding to name of that attribute
(3 answers)
Closed 6 years ago.
I'm programming the board game Monopoly in Python. Monopoly has three types of land that the player can buy: properties (like Boardwalk), railroads, and utilities. Properties have a variable purchase price and rents for 6 conditions (0-4 houses, or a hotel). Railroads and utilities have a fixed price and rents based on how many other railroads or utilities you own.
I have a Game() class that contains three dictionary attributes, all whose key is the land parcel's position on the board from 0-39:
.properties, whose values are a list containing the space's name, buy price, color group and rents (tuple);
.railroads, which consists only of the space name;
.utilities, also containing only the space name.
I did this because at certain points I want to iterate over the appropriate dictionary to see if the player owns other parcels of land in that dictionary; and also because the number of values differs.
Game() also has a tuple called space_types, where each value is a number representing a type of space (property, railroad, utility, luxury tax, GO, etc.). To find out what kind of space_type my player is sitting on:
space_type = space_types[boardposition]
I also have a Player() class with a method buy_property(), which contains a print statement that should say:
"You bought PropertyName for $400."
where PropertyName is the name of the space. But right now I have to use an if/elif/else block like so, which seems ugly:
space_type = Game(space_types[board_position])
if space_type is "property":
# pull PropertyName from Game.properties
elif space_type is "railroad":
# pull PropertyName from Game.railroads
elif space_type is "utility":
# pull PropertyName from Game.utilities
else:
# error, something weird has happened
What I'd like to do is something like this:
dictname = "dictionary to pull from" # based on space_type
PropertyName = Game.dictname # except .dictname would be "dictionary to pull from"
Is it possible in Python to pass the value of a variable as the name of an attribute to be referenced? I will also appreciate someone telling me I'm approaching this fundamentally wrong and suggesting a better way to go about it.
Use the getattr built-in:
PropertyName = getattr(Game, dictname)
http://docs.python.org/2/library/functions.html#getattr
You can use the getattr function:
property_name = getattr(Game, dictname)
How about a dictionary of dictionaries?
D= {"property": Game.properties, "railroad": Game.railroads, "utility": Game.utilities}
space_type = Game(space_types[board_position])
dictname = D[space_type]

Combine/ "concatenate" two variables, one being a user input

I am looking to combine a user inputted string as one variable (it is dynamic, of course) and use it to make another variable.
Example:
x = str(input("What do you want to buy? "))
(I want the new variable to be like x_cost - but of course you don't actually write that)
Let's say that the user inputs apple, so the new variable would be: apple_cost.
Is there a way to do this?
You should use a dict for this. I get that it can be hard to understand what a dict is if you've never seen it before, but if you want to learn, it's absolutely necessary to slow down and understand these things.
costs = {}
item_name = input("What do you want to buy? ")
costs[item_name] = input('Price? ')
So you can try and enter a few things
costs = {}
for i in range(4):
item_name = input("What do you want to buy? ")
costs[item_name] = input('Price? ')
How would you print out all these new variables if you don't know the names? With a dict it is easy:
for key, value in costs.items():
print(key, "costs", value)
A good way of solving this problem would be to use a dictionary. A dictionary "entry" holds two objects, a key and an item. You can think of the key as the magic word and the item as the genie--by calling the key (i.e. saying the magic words) you can reference an item (i.e. summoning the genie).
Let's go with the fruit example. If you want the user to input one of three fruits (lets say apple, pear, and cantaloupe) and have it correspond to a price. If we say the apple costs one dollar, the pear two, and the cantaloupe one hundred, then here is what our dictionary would look like:
#This is our dictionary. you can see the keyword (the fruit) goes first
#in order to summon the price, which we will store in another variable
fruit_dict = {'apple': 1.00, 'pear': 2.00, `cantaloupe`: 100.00}
Now that we have a working dictionary, let us write a program!
#First we define the dictionary
fruit_dict = {"apple": 1.00, "pear": 2.00, "cantaloupe": 100.00}
#Now we need to ask for user input
fruit = raw_input("What fruit would ya like?\n>>> ")
#Next, we look for the fruit in our dictionary. We will use a function
#called `values()`, which returns `True` or `False`.
if fruit in fruit_dict:
fruit_cost = fruit_dict[fruit] #accessing the value with dictname[key]
Easy as that! Now you can do what you want with the variable.
Best of luck, and happy coding!
You cannot create variable names dynamically.
What you need is a dictionary.
There are two ways to achieve what you want
mydict = {}
x = str(input("What do you want to buy? "))
mydict[str(x)+'_cost'] = 'some value'
Now using user input directly to populate a dictionary can be a risky business from security point of view, so you may want do:
import hashlib
mydict = {}
x = str(input("What do you want to buy? "))
hashkey = hashlib.md5(str(x)).hexdigest()
mydict[hashkey+'_cost'] = 'some value'
In python everything is object. A program starts in a main module main. Each module, class, etc has its own namespace (a dictionary) where variables are defined. So if you put a key in that namespace dict then it becomes variable. You can make use of that variable to point to any other object you want.
Just look at this code...
try this in python interactive mode....
import sys
sys.modules['__main__'].__dict__ # this is your main modules namespace.
So just push the name of variable into the dict as key and assign the value/object.
sys.modules['__main__'].__dict__['apple_cost']]
apple_cost = 10.5
You can access the namespace of any containers class/modules/etc... But I would not suggest you to do what I explained (this is just one way of doing it. little bit hacky/ugly) instead use descriptors or simple getattr method in a class (bit advanced but something useful to learn) to implement some thing like this.

Choose a Class object from a list thereof in a less clumsy way

I have a self defined class, say, Man, (class names etc arbitrary throughout) and a list of these objects men. My goal is to search this list for any object whose age attribute is a certain number, and perform an operation on this object. If no such entry exists, I'd like to make one.
Now, I know I can do this:
for year in range(70):
year_found = False
if year in [m.age for m in men]:
# do something
year_found = True
if not year_found:
men.append(Man(age=year))
but use of year_found to keep a place in the array seems clunky. Does anyone know of a better data structure than a list of classes, or a more pythonic way to approach this?
You can try using next():
man_search = next((man for man in men if man.age == year), None)
if man_search is None:
men.append(Man(age=year))
else:
# do something
You probably want to use sets for this.
ages = set(m.age for m in men)
all_ages = set(range(70))
for age in (all_ages - ages):
men.append(Man(age=age))

Changing attributes based on user input

Okay, I have a class which has 10 objects, these have the attributes self.planet, self.distance, self.distsquared, self.radius, self.diamater where distance/distsquared/radius/diamater are all integers. And I would like to make a function where the user searches for a planet name, and then changes one of the attributes.
For example, the user should input the name "Jupiter", which would then find the object, and the next row of the function would ask the user to add a certain sum to the attribute self.distance.
Currently the first class is set up as following:
class Planets():
def __init__(self, planetName, dist, radius, diameter):
self.planetName= planetName
self.dist= dist
self.radius= radius
self.diameter= diameter
This is then retrieved through a planetObjects=[Planets(*p) for p in planetList] This is the object-list I would like to turn into a dictionary so the user can search for planetName, and alter the distance
Some users suggested I use a dictionary for this, but I have no idea how to go about doing that. Currently my class turns a list of lists into a list of objects, these objects have these attributes that the user is supposed to be able to change by searching for the Planet name, and then changing one of its attributes.
The class is currently just a simple class which has a constructor and a __str__ function
Meaning, function starts, asks the user something like "Which planet would you like to alter?", the user inputs "Jupiter" and the program asks, "How has the distance to Jupiter changed?" where the user adds for example 450 or so.
The current code I have is a function which opens an infile and turns it into a list of lists. This list is then turned into objects. I turned it into objects to easily be able to sort it and add new values based on previous values. But at this point the user also has to be able to alter values by searching for a planet name and then changing one of the attributes - this is where I am lost and need help!
Is there any way to do this? Thanks in advance!
In psuedocode:
class Planet(object):
# Define your planet class here
# any attributes that you do NOT need the user to be able to edit should start with _
Planets = [Planet('Mercury'.....
#or better
PlanetDict = {'Mercury':Planet(....
which = PromptUserForPlanet()
p = PlanetDict.get(which) # or find and return it if you didn't use a dictionary
for att in dir(p):
if not att.startswith('_'):
input = raw_input('%s: (%s)' % (attr, repr(getattr(p,attr)))
if len(input) > 0:
setattr(p,att,input) # You may wish to do some type conversion first
Since p is a reference to the dictionary entry you will change the main object.
Given your class Planets, this may be solved like this. I'm assuming that planetList is structured like in this code. If it is not, you may have to alter the code a bit.
def increment_dist(planets):
name = raw_input('Please enter planet name')
try:
planets[name].dist += int(raw_input('Increment distance by (integer)'))
except KeyError:
print('No planet called {}'.format(name))
except ValueError:
print('That is not an integer')
planetList = [('Tellus', 1, 2, 4), ('Mars', 1, 3, 9)]
planet_dict = {name: Planets(name, dist, radius, diameter) for
name, dist, radius, diameter in planetList}
increment_dist(planet_dict)

question about managing values with multiple subvalues in python 3k

I have a question reguarding how I would perform the following task in python.
(I use python 3k)
what I have are several variables which can yield further variables on top of those
and each of those have even more variables
for example:
a generic name would be
item_version_type =
where each part (item, version, and type) refer to different variables(here there are 3 for each)
item = item_a, item_b, item_c
version = range(1,3)
itemtype = itemtype_a, itemtype_b, itemtype_c
simply listing each name and defining it is annoying:
itema_ver1_typea =
itemb_ver1_typea =
itemc_ver1_typea =
itema_ver2_typea =
etc.
etc.
etc.
especially when I have something where one variable is dependent on something else
for example:
if value == True:
version = ver + 1
and to top it off this whole example is rather simply compared to what I'm actually
working with.
one thing I am curious about is using multiple "." type of classes such as:
item.version.type
I know that this can be done
I just can't figure out how to get a class with more than one dot
either that or if anyone can point me to a better method
Thanks for help.
Grouping of data like this can be done in three ways in Python.
First way is tuples:
myvariable = ('Sammalamma', 1, 'Text')
The second way is a dictionary:
myvariable = {'value': 'Sammalamma', 'version': 1, 'type': 'Text'}
And the third way is a class:
class MyClass(object):
def __init__(self, value, version, type):
self.value = value
self.version = version
self.type = type
>>> myvariable = MyClass('Sammalamma', 1, 'Text')
>>> myvariable.value
'Sammalamma'
>>> myvariable.version
1
>>> myvariable.type
'Text'
Which one to use in each case is up to you, although in this case I would claim that the tuple doesn't seem to be the best choice, I would go for a dictionary or a class.
None of this is unique to Python 3, it works in any version of Python.
In addition to #Lennart Regebro's answer if items are immutable:
import collections
Item = collections.namedtuple('Item', 'value version type')
items = [Item(val, 'ver'+ver, t)
for val in 'abc' for ver in '12' for t in ['typea']]
print(items[0])
# -> Item(value='a', version='ver1', type='typea')
item = items[1]
print(item.value, item.type)
# -> b typea
sorry for posting this here instead of the comments but I have no clue how to work the site here.
for clarification
what I need is basically to have be able to get an output of said such as where
I could take a broad area (item) narrow it further (version) and even further (type as in type of item like lets say types are spoon, knife, fork)
or a better description is like arm.left.lower = lower left arm
where I could also have like leg.left.lower
so I could have arm.both.upper to get both left and right upper arms
where a value would be assigned to both.
what I need is to be able to do truth tests etc. and have it return the allowable values
such as
if leg == True
output is --> leg.both.lower, leg.both.upper, leg.left.upper leg.right.upper, etc., etc., etc.
if upper == True
output is --> leg.both.upper, leg.left.upper, etc., etc., etc.
hopefully that helps
Basically I get how to get something like item.version but how do I get something
like item.version.type
I need to have it to be more specific than just item.version
I need to be able to tell if item is this and version is that then type will be x
like
item.version.type
if version == 3:
item.version = spoon.3.bent
#which is different from
if version == 2:
item.version.type = spoon.2.bent

Categories