好吧,第一件事。
Python 中没有“变量声明”或“变量初始化”之类的东西。
简单来说就是我们所说的“分配”,但可能应该只称为“命名”。
赋值的意思是“左边的这个名字现在指的是评估右边的结果,不管它以前指的是什么(如果有的话)”。
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
因此,Python 的名称(可以说是比“变量”更好的术语)没有关联的类型。价值观确实如此。无论其类型如何,您都可以将相同的名称重新应用于任何事物,但事物仍然具有取决于其类型的行为。名称只是一种引用值(对象)的方式。这回答了您的第二个问题:您不会创建变量来保存自定义类型。您不会创建变量来保存任何特定类型。您根本不会“创建”变量。你给对象命名。
第二点:Python 在类方面遵循一个非常简单的规则,这实际上比 Java、C++ 和 C# 等语言更加一致:块内声明的所有内容都是class
类的一部分。因此,这里编写的函数 ( def
) 是方法,即类对象的一部分(不是按实例存储),就像在 Java、C++ 和 C# 中一样;但这里的其他名称也是类的一部分。同样,名称只是名称,它们没有关联的类型,并且函数在 Python中也是对象。因此:
class Example:
data = 42
def method(self): pass
在 Python 中,类也是对象。
所以现在我们创建了一个名为的对象Example
,它代表了所有事物的类Example
s。该对象有两个用户提供的属性(在 C++ 中,“成员”;在 C# 中,“字段或属性或方法”;在 Java 中,“字段或方法”)。其中之一是命名data
的,它存储整数值42
。另一个名为method
,它存储一个函数对象。(还有几个 Python 自动添加的属性。)
但是,这些属性仍然不是对象的一部分。从根本上说,一个对象只是一堆更多的名称(属性名称),直到你开始处理那些不能再分割的东西。因此,值可以在一个类的不同实例之间共享,甚至在不同类的对象之间共享,如果您有意设置的话。
让我们创建一个实例:
x = Example()
现在我们有一个名为 的单独对象x
,它是 的一个实例Example
。data
和method
实际上并不是对象的一部分,但是我们仍然可以通过 Python 来查找它们,因为x
Python 在幕后做了一些魔术。特别是当我们查找时method
,我们会得到一个“绑定方法”(当我们调用它时,x
会自动作为self
参数传递,如果我们直接查找就不会发生这种情况Example.method
)。
当我们尝试使用时会发生什么x.data
?
当我们检查它时,它首先在对象中查找。如果在对象中没有找到,Python 会在类中查找。
但是,当我们分配给 时 x.data
,Python 会在对象上创建一个属性。它不会替换类的属性。
这允许我们进行对象初始化。__init__
Python 将在创建新实例时自动调用类的方法(如果存在)。在此方法中,我们可以简单地分配给属性以在每个对象上设置该属性的初始值:
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
现在我们必须name
在创建时指定 a Example
,并且每个实例都有自己的name
。Example.name
每当我们查找实例时, Python 都会忽略类属性.name
,因为会首先找到实例的属性。
最后一个警告:修改(突变)和赋值是不同的东西!
在 Python 中,字符串是不可变的。它们不能被修改。当你这样做时:
a = 'hi '
b = a
a += 'mom'
您不会更改原始的 'hi ' 字符串。这在 Python 中是不可能的。相反,您创建了一个新的string 'hi mom'
,并导致a
不再是 的名称,而是'hi '
开始成为 的名称。'hi mom'
我们也b
为ass 起了名字,'hi '
重新申请a
名字后,b
仍然是 for 的名字'hi '
,因为'hi '
仍然存在,没有改变。
但列表可以更改:
a = [1, 2, 3]
b = a
a += [4]
现在b
也是 [1, 2, 3, 4],因为我们b
为命名的同一事物a
命名,然后我们更改了该事物。我们没有为a
to name 创建一个新列表,因为 Python 只是对列表进行了+=
不同的处理。
这对对象很重要,因为如果您将列表作为类属性,并使用实例来修改列表,那么更改将在所有其他实例中“看到”。这是因为 (a) 数据实际上是类对象的一部分,而不是任何实例对象;(b) 因为您正在修改列表并且没有进行简单的分配,所以您没有创建隐藏类属性的新实例属性。