问题
This is my first post and I'm quite new at programming, so I might not be able to convey my question appropriately, but I'll do my best!
tries_dict = {1:'first', 2:'second', 3:'third', 4:'fourth', ub_tries:'last'}
ub_tries = user input
tries = 1
input ('\nCome on make your ' + tries_dict.get(tries) + guess: ')
These 3 elements are part of a number guess game I created, and I included them in a while
loop where tries += 1
after each wrong answer.
As you can see, in my dictionary there are custom values for the first 4 answers and the last possible chance before the game is over, so here is what I tried to do:
I wanted to find a way to have the 'NEXT' value for every answer/key between 'fourth' and 'last'.
As in:
tries = 5
Come on make your next guess
tries = 6
Come on make your next guess
and so on
I did find a way with some complex looping, but being the curious type I wanted to know of more efficient/practical ways to accomplish this.
Here are some options i thought about but couldn't get to work:
- Using a range as a key
- Finding a way to generate a list with values between 4 and
ub_tries
and using that list as a key
So generally speaking: how can one create a way to have this general answer (next or whatever) for keys that aren't specified in a dictionary?
Any feedback would be greatly appreciated, feel free to ask for clarifications since I can tell myself my question is kind of messy.
I hope I get more crafty both at programming and asking related questions, so far my programming is nearly as messy as my summary skills, sigh!
回答1:
I'm not sure whether this is what you want, but dict.get may be the answer:
>>> ub_tries = 20
>>> tries_dict = {1:'first', 2:'second', 3:'third', 4:'fourth', ub_tries:'last'}
>>> tries_dict.get(1, 'next')
'first'
>>> tries_dict.get(4, 'next')
'fourth'
>>> tries_dict.get(5, 'next')
'next'
>>> tries_dict.get(20, 'next')
'last'
>>> tries_dict.get(21, 'next')
'next'
Of course you could wrap this up in a function, in various different ways. For example:
def name_try(try_number, ub_tries):
tries_dict = {1:'first', 2:'second', 3:'third', 4:'fourth', ub_tries:'last'}
return tries_dict.get(try_number, 'next')
At any rate, dict.get(key, default=None)
is like dict[key]
, except that if key
is not a member, instead of raising a KeyError
, it returns default
.
As for your suggestions:
using a range as a key??
Sure, you can do that (if you're in Python 2 instead of 3, use xrange
for range
), but how would it help?
d = { range(1, 5): '???',
range(5, ub_tries): 'next',
range(ub_tries, ub_tries + 1): 'last' }
That's perfectly legal—but d[6]
is going to raise a KeyError
, because 6
isn't the same thing as range(5, ub_tries)
.
If you want this to work, you could build a RangeDictionary
like this:
class RangeDictionary(dict):
def __getitem__(self, key):
for r in self.keys():
if key in r:
return super().__getitem__(r)
return super().__getitem__(key)
But that's well beyond "beginners' Python", even for this horribly inefficient, incomplete, and non-robust implementation, so I wouldn't suggest it.
finding a way to generate a list with values between 4 and ub_tries and using such list as a key
You mean like this?
>>> ub_tries = 8
>>> tries_dict = {1:'first', 2:'second', 3:'third', 4:'fourth', ub_tries:'last'}
>>> tries_dict.update({i: 'next' for i in range(5, ub_tries)})
>>> tries_dict
{1: 'first', 2: 'second', 3: 'third', 4: 'fourth', 5: 'next', 6: 'next', 7: 'next', 8: 'last'}
>>> tries_dict[6]
'next'
That works, but it's probably not as good a solution.
Finally, you could use defaultdict
, which lets you bake the default value into the dictionary, instead of passing it as part of each call:
>>> from collections import defaultdict
>>> tries_dict = defaultdict(lambda: 'next',
... {1:'first', 2:'second', 3:'third', 4:'fourth', ub_tries:'last'})
>>> tries_dict
defaultdict(<function <lambda> at 0x10272fef0>, {8: 'last', 1: 'first', 2: 'second', 3: 'third', 4: 'fourth'})
>>> tries_dict[5]
'next'
>>> tries_dict
defaultdict(<function <lambda> at 0x10272fef0>, {1: 'first', 2: 'second', 3: 'third', 4: 'fourth', 5: 'next', 8: 'last'})
However, note that this permanently creates each element the first time you ask for it—and you have to create a function that returns the default value. This makes it more useful for cases where you're going to be updating values, and just want a default as a starting point.
回答2:
Have I captured your intent for the game here?
max_tries = 8
tries_verbage = {
1: 'first',
2: 'second',
3: 'third',
4: 'fourth',
max_tries: 'last'
}
for i in xrange(1, max_tries + 1):
raw_input('Make your %s guess:' % tries_verbage.get(i, 'next'))
returns
Make your first guess:1
Make your second guess:2
Make your third guess:3
Make your fourth guess:4
Make your next guess:5
Make your next guess:6
Make your next guess:7
Make your last guess:8
回答3:
Why don't you just use a list?
MAX_TRIES = 10
tries_list = ["first", "second", "third", "fourth"]
for word in (tries_list[:MAX_TRIES-1] +
(["next"] * (MAX_TRIES - len(tries_list) - 1)) + ["last"]):
result = raw_input("Come on, make your {} guess:".format(word))
Note this code won't work as planned for MAX_TRIES = 0
, but I don't think that will be a problem.
回答4:
You can use a dictionary with range as a key:
def switch(x):
return { 1<x<4: 'several', 5<x<40: 'lots'}[1]
x = input("enter no. of monsters ")
print switch(x)
Hope this helps. :)
来源:https://stackoverflow.com/questions/13464143/use-a-range-as-a-dictionary-key-in-python-what-option-do-i-have