【问题标题】:Class variables in pythonpython中的类变量
【发布时间】:2015-03-27 13:17:05
【问题描述】:

我(不小心)写了以下代码:

#!/usr/bin/python3.4

class Account:

    balance = 1000

    def withdraw(self, amount):
        print('Withdrawing')
        if(amount > self.balance):
            print("You cannot withdraw that amount!")
        else:
            self.balance -= amount

    def checkBalance(self):
        if (self.balance == 0):
            print("Your account is empty.")
        else:
            print("You still have ", str(self.balance) + "€ euros in your account!")


def Main():
    account1 = Account()
    account2 = Account()

    account1.withdraw(100)
    account1.withdraw(300)

    account1.checkBalance()
    account2.checkBalance()


if __name__ == "__main__":
    Main()

输出:

Withdrawing
Withdrawing
You still have 600€ euros in your account!
You still have 1000€ euros in your account!

我的问题:

1) 为什么 balance 变量虽然被声明为类(静态)变量,但它的行为却不是类(静态)变量?

2) 即使在从方法中访问balance 变量时使用self 关键字会阻止静态行为,此时会生成类变量balance 的实例副本吗? (至少这是我的推断,每个对象都有自己的副本 - 应该是类变量 - balance

3) 通过反复试验,我发现获得(预期?)行为的一种方法是使用 @classmethod 注释方法。这是否像 Java 中那样阻止从非静态方法访问静态变量?

我知道thisthis 的帖子,但恕我直言,他们没有解决上述问题。

【问题讨论】:

    标签: python class variables static


    【解决方案1】:

    诀窍就在这里:

    self.balance -= amount
    

    这实际上转化为:

    self.balance = self.balance - amount
    

    现在,复杂的事情是self.balance 在该分配的任何一方实际上都不是同一个东西。首先评估 RHS:Python 尝试查找实例变量,失败,然后回退到类变量。但现在它执行 LHS,在这里它只是做它通常做的事情:直接分配给一个名为 balance 的实例变量。

    关键是 LHS 不知道原始值来自类变量;它只是将它被告知的位置分配给self.balance,这是一个实例变量。

    当然,从那时起,实例变量就存在了,因此任何进一步读取self.balance 都会得到它而不是原来的类变量:类变量保持不变,但被隐藏实例变量。

    当你将方法定义为类方法时,第一个参数不再是实例(self)而是类本身;因此,习惯上称该参数为cls。所以你直接读写类变量。

    【讨论】:

    • 如果我能如此优雅地表达,我会说的。如果将self.balance 替换为Account.balance,那么它将按照OP 的预期运行。
    • 也许提到类变量仍然存在,只是在self.checkBalance方法中没有引用它。
    • 那么当python找不到实例变量self.x时,它会回退到查找类变量x?在这种情况下,实际发生在比较if amount > self.balance 中。它在带有减量运算符的语句之前。另外:@classmethod 注释是否会阻止实例变量的创建,尽管存在 self. ?注释是否指示解释器忽略(包括). 之前的任何内容?
    • 嗯,它无处不在,但有趣的是我在赋值语句中描述发生的事情。不,关键是您在 classmethod 中调用的 self 并不是真正的 self 而是 cls:它是类,而不是实例。不要忘记selfcls 只是约定,您可以使用任何您喜欢的名称,但最好明确一点,在类方法的情况下,第一个参数是类对象。
    猜你喜欢
    • 2011-02-12
    • 2016-02-11
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 2011-03-24
    • 2012-01-31
    相关资源
    最近更新 更多