В чем разница между переменными класса и экземпляра?
в чем разница между переменными класса и экземпляра в Python?
class Complex:
a = 1
и
class Complex:
def __init__(self):
self.a = 1
используя вызов:x = Complex().a в обоих случаях присваивает x 1.
более глубокий ответ о __init__() и self будут оценены.
2 ответа:
когда вы пишете блок класса, вы создаете атрибуты класса (или переменные класса). Все имена, которые вы назначаете в блоке класса, включая методы, которые вы определяете с помощью
defстановятся атрибутами класса.после создания экземпляра класса все, что имеет ссылку на экземпляр, может создавать на нем атрибуты экземпляра. Внутри методов" текущий " экземпляр почти всегда привязан к имени
self, именно поэтому вы думаете о них как о " себе переменные параметры." Обычно в объектно-ориентированном дизайне код, прикрепленный к классу, должен иметь контроль над атрибутами экземпляров этого класса, поэтому почти все присвоение атрибутов экземпляра выполняется внутри методов, используя ссылку на экземпляр, полученный в . Мы могли бы создать миллион экземпляров, но нам нужно только сохранить одну строку в памяти, потому что они могут все найти ее.но вы должны быть немного осторожны. Взгляните на следующие операции:
sc1 = SomeClass() sc1.foo_list.append(1) sc1.bar_list.append(2) sc2 = SomeClass() sc2.foo_list.append(10) sc2.bar_list.append(20) print sc1.foo_list print sc1.bar_list print sc2.foo_list print sc2.bar_listкак вы думаете, что это печатает?
[1] [2, 20] [10] [2, 20]это потому, что каждый экземпляр имеет свою собственную копию
foo_list, поэтому они были добавлены по отдельности. Но все экземпляры имеют общий доступ к тому жеbar_list. Поэтому, когда мы сделалиsc1.bar_list.append(2)это повлиялоsc2, хотяsc2не существует! И точно так жеsc2.bar_list.append(20)повлияло наbar_listвосстановлено черезsc1. Это часто не то, что вы хотите.
дополнительные исследования. :)
чтобы действительно Грок Python, исходя из традиционных статически типизированных OO-языков, таких как Java и C#, вы должны научиться немного переосмыслить классы.
в Java класс на самом деле не вещь в своем собственном праве. Когда вы пишете класс, вы больше объявляете кучу вещей, которые все экземпляры этого класса имеют общее. На во время выполнения есть только экземпляры (и статические методы/переменные, но это действительно просто глобальные переменные и функции в пространстве имен, связанном с классом, ничего общего с OO на самом деле). Классы-это то, как вы записываете в своем исходном коде, как будут выглядеть экземпляры во время выполнения; они только "существуют" в вашем исходном коде, а не в запущенной программе.
в Python класс не является чем-то особенным. Это такой же объект, как и все остальное. Так что "атрибуты класса" на самом деле точно то же самое, что и "атрибуты экземпляра"; на самом деле есть только "атрибуты". Единственная причина для проведения различия заключается в том, что мы склонны использовать объекты, которые являются классами, отличными от объектов, которые не являются классами. Основной механизм все тот же. Вот почему я говорю, что было бы ошибкой думать об атрибутах класса как о статических переменных из других языков.
но то, что действительно делает классы Python отличными от классов Java-стиля, заключается в том, что как и любой другой объект каждый класс является экземпляром некоторого класса!
в Python большинство классов являются экземплярами встроенного класса под названием
type. Именно этот класс управляет общим поведением классов и делает все вещи OO так, как он это делает. Способ OO по умолчанию иметь экземпляры классов, которые имеют свои собственные атрибуты и имеют общие методы/атрибуты, определенные их классом, - это просто протокол в Python. Вы можете изменить большинство его аспектов, если вы хотите. Если вы когда-нибудь слышали об использовании метакласс, все это определение класса, который является экземпляром другого класса, чемtype.единственная действительно "особенная" вещь о классах (помимо всего встроенного оборудования, чтобы заставить их работать так, как они работают по умолчанию), это синтаксис блока класса, чтобы вам было проще создавать экземпляры
type. Это:class Foo(BaseFoo): def __init__(self, foo): self.foo = foo z = 28примерно эквивалентно следующее:
def __init__(self, foo): self.foo = foo classdict = {'__init__': __init__, 'z': 28 } Foo = type('Foo', (BaseFoo,) classdict)и он организует для всего содержания
classdictчтобы стать атрибутами объекта, который создается.тогда становится почти тривиальным видеть, что вы можете получить доступ к атрибуту класса с помощью
Class.attributeтак же легко, какi = Class(); i.attribute. ОбаiиClassявляются объектами, а объекты имеют атрибуты. Это также позволяет легко понять, как вы можете изменить класс после его создания; просто назначьте его атрибуты так же, как и вы с любым другим объектом!фактически, экземпляры не имеют особых особых отношений с классом, используемым для их создания. Способ Python знает, какой класс для поиска атрибутов, которые не найдены в экземпляре, является скрытым . Который вы можете прочитать, чтобы узнать, какой класс это экземпляр, как и с любым другим атрибутом:
c = some_instance.__class__. Теперь у вас есть переменнаяcпривязан к классу, хотя он, вероятно, не имеет того же имени, что и класс. Вы можно использовать это для доступа к атрибутам класса или даже вызвать его, чтобы создать больше экземпляров (даже если вы не знаете, что это за класс!).и вы даже можете назначить
i.__class__чтобы изменить, какой класс это экземпляр! Если вы сделаете это, ничего особенного не произойдет сразу. Это не разрушает землю. Все это означает, что когда вы ищете атрибуты, которые не существуют в экземпляре, Python будет смотреть на новое содержимое__class__. Так как это включает в себя большинство методов, и методы обычно ожидают, что экземпляр, на котором они работают, находится в определенных состояниях, это обычно приводит к ошибкам, если вы делаете это случайным образом, и это очень запутанно, но это можно сделать. Если вы очень осторожны, то вещь, которую вы храните в__class__даже не обязательно быть объектом класса; все, что Python будет делать с ним, это искать атрибуты при определенных обстоятельствах, поэтому все, что вам нужно, это объект, который имеет правильные атрибуты (некоторые предостережения в сторону, где Python действительно разборчив в вещах будучи классами или экземплярами определенного класса).пожалуй, пока хватит. Надеюсь (если вы даже читали это далеко), я не слишком смутил вас. Python аккуратен, когда вы узнаете, как это работает. :)
то, что вы называете переменной "экземпляр", на самом деле не является переменной экземпляра; это переменной класс. Смотрите ссылка на язык о классах.
в вашем примере
aпредставляется переменной экземпляра, поскольку она является неизменяемой. Это природа как класс переменную можно увидеть в том случае, когда вы назначаете изменяемый объект:>>> class Complex: >>> a = [] >>> >>> b = Complex() >>> c = Complex() >>> >>> # What do they look like? >>> b.a [] >>> c.a [] >>> >>> # Change b... >>> b.a.append('Hello') >>> b.a ['Hello'] >>> # What does c look like? >>> c.a ['Hello']если вы используете
self, тогда это будет истинная переменная экземпляра, и таким образом, каждый экземпляр будет иметь свой уникальныйa. Объект