Python создает несколько экземпляров для одного объекта / класса

Я использую Python. Я читал немного об этом и, похоже, не могу обдумать его. То, что я хочу сделать, – это класс, называемый Зельями с различными предметами зелья. На данный момент есть одно зелье, простое HealthPotion. Я хочу, чтобы зелья были штабелированы в запасах и магазинах. Поэтому мне нужен экземпляр суммы зелья для инвентаря и экземпляра для каждого магазина, в котором есть зелья. Количество зелья было бы динамичным, для покупки / продажи и разграбления зелий. Если кто-то может дать основное объяснение или примеры, которые были бы замечательными.

Вот фрагмент того, что у меня есть:

class Potion(Item): def __init__(self, name, desc, val, amt, type, effect, bound): Item.__init__(self, name, desc, val, amt, type, effect, bound) self.name = name self.desc = desc self.val = val self.amt = amt self.type = 0 #Restorative self.effect = effect def use(self, you): #Use health potion you.hp_current += self.effect you.displayStats() #Format: Name, Description, Value, Amount, Type, Effect, Bound HealthPotion = Potion('Health Potion', 'Restores 10 hit points when consumed', 10, 0, 0, 10, 0) 

В идеале значение по умолчанию будет установлено равным 0, и я смогу объявить, сколько определенного магазина начнется с их запаса. Запасы и инвентарь устанавливаются в виде массива, который добавляется и удаляется в / из. Я думаю, что у меня есть логика для того, как это будет работать, у меня просто возникают проблемы с созданием сумм.

EDIT: Это часть того, что у меня есть в методе покупки, чтобы увидеть, что произойдет без использования экземпляров. Это довольно уродливо, и я заметил, что you.inventory.y.amt не будет работать. y – выбранный элемент из списка элементов, отображаемых в «магазине».

  x = selection - 1 #Item menu starts at 1. But arrays start at 0. So it takes user input and subtracts 1 to match the array. y = self.stock[x] if y.val <= you.coin: if y.amt == 0: you.inventory.append(y) you.inventory.y.amt += 1 else: you.inventory.y.amt += 1; you.coin -= y.val self.funds += y.val if self.stock.y.amt > 1: self.stock.y.amt -= 1 else: self.stock.y.amt -= 1 self.stock.pop(x) 

Я рассмотрел такие примеры:

 class foo: a = 1 i = foo() foo.a => 1 ia => 1 ia = "inst" foo.a => 1 ia => "inst" 

Мне интересно, не создаю ли я второй объект HealthPotion, но это звучит не так. Этот пример заставляет меня думать иначе. Может быть, я просто не понимаю, что происходит.

«Это создаст первый объект класса Employee»

 emp1 = Employee("Zara", 2000) 

«Это создало бы второй объект класса Employee»

 emp2 = Employee("Manni", 5000) 

Благодаря!

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

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

 class Person(object): def __init__(self, name): self.name = name def speak(self): print "Hi! My name is {self.name}.".format(self=self) 

Тогда экземпляр Person , ну, человек! Например:

 >>> basil = Person("Basil") >>> polly = Person("Polly") >>> >>> basil.speak() Hi! My name is Basil. >>> polly.speak() Hi! My name is Polly. >>> basil == polly False 

Таким образом, экземпляр – это не человек, а человек.

Разве у вас нет класса, чьи экземпляры сами являются классами, я слышал, вы спрашиваете? Да, конечно ты можешь! Он называется метаклассом и является очень мощным инструментом при определенных обстоятельствах. Однако, это не так.


Теперь, если вы посмотрите на свою ситуацию, вы видите разницу? HealthPotion – это не особое зелье (скажем, это у меня в кармане) – это своего рода зелье. И способ, которым мы выражаем это отношение, – это наследование классов: определить новый класс HealthPotion который наследуется от Potion . Затем вы можете иметь экземпляры этих (в моем кармане, в магазине, где угодно). Если вы хотите использовать зелье, вы используете конкретный экземпляр класса.

Код, который у вас там, использует очень запутывающие соглашения об именах, которые, как я думаю, вызывает вас путаницу — HealthPotion не является классом, это экземпляр, но имя CamelCase предполагает, что это класс в python.

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

 health_potion_1 = Potion("Health Potion", ...) health_potion_2 = Potion("Health Potion", ...) foobar_potion_1 = Potion("Foobar Potion", ...) #... 

Хотя это довольно плохой стиль, вы, вероятно, хотите, чтобы иметь возможность легко создавать здоровье и подобные зелья с теми же свойствами и зелья с различными эффектами

Для этого вы должны иметь

 class HealthPotion(Potion): def __init__(self, name="Health Potion", effect=10): super(HealthPotion, self).__init__(name, "Restores %d points of health" % (effect, ), effect, 0, 0) def use(self, you): you.hp_current+=self.effect 

Если вы хотите иметь несколько элементов в инвентаре, было бы проще просто иметь список (или набор или некоторую коллекцию) для вашего инвентаря и иметь несколько экземпляров в списке, например

 inventory = [HealthPotion(), HealthPotion()] 

Если вы хотите сделать стек, я все же считаю, что это функция инвентаря, а не элемент (помимо item.stackable ), поэтому у меня будет класс Inventory который обрабатывает коллекции объекта, будь то содержимое человека, сундук или магазин. простая реализация будет оберткой вокруг

 inventory = [(HealthPotion(), 2)] 

где любые идентичные элементы представлены как пара элемента и сумма

Кроме того, довольно легко преобразовать первый в последний, если у вас есть метод stacks_with :

 def stack_size(item, inv): "The number of items that will stack with item in inv" return len([i for i in inv if item.stacks_with(i)]) def stacked_inventory(inv): # if there is no stackable pair in the first i items # (ie the stack size for that item is 0 in inv[0:i]), # then the 'i'th item is a new stack, # with stack_size(inv[i], inv) items in it stacks = [ (inv[i], stack_size(inv[i])) for i in range(0,len(inv)) if not stack_size(inv[i], inv[0:i])] return stacks