Python变量声明


85

学习Python,并且有一些基本的疑问。

1.我已经看到变量声明(这里的路径)为

class writer:
    path = ""

有时,没有显式声明,而是通过进行初始化__init__

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

我了解的目的__init__,但建议在其他任何函数中声明变量。

2.如何创建变量以保存自定义类型?

class writer:
    path = "" # string value
    customObj = ??

12
并且,关于第二个问题:在Python中,变量没有类型:值却没有。因此,任何变量都可以保存您的自定义对象。
jpaugh 2012年

4
如果您停止将名称/标识符视为变量,这将有所帮助。它们是对象的引用
John La Rooy

2
@gnibbler或为他们命名...
不错,2012年

1
@detly,我认为姓名是一个错误的选择。事物通常只有一个名称,而一个对象可能具有多个引用
John La Rooy

2
@JohnClements,但是python不能像数学一样工作。如果您想了解python,则需要知道具有__name__属性的对象具有“名称”。并非所有对象都有__name__属性,但是您仍然可以引用它们。如果我们开始将“引用”称为“名称”,那么我们正在对初学者造成损害。
John La Rooy

Answers:


202

好吧,第一件事。

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,该对象表示Examples的所有事物的类。该对象具有两个用户提供的属性(在C ++中为“成员”;在C#中为“字段或属性或方法”;在Java中为“字段或方法”)。其中之一被命名data,它存储整数值42。另一个名为method,它存储一个函数对象。(Python自动添加了更多属性。)

但是,这些属性实际上并不是对象的真正组成部分。从根本上讲,一个对象只是一堆更多的名称(属性名称),直到您了解到无法再划分的事物为止。因此,如果您有意设置值,则可以在类的不同实例之间甚至在不同类的对象之间共享值。

让我们创建一个实例:

x = Example()

现在,我们有一个名为的单独对象x,它是的实例Example。该datamethod是对象不实际的一部分,但我们仍然可以找一找通过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当我们创建一个时必须指定一个Example,每个实例都有自己的nameExample.name每当我们查找.name实例的时,Python都会忽略class属性,因为将首先找到实例的属性。

最后一个警告:修改(变异)和赋值是不同的!

在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只是对列表进行了+=不同的对待。

这对对象很重要,因为如果您有一个列表作为类属性,并使用实例来修改该列表,则在所有其他实例中都将“看到”更改。这是因为(a)数据实际上是类对象的一部分,而不是任何实例对象;(b)因为您正在修改列表而不是进行简单的分配,所以您没有创建新的实例属性来隐藏类属性。


12
这就是为什么我们称它们为“标识符”。:-)
马丁·彼得

最后在您的字符串示例中使用@Karl_Knechtel,如果我们从不将其命名为“ b”,那么“ hi”会怎样?这是内存泄漏吗?
heretoinfinity

2
@heretoinfinity:不;Python使用垃圾回收来释放无法访问的对象
John Clements

在此视频中,变量声明得到了很好的解释:youtube.com/watch?v=ao2N37E-D9s
伊沙克·汗

看看这个视频的答案youtube.com/...
邵族ñ

23

这可能要晚6年了,但是在Python 3.5及更高版本中,您需要声明这样的变量类型:

variable_name: type_name

或这个:

variable_name # type: shinyType

因此,在您的情况下(如果CustomObject定义了一个类),可以执行以下操作:

customObj: CustomObject

获取更多信息。


22

无需在Python中声明新变量。如果我们在谈论函数或模块中的变量,则不需要声明。只需在需要的地方为它分配一个值:mymagic = "Magic"。Python中的变量可以保存任何类型的值,您不能限制它。

您的问题专门询问类,对象和实例变量。创建实例变量的惯用方式是在__init__方法中,而在其他任何地方(虽然您可以在其他方法中甚至在不相关的代码中创建新的实例变量,但这是一个坏主意。这会使您的代码难以推理或难以维护。

因此,例如:

class Thing(object):

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

简单。现在,此类的实例具有一个magic属性:

thingo = Thing("More magic")
# thingo.magic is now "More magic"

在类本身的名称空间中创建变量会导致完全不同的行为。它在功能上有所不同,只有在有特定原因的情况下才应这样做。例如:

class Thing(object):

    magic = "Magic"

    def __init__(self):
        pass

现在尝试:

thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1

要么:

class Thing(object):

    magic = ["More", "magic"]

    def __init__(self):
        pass

thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]

这是因为类本身的名称空间与从其创建的对象的名称空间不同。我会留给您研究一下。

要注意的是,惯用Python将(a)初始化__init__方法中的对象属性,并且(b)根据需要记录类的行为。您不必为编写的所有内容而烦恼的功能齐全的Sphinx级别的文档,但是至少可以对您或其他人可能需要的详细信息发表一些评论。


12

为了进行范围界定,我使用:

custom_object = None

1

变量具有作用域,因此是的,具有特定于您的函数的变量是合适的。您不必总是明确说明它们的定义。通常您可以使用它们。仅当您要执行特定于变量类型的操作(如列表的追加)时,才需要在开始使用它们之前对其进行定义。典型的例子。

list = []
for i in stuff:
  list.append(i)

顺便说一句,这并不是设置列表的好方法。最好说:

list = [i for i in stuff] # list comprehension

...但是我离题了。

您的其他问题。自定义对象应该是一个类本身。

class CustomObject(): # always capitalize the class name...this is not syntax, just style.
  pass
customObj = CustomObject()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.