Можно ли использовать функцию input (), чтобы пользователь вводил переменную для объекта? - PullRequest
3 голосов
/ 14 июля 2020

Допустим, у меня есть класс и объект указанного класса:

class Rock:
    def __init__(self, name, group):
        self.name = name
        self.group = group

granite = Rock('Granite', 'Igneous')

Теперь предположим, что я хочу, чтобы пользователь ввел камень, поэтому у меня есть такая строка:

rock = input('Type the name of a rock: ')

В зависимости от того, какой камень вводит пользователь, я хочу, чтобы он распечатал строку, например: «Гранит принадлежит к вулканической группе». Я могу получить эту строку, набрав:

print(granite.name + ' belongs to the ' + granite.group + ' group.')

Однако это дает только иллюзию выбора, поскольку если пользователь набирает любой камень, кроме гранита, он будет озадачен, почему единственный вывод касается гранита . В идеале я хотел бы иметь возможность вводить что-то вроде:

print(rock.name + ' belongs to the ' + rock.group + ' group.')

Где, независимо от того, что вводит пользователь, если есть объект с переменной, равной этой строке, переменная rock теперь будет равна сказал каменный объект. Однако это не работает, потому что пользователь вводит строку, а не класс переменной. Я могу обойти это, добавив оператор if, например:

if rock == 'granite':
    rock = granite

Хотя, если я это сделаю, мне придется написать оператор if для КАЖДОГО рок-объекта, который у меня есть, и если у меня есть A МНОГО занятий роком, это было бы очень неэффективно. Итак, мой вопрос: есть ли способ, чтобы пользователь вводил фактическую переменную, а не просто строку? Если нет, мы будем благодарны за любой совет, как это сделать.

Ответы [ 5 ]

4 голосов
/ 14 июля 2020

Разработка предложения @Barmar. Используйте словарь:

rocks = {"granite": Rock('Granite', 'Igneous'), ....}
rock_name = input('Type the name of a rock: ')
rock = rocks[rock_name.lower()] # As long as it is a valid name

Возможно, вам даже не понадобится Rock.name.

2 голосов
/ 14 июля 2020

Поместите все камни в словарь, чтобы вы могли найти их по имени.

class Rock:

    all_rocks = {}

    def __init__(self, name, group):
        self.name = name
        self.group = group
        self.all_rocks[name] = self

granite = Rock('Granite', 'Igneous')
rock_name = input("Type the name of a rock")
rock = Rock.all_rocks.get(rock_name)
print(rock.group)
1 голос
/ 14 июля 2020

В другом варианте идеи создания индекса для горных пород это решение создает второй класс для индекса, который также индексируется по группам - возможно, это ваша следующая задача. Разница здесь в том, что, поскольку камни не индексируются переменной класса, вы потенциально можете создавать различные базы данных пород. Может, камни из разных регионов? Кто знает, но поскольку он пропускает глобальную переменную на уровне класса, он более гибкий.

from collections import defaultdict

class Rock:
    def __init__(self, name, group):
        self.name = name
        self.group = group

class RockIndex:

    def __init__(self):
        self.by_name = {}                   # one rock by name
        self.by_group = defaultdict(list)    # many rocks by type

    def make_rock(self, name, group):
        rock = Rock(name, group)
        # normalize name a group to upper for index
        self.by_name[name.upper()] = rock
        self.by_group[group.upper()].append(rock)
        return rock


rock_db = RockIndex()
rock_db.make_rock('Granite', 'Igneous')

rock = input('Type the name of a rock: ')
try:
    grp = rock_db.by_name[rock.upper()].group
    print(f"{rock} belongs to the {grp} group.")
except KeyError:
    print("I don't know that rock")
1 голос
/ 14 июля 2020

Для того, что вы предлагаете, требуется слишком много проверок ввода, и даже после этого я не думаю, что это правильный подход.

Продолжая ответ @DYZ (он написал, пока я писал), вам следует создайте словарь и попытайтесь сопоставить ввод со словарем с обработкой ввода.

rocksDict = {
  "rock1": Rock("Granite"),
  "rock2": Rock("Igneous"),
  "rock3": [Rock('Granite'),Rock('Granite')]
}
rockName = input('Type the name of a rock: ')

if key in rocksDict.keys(): 
    #debugging comments
    #print("Present, ", end =" ") 
    #print("value =", dict[key]) 

    type = rocksDict.get(rockName)
    print(type)
    
else: 
    print("Invalid Rock Name") 

Таким образом, вы можете разместить множество камней, просто продолжая заполнять RockDict.

1 голос
/ 14 июля 2020

Python имеет способ получить все локальные переменные в dict: locals().

Вы можете сделать что-то вроде rock = locals()[input("...")]

Конечно, вам нужно также обрабатывать KeyError s.

Но поскольку этот dict содержит все локальных переменных, как только у вас есть другая переменная, которая является не экземпляром Rock, пользователь может выбрать эту нерелевантную переменную. Вы также можете справиться с этим случаем с помощью isinstance(..., Rock)

Но все это своего рода «хакерство», и использование dict со всеми камнями, отображенными по имени, намного предпочтительнее и безопаснее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...