Python中不存在“变量声明”(variable declaration)或“变量初始化”(variable initialization)这样的说法。
这里我们简单地称它为“assignment”(不知道怎么翻译合适),但恰当的话应该只称它为“命名”(naming)。
“assignmen”的意思是“左边的这个名称现在指向的是对右边求值的结果,而不管它之前指向的是什么(如果有的话)”。
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# 之类的语言更加一致:在类块中声明的所有内容都是类的一部分,因此,这里写的函数(def) 是方法,即类对象的一部分 (不是存储在每个实例上),就像在 Java、c++ 和 c# 中一样;但是这里的其他名字也是这个类的一部分。同样,名称只是名称,它们没有关联的类型 (对象才有类型),函数在Python中也是对象。因此:
class Example:
data = 42
def method(self):
pass
在 Python 里,类也是对象
现在我们创建了一个名为 Example 的对象,它表示所有实例的类。这个对象有两个用户提供的属性 (在 c++ 中是“members”;在 c# 中,“fields or properties or methods”;在 Java 中,“fields or methods”)。其中一个名为 data ,它存储整数值42。另一个名为 method ,它存储一个函数对象。(Python还自动添加了其他几个属性)
不过,这些属性仍然不是对象的真正组成部分。从根本上说,一个对象就是一组名称(属性名称),直到你处理到不能再分割的东西为止。因此,可以在类的不同实例之间共享值,甚至在不同类的对象之间共享值 (如果你有意设置的话) 。
让我们创建一个实例:
x = Example()
现在我们有一个单独的对象 x,它是一个实例。数据和方法实际上不是 x 对象的一部分,但是我们仍然可以通过 x 查找它们,因为 Python 在幕后做了一些魔术。特别是当我们查找方法时,我们将得到一个“绑定方法”(当我们调用它时,x 自动作为 self 参数传递,如果我们直接查找 Example.method,是无法去查找的)。
当我们尝试使用 x.data 时会发生什么?
当我们检查它时,它首先在 x 对象中查找。如果在对象中没有找到,Python 会查找类。
然而,当我们 assign to x.data,Python 将在对象上创建一个属性。它不会替换类的属性。
这允许我们进行对象初始化。如果新实例被创建,Python 将自动调用该类的__init__方法。在这个方法中,我们可以简单地给每个对象 assign to attributes to set initial values (也就是说通过__init__给对象创建属性)
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
def method(self):
pass
现在,我们在创建实例时必须指定一个名称,每个实例都有自己的名称。每当我们查找实例的 .name 时,Python 将忽略 class 属性 Example.name,因为实例的属性将首先被找到。
最后一个警告: modification (mutation) 和 assignment 是不同的概念!
在Python中,字符串是不可变的。它们不能被修改。比如:
a = 'hi '
b = a
a += 'mom'
你不能更改原来的“hi”字符串,这在 Python 中是不可能的。相反,你创建一个新的字符串“hi mom”,并使 a 不再是“hi”的名称,而是开始成为“hi mom”的名称。我们也将 b 作为 hi 的名称,重新应用 a 名称后,b 仍然是 hi 的名称,因为 hi 仍然存在,没有改变。
但是列表可以改变:
a = [1, 2, 3]
b = a
a += [4]
现在 b 也是 [1,2,3,4],因为我们给 b 取了和 a 一样的名字,然后我们改变了它。我们没有为 a 创建一个新的列表并命名,因为Python只是简单地将 += 用于列表。
这对对象很重要,因为如果您有一个列表作为 class 属性 (注意类属性和实例属性是不一样的),并使用一个实例来修改列表,那么在所有其他实例中都可以“看到”更改。这是因为
(a) 数据实际上是类对象的一部分,而不是任何实例对象;
(b) 因为你在修改列表而不是执行简单的 assignment,所以你没有创建一个隐藏 class 属性的新实例属性。