在方法中访问 class 变量的方法 - python

Ways to access class variable in method - python

你能告诉我在方法内部调用 Class_name.class_variable 和 self.class_variable 有什么区别吗?这是示例:

class Employee:

   raise_amount = 1.04

   def __init__(self, first, last, pay):
       self.first = first
       self.last = last
       self.pay = pay

   def apply_raise(self):
       self.pay = int(self.pay * Employee.raise_amount)

所以我使用了Employee.raise_amount,但我也可以这样写这个方法:

def apply_raise(self):
    self.pay = int(self.pay * self.raise_amount)

我用以下方法测试过:

emp_1 = Employee('James', 'Amb', 10000)
emp_2 = Employee('Test', 'User', 20000)

print("Original value")
print("emp_1.raise_amount", emp_1.raise_amount)
print("emp_2.raise_amount", emp_2.raise_amount)

emp_1.raise_amount = 1.1
print("emp_1.raise_amount = 1.1")
print("emp_1.raise_amount", emp_1.raise_amount)
print("emp_2.raise_amount", emp_2.raise_amount)

Employee.raise_amount = 1.2
print("Employee.raise_amount = 1.2")
print("emp_1.raise_amount", emp_1.raise_amount)
print("emp_2.raise_amount", emp_2.raise_amount)

我运行程序使用Employee.raise_amount然后self.raise_amount。在这两种情况下输出是相同的:

Original value
emp_1.raise_amount 1.04
emp_2.raise_amount 1.04
emp_1.raise_amount = 1.1
emp_1.raise_amount 1.1
emp_2.raise_amount 1.04
Employee.raise_amount = 1.2
emp_1.raise_amount 1.1
emp_2.raise_amount 1.2

那么有什么区别,什么时候应该使用 Class_name.class_variable 和 self.class_variable

一个擅长继承,另一个不擅长。

class Base:
    a = 1

    def f(self):
        print(Base.a)


class Foo(Base):
    a = 2

Base().f()
Foo().f()

产出

1
1

print(Base.a) 更改为 print(self.a) 会将输出更改为

1
2

因为现在 selfFoo 的一个实例(所以它指的是 Foo.a),其中 Base.a 毫不奇怪地指的是 Base.a,无论我们用来调用 f.

的当前实例

Python 属性读取,self.attribute 的工作方式如下:

  1. Python 检查属性是否是 class 或祖先 class 中的数据描述符,如果是,则调用其 __get__ 方法(不是这种情况,我稍后会回到这里)
  2. 然后检查实例(self)__dict__属性,看是否包含attribute,如果包含,则获取
  3. 检查是否存在“非数据描述符”(没有__set__方法的描述符,例如函数或方法)
  4. 然后检查它是否是 class __dict__ <- 你在这里!
  5. 中的普通(非描述符)属性
  6. 检查任何祖先中的普通属性 classes
  7. 调用 class 上的 __gettattr__ 方法(如果存在)
  8. 引发属性错误。

这套规则在使用语言的时候其实是很自然的。但是你必须小心,如果你在任何时候 回到属性 - 如果你做类似 self.attribute = value 的事情,那么属性是在实例中设置的,而不是在class,如果您在其他方法中通过执行 ClassName.attribute 检索它,它将看到在 class 上设置的原始值,而不是在 self 上设置的值,即使是同一个实例。

考虑到所有因素,始终使用 self.attribute 的自然设计对于 read-only class 属性会更好。如果您需要为单个实例设置一个特殊值,您可以只为该实例设置一个新值,一切都会继续工作。对于使用您的案例的示例,假设对于大多数员工来说,raise_ammount 是 1.04,但其中一个是 1.06 的特殊情况,任何方法甚至外部代码都可以在实例上设置新属性,并且从 self. 读取值的方法将查看更新后的数字。

至于“描述符”——它们是绑定到 class 的特殊对象,具有 __get____set____delete__ 方法之一,并覆盖属性访问在实例上和 class。它们是 @property 装饰器、方法和 class 方法本身使用的机制(以便语言可以在方法调用中插入 self 参数)。

哦,所有这些步骤都用 object.__getattribute__ 方法中的语言编码(与 __getattr__ 不同)。任何覆盖 __getattribute__ 的 class 都可以随意重写这些规则(通常只会调整对某些属性的访问,以创建代理对象或类似的东西,而不是完整的层次集几乎一样复杂的规则)