为什么在 Python 类 __init__ 中调用函数既可以是 Attribute 又可以是 Method?

问题描述

我对 Python 类的方法属性很困惑。假设我们有一个这样的 Python 类:

# case 1
class Person:

    def __init__(self,first,last):

        self.first = first
        self.last = last
        self.fun()

    def fun(self):
        value = self.first + '---' + self.last
        self.fun = value
        return value

person_1 = Person('A','B')  
person_1.fun

---> "A---B"

如我们所见,在case_1中,我们初始化了一个实例 person_1。我们可以通过将 fun 作为属性调用来获得我们想要的结果。但是,如果我们将代码更改为以下内容fun 将变成方法(case_2)

# case 2
class Person:

    def __init__(self,last):

        self.first = first
        self.last = last
        self.fun()

    def fun(self):
        value = self.first + '---' + self.last
        return value

person_1 = Person('A','B')  
person_1.fun

---> <bound method Person.fun of <__main__.Person object at 0x7fd4f79168d0>>

我们仍然在类中包含 init 进程。但是现在 fun 变成了方法,而不是属性(案例_2)

如果我们删除 self.fun() 中的 init 但保留 self.fun = value,它仍然是一个 方法(案例_3)

# case 3
class Person:

    def __init__(self,last):

        self.first = first
        self.last = last

    def fun(self):
        value = self.first + '---' + self.last
        self.fun = value
        return value

person_1 = Person('A','B')  
person_1.fun

---> <bound method Person.fun of <__main__.Person object at 0x7fd4f797f390>>

你介意给我一些关于为什么会发生这种情况的说明吗?将函数用作 Python 类中的属性的正确方法是什么?在此先感谢您!

解决方法

在第 1 种情况下,您的构造函数调用 fun() ,其中包含一行以使用属性值覆盖自身。这是令人困惑的,不是一件好事,因为它令人困惑。

在第 2 种情况下,您的 fun 方法不包含覆盖自身的行,因此不会被覆盖。

在情况 3 中,您实际上从未调用过 fun 方法,因此它永远没有机会覆盖自己。如果您使用 person_1.fun() 调用它,即使用括号,那么它将执行并覆盖自身,从那时起,person_1.fun 将是一个属性值。

请记住,在 python 中,函数/方法只有在使用括号调用时才会执行。如果不用括号表示,那么求值的结果不是函数的输出,而是表达式产生对函数本身的引用,可以放在另一个变量或数据结构中,稍后调用.

为了说明这一点:

>>> def my_func():                                      
...     print('got called')                             
...     return 42                                       
...                                                     
>>> x = my_func #no parentheses,x becomes an alias to my_func                         
>>> y = my_func()  #parentheses means actually execute                                      
got called                                              
>>> y                                                   
42                                                      
>>> x                                                   
<function my_func at 0x765e8afdc0>                      
>>> x()  #x is a reference to my_func and can be called itself                                               
got called                                              
42                                                      
>>>
,

啊哈,我想我明白了!

在情况 1 中,我们只是在初始化实例时运行函数 fun()。并且因为它在 self.fun = value 中定义了属性 fun(),因此 fun 可以用作属性。 (不能再作为方法使用了,因为它已经被替换为属性了。)

在情况 2 中,我们只调用并运行此函数。但是 fun 没有被定义为类内部的属性。这就是为什么它仍然是一种方法。

在情况 3 中,fun 是一个方法,但在此方法中,我们定义了一个属性 fun。因此我们可以先初始化一个实例,然后运行函数fun。之后,属性fun被添加到这个实例中,然后我们可以将其称为person_1.fun

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...