【问题标题】:Python, how come we can create class variables that were not defined in class creation?Python,为什么我们可以创建在类创建中没有定义的类变量?
【发布时间】:2020-06-27 14:20:24
【问题描述】:

假设我们有这个简单的 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'))

这应该返回 true。还有

print (MyClass.new_attribute)

应该返回 foo。

为什么我们可以创建一个未在该类的原始定义中定义的新类变量?

MyClass.new_attribute = 'foo'

与在原始定义中创建该类属性完全相同吗?

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

所以我们可以在运行时创建新的类属性?这如何不干扰创建类对象并将这些类变量作为类对象的实例变量的 init 构造函数?

【问题讨论】:

  • 没错。 class 对象是type 的一个实例,type 被称为MyClass元类

标签: python class instance-variables class-variables


【解决方案1】:

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 的 3 参数形式允许您传递一个 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__ 方法。

【讨论】:

  • 那么当你在init方法中做self.xyz = 1的时候,就好像你给实例化的对象添加了类属性一样?好吧,属性可以是变量或方法。
  • 类属性在 Python 中的含义与在其他语言中的含义不同。类属性是类的属性。实例属性是类实例的属性。由于一个类另一个类的实例,class_var 可以是type 实例的实例属性,也可以是MyClass 类的类属性。
【解决方案2】:

这是否意味着类变量可以被视为类对象本身的实例变量(因为所有类都是对象)?

是的。

为什么我们可以创建一个未在该类的原始定义中定义的新类变量?

因为 Python 是一种动态语言。一个类可以在运行时创建 - 事实上,它在您交互式运行 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'

这里没有魔法:任何东西都只能存在于它的定义点和它的破坏点之间。 Python 允许您随时为对象添加属性,但某些类(例如object)禁止这样做。

使用 MyClass 类的前一个 a 对象,您可以这样做:

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'

【讨论】:

    猜你喜欢
    • 2015-03-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2020-07-31
    • 2015-07-08
    • 2018-11-01
    • 1970-01-01
    相关资源
    最近更新 更多