разница между переменными внутри и снаружи __init __ () - PullRequest
166 голосов
/ 08 октября 2009

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

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?

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

Ответы [ 6 ]

200 голосов
/ 08 октября 2009

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

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

70 голосов
/ 23 октября 2014

Без себя

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

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'

С собой

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

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

c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'
11 голосов
/ 11 мая 2017

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

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

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

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

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

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

Мой вклад :

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

Объяснение

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

Проблема с доступом к статическим переменным класса через Ссылка self состоит в том, что она ссылается на переменную статического класса только в том случае, если нет переменной экземпляра с тем же именем, и, что еще хуже, пытается переопределить static переменная класса через ссылку 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

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

5 голосов
/ 06 марта 2013

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

например:

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
      ...
      ...
1 голос
/ 06 сентября 2017
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='abc@xyz', firstname='first', lastname='last')
User.print_var(u1)

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

obj.email obj.firstname obj.lastname
('abc@xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')
0 голосов
/ 01 июня 2019

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

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 внутри.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...