2012-06-26 2 views
6

Вот очень простой код, который я сделал, чтобы продемонстрировать проблему, с которой я сталкиваюсь. Что здесь происходит, так это то, что я создаю два разных экземпляра одного и того же класса, но изменение атрибута одного изменяет соответствующий атрибут другого экземпляра. Я не знаю, почему это так. Является ли это обычным явлением на Python или я сталкиваюсь с чем-то, что полностью перепутано?Несколько экземпляров одного класса, перезаписываемых одновременно? (Python)

class exampleClass(object): 

    attribute1=0 
    attribute2="string" 

x=exampleClass 
x.attribute1=20 
x.attribute2="Foo" 

y=exampleClass 
y.attribute1=60 
y.attribute2="Bar" 

print("X attributes: \n") 
print(x.attribute1) 
print(x.attribute2) 

print("Y attributes: \n") 
print(y.attribute1) 
print(y.attribute2) 

Вот что программа выглядит как выходит из моей консоли:

>>> 
X attributes: 

60 
Bar 
Y attributes: 

60 
Bar 
>>> 

Я думаю, что это следовало бы сказать:

X attributes: 

20 
Foo 
Y attributes: 

60 
Bar 

Что я делаю неправильно?

+0

Короткий ответ: Оба символа 'x' и' y' относятся к объекту класса 'exampleClass', а не к его экземплярам. Для создания экземпляров вам нужно вызвать объект класса, как в 'x = exampleClass()'. Впоследствии изменения атрибутов, которые вы делаете на 'x', будут влиять только на экземпляр, на который он ссылается. – martineau

ответ

8

Вы создаете атрибуты класса, если хотите атрибуты экземпляра. Используйте:

class exampleClass(object): 
    def __init__(self): 
     self.attribute1 = 0 
     self.attribute2 = "string" 

Кроме того, вы не создаете все экземпляры ExampleClass, вам это нужно:

x = exampleClass() 
y = exampleClass() 

Ваш код просто использует новые имена для класса и изменения его атрибутов.

+0

Это то, что похоже на мою консоль ... все еще испытывает ту же проблему. >>> класс exObj (объект): \t Защиту __init __ (Я): \t \t self.attribute1 = 0 \t \t self.attribute2 = "строка" \t \t >>> се = exObj > >> кт = exObj >>> ce.attribute1 = 44 >>> ct.attribute1 = 54 >>> ce.attribute1 >>> ct.attribute1 >>> – jecaklafa

+0

Извините за грубый форматирование. – jecaklafa

+0

@jecaklafa: вам нужно создать класс с помощью parens. –

3

Изменения сделаны так, что они яснее.

С кодом, который у вас есть, ваша проблема заключается в том, что вы делаете переменные x и y ссылаются на определение класса, а не на создание объектов, которые, как я считаю, теперь появились как проблема со всеми обсуждениями и сообщениями.

x = exampleClass 

Теперь означает, что x теперь указывает на определение класса. Это интересно, потому что, так как вы attribute1 как переменной ExampleClass, вы можете сделать это:

x.attribute1 = 3 

Теперь, если вы сделали следующее:

exampleClass.attribute1 

Вместо того, чтобы видеть 0, как вы изначально установить его, вы увидите 3!

Чтобы создавать объекты класса вам нужно сделать следующее:

x = exampleClass() 
y = exampleClass() 

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

x.attribute1 = 219 

Тогда вы обнаружите, что y.attribute1 не изменяется :) Использование имени класса и функции является общим в python как ссылка на определение. Поэтому будьте осторожны, если вы хотите создать экземпляр объекта, обязательно используйте круглые скобки, если вы хотите вызвать функцию, убедитесь, что вы тоже это сделали, иначе использование этого имени является ссылкой на определение.

Я предлагаю вам прочитать ответ Неда Батчелдера (и другие сейчас), так как вы должны делать такие переменные экземпляра таким образом: init функция, поскольку она намного чище и больше соответствует стандартам дизайна, которые больше всего подходят.

Но в целом, поскольку он наследует объект Object, тогда вы можете предположить, что его выполнение таким образом создаст экземпляры (с круглыми скобками) и т. Д., И поэтому вы можете изменить значения объекта, поскольку я считаю, что они должны быть переменными экземпляра даже без " Я».

4

Вы сделали атрибуты атрибутов класса. Это означает, что они привязаны к самому классу, а не к объектам класса.

Если вы хотите объектно-обзорного вы могли бы сделать что-то вроде:

class exampleClass(object): 
     def __init__(self): 
      self.attribute1=0 
      self.attribute2="string" 

x = exampleClass() 
y = exampleClass() 

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

+2

Еще нужно выполнить exampleClass(), а не exampleClass, иначе он будет указателем на чертежи этого класса. – richardhsu

+0

@richardhsu: он будет генерировать 'NameError', поскольку атрибуты еще не созданы. –

+1

Точно, но вы все еще можете сделать x = exampleClass, он действителен в Python и делает x ссылкой на exampleClass, поэтому да, ваш код правильный для дизайна класса, но для создания экземпляра объекта этого класса требуются скобки. – richardhsu

1

Классы тоже объекты, в Python. Следовательно, они могут быть назначены переменным и иметь свои собственные атрибуты, как и любой другой объект.

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

Имея это в виду, ваша программа не делает то, что вы думаете.

class exampleClass(object): 

    attribute1=0 
    attribute2="string" 

Здесь вы создали класс с именем exampleClass, с двумя атрибутами attribute1 и attribute2. Это не атрибуты экземпляра; это действительно распространенная ошибка людей, изучающих Python. Вам нужно обучить себя этому, потому что для простых примеров часто будет работать «как будто» они были атрибутами экземпляра. Имена привязки в блоке class создают атрибуты объекта класса. Единственный способ создания атрибутов экземпляра - получить ссылку на экземпляр после его существования и присвоить ему атрибуты; Python дает вам метод __init__ (который будет вызываться при создании экземпляра) в качестве места для этого.

Таким образом, основным правилом является: имена, определенные в блоке класса, являются атрибутами объекта класса, имена, назначенные как атрибуты self в __init__, являются атрибутами всех экземпляров этого класса.

Ваша путаница усугубляется еще один вопрос:

x=exampleClass 
x.attribute1=20 
x.attribute2="Foo" 

Поскольку классы объектов, как и все остальное в Python, это вполне разумный код Python, но он не делает то, что вы думаете. Вы фактически не создали экземпляр своего класса; для этого вам нужно вызвать класс, как в exampleClass(). Готическое имя exampleClass просто ссылается на объект класса, поэтому вы просто привязали это имя x к этому объекту и затем присвоили некоторые его атрибуты. Естественно, когда вы затем связываете y с объектом класса и присваиваете атрибуты этому объекту через y, объект, на который ссылается x, затрагивается (это тот же объект).

Смежные вопросы