在方法中访问 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
因为现在 self
是 Foo
的一个实例(所以它指的是 Foo.a
),其中 Base.a
毫不奇怪地指的是 Base.a
,无论我们用来调用 f
.
的当前实例
Python 属性读取,self.attribute
的工作方式如下:
- Python 检查属性是否是 class 或祖先 class 中的数据描述符,如果是,则调用其
__get__
方法(不是这种情况,我稍后会回到这里)
- 然后检查实例(self)
__dict__
属性,看是否包含attribute
,如果包含,则获取
- 检查是否存在“非数据描述符”(没有
__set__
方法的描述符,例如函数或方法)
- 然后检查它是否是 class
__dict__
<- 你在这里! 中的普通(非描述符)属性
- 检查任何祖先中的普通属性 classes
- 调用 class 上的
__gettattr__
方法(如果存在)
- 引发属性错误。
这套规则在使用语言的时候其实是很自然的。但是你必须小心,如果你在任何时候 写 回到属性 - 如果你做类似 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 都可以随意重写这些规则(通常只会调整对某些属性的访问,以创建代理对象或类似的东西,而不是完整的层次集几乎一样复杂的规则)
你能告诉我在方法内部调用 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
因为现在 self
是 Foo
的一个实例(所以它指的是 Foo.a
),其中 Base.a
毫不奇怪地指的是 Base.a
,无论我们用来调用 f
.
Python 属性读取,self.attribute
的工作方式如下:
- Python 检查属性是否是 class 或祖先 class 中的数据描述符,如果是,则调用其
__get__
方法(不是这种情况,我稍后会回到这里) - 然后检查实例(self)
__dict__
属性,看是否包含attribute
,如果包含,则获取 - 检查是否存在“非数据描述符”(没有
__set__
方法的描述符,例如函数或方法) - 然后检查它是否是 class
__dict__
<- 你在这里! 中的普通(非描述符)属性
- 检查任何祖先中的普通属性 classes
- 调用 class 上的
__gettattr__
方法(如果存在) - 引发属性错误。
这套规则在使用语言的时候其实是很自然的。但是你必须小心,如果你在任何时候 写 回到属性 - 如果你做类似 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 都可以随意重写这些规则(通常只会调整对某些属性的访问,以创建代理对象或类似的东西,而不是完整的层次集几乎一样复杂的规则)