python的类变量和实例变量

在 Python 中,类变量和实例变量有以下区别和联系:

区别

  1. 定义位置:

    • 类变量是在类的定义内部,但在任何方法之外定义的变量。
    • 实例变量是在类的方法(如 __init__ 方法)中通过 self 关键字定义的变量。
  2. 作用范围:

    • 类变量属于类本身,被类的所有实例共享。
    • 实例变量属于类的某个特定实例,每个实例都有自己独立的实例变量副本。
  3. 访问方式:

    • 类变量可以通过类名直接访问,也可以通过实例访问。
    • 实例变量只能通过实例访问。
  4. 修改影响:

    • 对类变量的修改会影响到所有实例。
    • 对实例变量的修改只影响当前实例。

联系

  1. 都用于存储与类或实例相关的数据。

  2. 实例变量的查找会先在实例自身的属性中查找,如果没有找到,会去类中查找类变量。

下面是一个示例代码,展示了类变量和实例变量的区别:

class MyClass:
    class_variable = "这是类变量"  # 定义类变量

    def __init__(self, instance_variable_value):
        self.instance_variable = instance_variable_value  # 定义实例变量

# 创建实例
instance1 = MyClass("实例 1 的值")
instance2 = MyClass("实例 2 的值")

# 访问类变量
print(MyClass.class_variable)  
print(instance1.class_variable)  
print(instance2.class_variable)  

# 访问实例变量
print(instance1.instance_variable)  
print(instance2.instance_variable)  

# 修改类变量
MyClass.class_variable = "修改后的类变量"

# 此时所有实例访问到的类变量都被修改
print(instance1.class_variable)  
print(instance2.class_variable)  

# 修改实例变量
instance1.instance_variable = "修改后的实例 1 的变量"

# 只有 instance1 的实例变量被修改
print(instance1.instance_variable)  
print(instance2.instance_variable)  

延申:类属性和实例属性

类属性和实例属性在 Python 中有以下区别和联系:

区别

  1. 定义位置:

    • 类属性在类的定义中直接定义,通常在方法之外。
    • 实例属性在类的方法中通过 self 关键字进行定义,常见于 __init__ 方法中。
  2. 归属对象:

    • 类属性属于类本身,为类的所有实例所共享。
    • 实例属性属于类的具体实例,每个实例都有自己独立的实例属性值。
  3. 访问方式:

    • 类属性可以通过类名直接访问,也能通过实例访问。
    • 实例属性只能通过实例来访问。
  4. 修改影响:

    • 对类属性的修改,会影响到所有通过该类创建的实例。
    • 对实例属性的修改,只影响当前实例,不会影响其他实例和类属性。

联系

  1. 都是用于存储与类或实例相关的数据。

  2. 当通过实例访问一个属性时,如果实例中没有该属性,会自动到类中查找对应的类属性。

下面是一个示例来说明类属性和实例属性的区别和联系:

class MyClass:
    class_attribute = "这是类属性"  # 定义类属性

    def __init__(self, instance_attribute_value):
        self.instance_attribute = instance_attribute_value  # 定义实例属性

# 创建实例
obj1 = MyClass("实例 1 的值")
obj2 = MyClass("实例 2 的值")

# 访问类属性
print(MyClass.class_attribute)  
print(obj1.class_attribute)  
print(obj2.class_attribute)  

# 访问实例属性
print(obj1.instance_attribute)  
print(obj2.instance_attribute)  

# 修改类属性
MyClass.class_attribute = "修改后的类属性"

# 此时所有实例访问到的类属性都被修改
print(obj1.class_attribute)  
print(obj2.class_attribute)  

# 修改实例属性
obj1.instance_attribute = "修改后的实例 1 的属性"

# 只有 obj1 的实例属性被修改
print(obj1.instance_attribute)  
print(obj2.instance_attribute)  

访问顺序(MRO):

在 Python 中,当访问属性时,会先查找实例属性,如果实例中没有该属性,再去查找类属性。

也就是说,实例属性的优先级高于类属性。当实例属性和类属性同名时,实例属性会屏蔽掉类属性。但是,当删除实例属性后,再使用相同的名称访问,将访问到类属性。

例如,以下代码中定义了一个类MyClass,其中有一个类属性class_attribute

class MyClass:
    class_attribute = "这是类属性" 

obj = MyClass()
print(obj.class_attribute)  

在上述代码中,通过实例obj访问class_attribute属性时,由于实例obj本身没有该实例属性,所以会找到类中的class_attribute类属性并输出。

如果给实例添加了与类属性同名的实例属性:

obj.instance_attribute = "这是实例属性" 
print(obj.instance_attribute)  

此时再访问instance_attribute属性,将输出实例属性的值,类属性被屏蔽。

若删除实例属性:

del obj.instance_attribute 
print(obj.class_attribute)  

再次访问instance_attribute属性时,由于实例的该属性不存在了,就会显示出类属性的值。

这里又涉及到一个多继承的问题:

在 Python 中,多继承的查找顺序可以通过方法解析顺序(Method Resolution Order,简称 MRO)来确定。Python 使用 C3 算法来计算多继承的顺序。

Python 3 中,多继承的查找顺序是广度优先,即从左到右,先在同一级的父类中查找,然后再向上一级查找,直到找到所需的方法或属性,或者到达object类。如果在当前类中找到了方法,就直接执行,不再继续搜索。如果没有找到,就按照 MRO 顺序查找下一个类中是否有对应的方法。

要查看某个类的 MRO 顺序,可以使用该类的__mro__属性,它返回一个元组,展示了方法的搜索顺序。

例如,对于以下类的定义:

class A:
    pass

class B(A):
    pass

class C(A):
    pass

class D(B, C):
    pass

可以通过D.__mro__来查看D类的方法解析顺序。

需要注意的是,Python 2 中的经典类(不继承自object的类)采用深度优先的查找顺序,而新式类(继承自object的类)采用广度优先的查找顺序。为了保证代码在 Python 2 和 Python 3 中都能正确运行,建议在定义类时,如果没有父类,统一继承自object

另外,在多继承中,如果多个父类有相同的方法名,可能会导致方法的调用具有一定的不确定性,并且可能出现一些复杂的情况。为了避免潜在的问题,建议尽量减少多继承的使用,或者确保类的设计清晰合理,避免方法名的冲突。如果确实需要多继承,并且存在同名方法,可以通过明确指定调用某个父类的方法来避免歧义。例如使用super(父类名, self).方法名()的方式来指定调用特定父类的方法。

相关推荐

  1. python变量实例变量

    2024-07-11 14:04:02       24 阅读
  2. Python变量实例变量

    2024-07-11 14:04:02       46 阅读
  3. Python变量实例变量有什么区别?

    2024-07-11 14:04:02       40 阅读
  4. Python 变量

    2024-07-11 14:04:02       41 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 14:04:02       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 14:04:02       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 14:04:02       57 阅读
  4. Python语言-面向对象

    2024-07-11 14:04:02       68 阅读

热门阅读

  1. JDK-CompletableFuture

    2024-07-11 14:04:02       25 阅读
  2. Python 获取 SQL 指纹和 HASH 值

    2024-07-11 14:04:02       25 阅读
  3. 井字棋 AI-Python

    2024-07-11 14:04:02       25 阅读
  4. android解锁remount

    2024-07-11 14:04:02       27 阅读
  5. 洛谷 P3008 [USACO11JAN] Roads and Planes G

    2024-07-11 14:04:02       22 阅读
  6. 2.Spring的IOC容器里面加入对象的常见方式

    2024-07-11 14:04:02       24 阅读
  7. React基础学习-Day02

    2024-07-11 14:04:02       19 阅读
  8. MyClass.static_method() 加不加括号有什么区别

    2024-07-11 14:04:02       23 阅读
  9. AcWing 1633:外观数列

    2024-07-11 14:04:02       26 阅读