разница между переменными внутри и снаружи __init __()

Есть ли разница между этими классами, кроме названия?

class WithClass ():
    def __init__(self):
        self.value = "Bob"
    def my_func(self):
        print(self.value)

class WithoutClass ():
    value = "Bob"

    def my_func(self):
        print(self.value)

Имеет ли какое-то значение, если я использую или не использую метод __init__ для объявления value переменной?

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

Ответ 1

Переменный набор вне __init__ принадлежит классу. Они разделяются всеми экземплярами.

Переменные, созданные внутри __init__ (и всех других функций метода) и предваряемые self., относятся к экземпляру объекта.

Ответ 2

Без себя

Создайте несколько объектов:

class foo(object):
    x = 'original class'

c1, c2 = foo(), foo()

Я могу изменить экземпляр c1, и это не повлияет на экземпляр c2:

c1.x = 'changed instance'
c2.x
>>> 'original class'

Но если я изменю класс foo, все экземпляры этого класса также будут изменены:

foo.x = 'changed class'
c2.x
>>> 'changed class'

Обратите внимание, как работает область обзора Python:

c1.x
>>> 'changed instance'

С Self

Изменение класса не влияет на экземпляры:

class foo(object):
    def __init__(self):
        self.x = 'original self'

c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'

Ответ 3

Я хотел бы добавить что-то к ответам, которые я прочитал в этой теме и этой теме (которая ссылается на эту).

Отказ от ответственности: эти замечания взяты из экспериментов, которые я провел

Переменные вне __init__:

Фактически это статические переменные класса, и поэтому они доступны для всех экземпляров класса.

Переменные внутри __init__:

Значение этих переменных экземпляра доступно только для имеющегося экземпляра (через ссылку на self)

Мой вклад:

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

Пояснение:

Раньше я думал, что оба способа объявить переменные был точно таким же (глупо меня), и это было отчасти потому, что я мог бы получить доступ как вид переменные через self ссылку. Именно сейчас, когда я столкнулся с проблемой, я исследовал эту тему и прояснил ее.

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

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

Пример:

#!/usr/bin/env python

class Foo:
    static_var = 'every instance has access'

    def __init__(self,name):
        self.instance_var = 'I am %s' % name

    def printAll(self):
        print 'self.instance_var = %s' % self.instance_var
        print 'self.static_var = %s' % self.static_var
        print 'Foo.static_var = %s' % Foo.static_var

f1 = Foo('f1')

f1.printAll()

f1.static_var = 'Shadowing static_var'

f1.printAll()

f2 = Foo('f2')

f2.printAll()

Foo.static_var = 'modified class'

f1.printAll()
f2.printAll()

Выход:

self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class

Надеюсь это кому-нибудь пригодится

Ответ 4

далее к ответу S.Lott, переменные класса передаются методу metaclass new и могут быть доступны через словарь при определении метакласса. Таким образом, переменные класса могут быть доступны даже до создания и создания классов.

например:

class meta(type):
    def __new__(cls,name,bases,dicto):
          # two chars missing in original of next line ...
          if dicto['class_var'] == 'A':
             print 'There'
class proxyclass(object):
      class_var = 'A'
      __metaclass__ = meta
      ...
      ...

Ответ 5

class User(object):
    email = 'none'
    firstname = 'none'
    lastname = 'none'

    def __init__(self, email=None, firstname=None, lastname=None):
        self.email = email
        self.firstname = firstname
        self.lastname = lastname

    @classmethod
    def print_var(cls, obj):
        print ("obj.email obj.firstname obj.lastname")
        print(obj.email, obj.firstname, obj.lastname)
        print("cls.email cls.firstname cls.lastname")
        print(cls.email, cls.firstname, cls.lastname)

u1 = User(email='[email protected]', firstname='first', lastname='last')
User.print_var(u1)

В приведенном выше коде пользовательский класс имеет 3 глобальных переменных, каждый со значением "none". u1 - это объект, созданный путем создания экземпляра этого класса. Метод print_var печатает значение переменных класса класса User и объектных переменных объекта u1. В приведенном ниже примере каждая переменная класса User.email, User.firstname и User.lastname имеет значение 'none', тогда как переменные объекта u1.email, u1.firstname и u1.lastname имеют значения '[email protected]', 'first' и 'last'.

obj.email obj.firstname obj.lastname
('[email protected]', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')

Ответ 6

Это очень легко понять, если вы отслеживаете словари классов и экземпляров.

class C:
   one = 42
   def __init__(self,val):
        self.two=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)

Результат будет таким:

{'two': 50}
{'__module__': '__main__', 'one': 42, '__init__': <function C.__init__ at 0x00000213069BF6A8>, '__dict__': <attribute '__dict__' of 'C' objects>, '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None}

Обратите внимание, что я установил здесь полные результаты, но важно то, что экземпляр ci dict будет просто {'two': 50}, а словарь классов будет содержать пару ключ-значение 'one': 42 внутри.

Это все, что вы должны знать об этих конкретных переменных.

Ответ 7

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

В этой метафоре план - это класс, а дом - экземпляр класса, создающего объект.

У домов есть общие атрибуты, такие как наличие крыши, гостиной и т.д. Именно в этом заключается метод init. Он создает стандартные атрибуты вашего дома.

Предположим, у вас есть:

'class house:'
'roof = True'
'def __init__(self, collor):'
'self.wallcolor = collor'

>> create little goldlock house:

>> goldlock = house() #() invoke class house, not function

>> goldlock.roof

>> True

all house have roof, now let define goldlock wall collor to white:

>> goldlock.wallcolor = 'white'
>>goldlock.wallcolor
>> 'white'