Python, почему мы можем создавать переменные класса, которые не были определены при создании класса? - PullRequest
1 голос
/ 16 марта 2020

Допустим, у нас есть простой Python код

class MyClass(object):
    class_var = 1

    def __init__(self, i_var):
        self.i_var = i_var

Поправьте меня, если я что-то не так понял:

Class_Var - это переменная класса, которая одинакова для всех экземпляров объекта MyClass. I_Var - это переменная экземпляра, которая существует только в экземплярах объекта MyClass

foo = MyClass(2)
bar = MyClass(3)

foo.class_var, foo.i_var
## 1, 2
bar.class_var, bar.i_var
## 1, 3

Переменные класса также являются свойствами самого класса.

MyClass.class_var ##
## 1

MyClass.I_var в случае ошибки, исправьте ?

Означает ли это, что переменные класса могут рассматриваться как переменные экземпляра самого объекта класса (поскольку все классы являются объектами)?

MyClass.new_attribute = 'foo'
print(hasattr(ObjectCreator, 'new_attribute'))

Это должно вернуть правда. И

print (MyClass.new_attribute)

должен возвращать foo.

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

Является ли

MyClass.new_attribute = 'foo'

тем же, что и создание этого атрибута класса в исходном определении?

class MyClass(object):
    class_var = 1
    new_attribute = 'foo'

То есть мы можем создавать новые атрибуты класса во время выполнения? Как это не мешает конструктору init, который создает объект класса и имеет эти переменные класса в качестве переменных экземпляра объекта класса?

Ответы [ 2 ]

2 голосов
/ 16 марта 2020

A class объект - это просто экземпляр еще одного типа, обычно type (хотя вы можете изменить его с помощью параметра metaclass на оператор class).

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

Атрибуты класса и атрибуты экземпляра полностью разделены; первые хранятся в объекте class, последние - в экземплярах класса.

В __init__ нет ничего особенного; это просто еще один метод, который, помимо прочего, может присоединять новые атрибуты к объекту. Особенность заключается в том, что __init__ автоматически вызывается , когда вы создаете новый экземпляр класса путем вызова класса. foo = MyClass(2) эквивалентно

foo = MyClass.__new__(MyClass, 2)
foo.__init__(2)

Оператор класса

class MyClass(object):
    class_var = 1

    def __init__(self, i_var):
        self.i_var = i_var

примерно эквивалентен

def my_class_init(self, i_var):
    self.i_var = i_var


MyClass = type('MyClass', (object,), {'class_var': 1, '__init__: my_class_init})

Форма с тремя аргументами type позволяет вы передаете dict, который создает атрибуты класса при первом создании класса, но вы всегда можете также присвоить атрибуты и после факта:

MyClass = type('MyClass', (object,), {})
MyClass.class_var = 1
MyClass.__init__ = my_class_init

Просто чтобы поразить вас немного немного больше, вызов type может быть как

MyClass = type.__new__(type, 'MyClass', (object,), {...})
MyClass.__init__('MyClass', (object,), {...})

, хотя, если вы не определите пользовательский метакласс (подклассом type), вам никогда не придется думать о type сам имеет методы __new__ и __init__.

0 голосов
/ 16 марта 2020

Означает ли это, что переменные класса могут рассматриваться как переменные экземпляра самого объекта класса (поскольку все классы являются объектами)?

Да.

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

Поскольку Python является динамическим c языком. Класс может быть создан во время выполнения - фактически он создается во время выполнения при интерактивном запуске Python.

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

Да, если только метакласс (класс класса) запретил его.

Как это не мешает конструктору init, который создает объект класса, и имеет эти переменные класса в качестве переменных экземпляра объекта класса?

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

>>> class MyClass(object):
    class_var = 1

    def __init__(self, i_var):
        self.i_var = i_var
        self.j_var = self.class_var + 1


>>> a = MyClass(2)
>>> del MyClass.class_var
>>> b = MyClass(3)
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    b = MyClass(3)
  File "<pyshell#36>", line 6, in __init__
    self.j_var = self.class_var + 1
AttributeError: 'MyClass' object has no attribute 'class_var'

Здесь нет магов c: все может существовать только между точкой определения и точкой разрушения. Python позволяет добавлять атрибуты к объектам в любое время, за исключением того, что некоторые классы (например, object) запрещают это.

С предыдущим a объектом класса MyClass вы можете сделать :

a.z_var = 12

с этой точки, z_var будет атрибутом a, но другие объекты того же класса не будут иметь его.

Просто object запрещает:

>>> o = object()
>>> o.x=1
Traceback (most recent call last):
  File "<pyshell#41>", line 1, in <module>
    o.x=1
AttributeError: 'object' object has no attribute 'x'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...