为什么不必在Python中返回对象?

Mat*_*att 6 python python-3.x

我是Python和编程的新手,我刚刚进入OOP.在Python中,函数命名空间中定义的任何内容仅在该命名空间内有效; 一旦在那个空间之外,变量就会被遗忘:

def foo():
    a = 3

print(a)

NameError: name 'a' is not defined
Run Code Online (Sandbox Code Playgroud)

据我所知,除了从函数返回数据外,函数内部的任何信息都会在函数调用结束时丢失,这就是我的问题.请使用以下代码:

class Example:

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

    def foo(self):
        self.name = 'John'

bar = Example('Jake')
bar.foo()
print(bar.name)

'John'
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么你不必在方法之后返回对象?在正常函数中,任何变量都被遗忘,但在方法中,似乎数据实际上附加到对象本身,例如尽管首先在另一个方法中foo()引用,self.name但该方法能够引用self.name.它是否正确?还是有更好的技术解释?

Din*_*ari 5

首先,您不必在方法中返回值,而不是在python中,而不是在许多其他编程语言中.例如:

def append_a(lst):
    lst.append('a')

bob = []
append_a(bob)
print(bob)
['a']
Run Code Online (Sandbox Code Playgroud)

上面我们不返回函数中的任何内容,但我们用它来修改现有的数据结构,这在任何地方都很常见.

其次,在你的第二个例子中,你创建了一个Example类的实例,当你看到self.something你正在查看类的一个成员时,与其他语言不同,其中成员通常只声明一次,在python中你可以动态添加成员.
因此,在查看时,bar.name您正在查看类的成员,它在实例上的值bar.如果您查看其他实例,则值将不同.

class Example:

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

    def foo(self):
        self.name = 'John'

bar = Example('Jake')
bob = Example('Bob')
bar.foo()
print(bar.name)
print(bob.name)

John
Bob
Run Code Online (Sandbox Code Playgroud)


Piy*_*agi 4

要理解这一点,您需要了解 self 是如何工作的。您可以在这里了解更多信息: Understanding self in python

简而言之,self 指的是调用对象。调用self.variable是指与调用对象关联的变量。Python 足够聪明,可以在不存在的情况下创建一个。

在类内部调用与使用对象引用self.variable调用相同object.variable

考虑以下示例来证明这一点:

class Example:
    def print_x(self):
        print(self.x)

obj = Example()
obj.x = 5;    # Create a new attribute of the object and assign it a value 5
print(obj.x)  # Outputs 5
obj.print_x() # Outputs 5
Run Code Online (Sandbox Code Playgroud)

在您的示例中,我添加了一些打印语句来帮助您了解程序在执行过程中的状态:

    class Example:
    def __init__(self, name):
        print(dir(self)) # Printing object contents before initializing name
        self.name = name # New attribute 'name' created
        print(dir(self)) # Printing object contents after initializing name

    def foo(self):
        print("Before foo, self.name = "+ self.name)
        self.name = 'John'
        print("After foo, self.name = "+ self.name)


bar = Example('Jake')
bar.foo()
print(bar.name)
Run Code Online (Sandbox Code Playgroud)

上述代码的输出是

['__doc__', '__init__', '__module__', 'foo']
['__doc__', '__init__', '__module__', 'foo', 'name']
Before foo, self.name = Jake
After foo, self.name = John
John
Run Code Online (Sandbox Code Playgroud)

我将引导您完成这段代码。当我们第一次创建 bar 时,__init__()会调用该方法。这里我们使用 打印对象的内容dir(self)。输出['__doc__', '__init__', '__module__', 'foo']表明该对象只有一个成员,即“foo”方法。

现在我们创建一个名为“name”的新属性,并为其分配值“Jake”。因此,该对象现在有另一个成员,即“name”属性,如下一个 dir(self) 的输出所示['__doc__', '__init__', '__module__', 'foo', 'name']

现在我们调用 foo 方法并打印该方法之前和之后的值。在 foo 中更改之前name,与该对象关联的值为name“Jake”。然而,name改变后, 的值为self.name“John”。这由

Before foo, self.name = Jake
After foo, self.name = John`
Run Code Online (Sandbox Code Playgroud)

接下来我们通过打印来验证通过更改所做的更改确实改变了inself.name的值,这给了我们预期的输出,namebarbar.nameJohn

现在回到你的问题,self.name当我们超出范围时,某些方法中的普通变量是否会丢失。self基本上可以在类内的任何地方使用来引用调用对象(在本例中为 bar)。它用于操作该调用对象。现在由于bar在范围内,我们可以打印它的name属性。

在普通函数中,任何变量都会被忘记,但在方法中,数据似乎实际上附加到对象本身

self操作对象中的属性并且不限于方法的范围。