Python: функция печати для вызова случайно сгенерированного объекта класса

#python-3.x

#python-3.x

Вопрос:

Начинающий разработчик Python играет и пытается создать карточную игру. Работаю над собственной системой случайного выбора карточек.

 import random

# list to draw random card from from:
card_names = ["ace_h", "two_h", "three_h"]

class Cards(object):

    in_play = False
    def __init__(self, face, color, value):
        self.face = face
        self.color = color
        self.value = value      

ace_h = Cards("Ace", "Hearts", 14)
two_h = Cards("Two", "Hearts", 2)
three_h = Cards("Three", "Hearts", 3)

random_1 = random.choice(card_names)
print (random_1  ".face")
  

Если предположение ace_h было выбрано методом рандомизации, я надеялся, что печать в конце отобразит результат для печати ace_h.face (который будет Ace). Скорее, печать просто отображается ace_h.face в виде строки, а не фактического значения, связанного с ней.

Как я могу это изменить?

Обратите внимание, что простое использование print (ace_h.face) дает желаемый результат.

Комментарии:

1. Почему бы не сделать random_1 = random.choice([ace_h, two_h, three_h]) and then print(random_1.face) ?

2. Спасибо, это сработало, но я не уверен, почему? В чем разница между вашим кодом и моим, кроме того, что мой ссылается на заранее определенный список?

3. Добавление к @elethan: здесь даже не нужны именованные переменные. Просто создайте сингл list с картами в нем напрямую, потому что они логически представляют собой набор опций, а не набор независимых переменных.

4. @user2390206: код elethan создает список реальных объектов, а не строк, описывающих их, и ищет фактический атрибут, не объединяя имя атрибута.

5. @user2390206 как сказал @ShadowRanger, ваш код просто печатает строки, в то время как мой печатает возвращаемое значение face атрибута для любого Card выбранного. Вы могли бы заставить свой существующий код работать таким же образом, если бы eval() ваша строка, которая будет запускать строку, как если бы это был код Python: print (eval(random_1 ".face")) , но использование eval() часто не рекомендуется, поскольку существуют потенциальные риски для безопасности (хотя, поскольку вы не принимаете пользовательский ввод, в этом случае все должно быть в порядке, но случайный выбор изобъекты, а не имена, на мой взгляд, лучший вариант).

Ответ №1:

У вас фундаментальное непонимание того, как ссылаться на вещи в Python.

В Python у вас есть имена переменных:

 ace_h = 1
two_h = 2
three_h = 3
  

Вы можете вызывать эти значения по имени:

 print(ace_h)  # => 1
  

Вы можете поместить значения в другую коллекцию:

 cards = [ace_h, two_h, three_h]
print(cards)  # [1, 2, 3]
  

Вы можете распечатать определенный элемент:

 print(cards[0])
  

Вы можете распечатать случайный элемент:

 print(random.choice(cards))
  

Но все они относятся к значениям 1, 2, 3 .

На самом деле вы можете увидеть это, проверив id :

 print(id(ace_h))
print(id(cards[0]))
  

не имеет значения, используете ли вы ace_h cards[0] метод or для присвоения имени значению, оно одно и то же.

Это работает одинаково для всего в Python — все они являются объектами. Вы можете присвоить им имена любого типа, будь то имена переменных, помещая их в список или словарь — если id(thing) это одно и то же, вы говорите об одном и том же объекте.

 ace_h = Cards("Ace", "Hearts", 14)
two_h = Cards("Two", "Hearts", 2)
three_h = Cards("Three", "Hearts", 3)

cards = [ace_h, two_h, three_h]

print(cards)
for card in cards:
    print(id(card))

print(id(ace_h))
print(id(two_h))
print(id(three_h))

random_card = random.choice(cards)

print(id(random_card))

print(random_card.face)

print('random card is ace_h? {}'.format(random_card is ace_h))
print('random card is two_h? {}'.format(random_card is two_h))
print('random card is three_h? {}'.format(random_card is three_h))
  

Вам будет намного лучше, если вы просто будете думать о переменных как о метках, которые вы прикрепляете к значениям. В вашем случае вы создаете Card значения и наклеиваете ace_h на них ярлык. Вы также помещаете это Card в список, где вы можете ссылаться на него по имени cards[0] . Вы можете присвоить ему любое количество имен:

 another_name = ace_h
cool_name = ace_h
king_arthur = ace_h
sir_lancelot = ace_h
minister_of_silly_walks = ace_h
  

Теперь каждое из этих имен ссылается на одно и то же значение. Вы можете проверить это с id помощью , и вы можете увидеть, что все они имеют правильные свойства с print(dir(ace_h)) помощью и print(dir(minister_of_silly_walks))) . И вы можете проверить, что они являются одним и тем же объектом ace_h is minister_of_silly_walks .

Ответ №2:

Вы можете поместить все объекты в список, подобный этому:

 objectList = [ace_h, two_h, three_h]
random_1 = random.choice(objectList)
  

а затем выведите нужный атрибут:

print(random_1.face)

Ответ №3:

Есть несколько способов, которыми вы могли бы это сделать, которые сразу приходят на ум.

  1. Вы можете изменить свой MO и предварительно инициализировать список переменных:

     import random
    
    class Cards(object):
        in_play = False
        def __init__(self, face, color, value):
            self.face = face
            self.color = color
            self.value = value      
    
    ace_h = Cards("Ace", "Hearts", 14)
    two_h = Cards("Two", "Hearts", 2)
    three_h = Cards("Three", "Hearts", 3)
    
    # list to draw random card from from:
    cards = [ace_h, two_h, three_h]
    
    random_1 = random.choice(cards)
    print (random_1.face)
      

    Как вы можете видеть, я просто немного изменил порядок вашего кода, чтобы card_names он мог содержать ссылки на фактические Card объекты вместо их имен. Это, вероятно, самый простой способ сделать это.

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

     import random
    
    # list to draw random card from from:
    card_names = ["ace_h", "two_h", "three_h"]
    
    class Cards(object):
    
        in_play = False
        def __init__(self, face, color, value):
            self.face = face
            self.color = color
            self.value = value      
    
    ace_h = Cards("Ace", "Hearts", 14)
    two_h = Cards("Two", "Hearts", 2)
    three_h = Cards("Three", "Hearts", 3)
    
    random_1 = random.choice(card_names)
    print(globals()[random_1].face)
      

    Это больше похоже на ваш исходный код. globals() возвращает a dict , содержащий все имена, определенные на уровне модуля, включая функции, классы и переменные, все с ключом по имени. globals()[random_1] следовательно, это будет Cards объект (который, я думаю, вам следует переименовать Card , кстати).

    Внутри функции вы могли бы использовать locals() , чтобы получить аналогичное dict() для локального пространства имен внутри этой функции. Например, в Cards.__init__ , вы могли бы сделать что-то вроде locals()['face'] доступа к face параметру.