Python - 面向对象编程 - 类变量、实例变量/类属性、实例属性

简介: Python - 面向对象编程 - 类变量、实例变量/类属性、实例属性

什么是对象和类


https://www.cnblogs.com/poloyy/p/15178423.html

 

什么是 Python 类、类对象、实例对象


https://www.cnblogs.com/poloyy/p/15178456.html

 

类变量、实例变量/类属性、实例属性


前言

只是叫法不一样

实例属性 = 实例变量

类属性 = 类变量

个人认为叫属性更恰当

 

类属性和实例属性区别

  • 类属性,所有实例对象共享该属性
  • 实例属性,属于某一个实例对象的属性,用于描述具体的对象

 

从实际栗子了解类属性、实例属性


有一个表格,四个常见的明星

姓名 年龄
周润发 58
成龙 55
刘德华 53
周星驰 54

总结一下

  • 四个人归类为明星
  • 每个明星都有两个属性:姓名、年龄
  • 明星这个群体具有一个属性:明星数量,在这张表是 4
  • 姓名和年龄等属性是用来描述具体的一个对象
  • 明星的数量是用于描述明星这个类别

 

使用面向对象编程思想来总结的话

  • 周润发、成龙、刘德华、周星驰都是实例对象
  • 他们都属于明星,明星是
  • 属于实例对象的属性有:姓名、年龄,所以也叫实例属性
  • 属于明星类的属性有:数量,所以也叫类属性

 

类里面的三种类型变量


  • 在所有方法之外定义的变量,称为类属性/类变量
  • 在方法内部,通过 self.变量名 方式定义的变量,称为实例属性/实例变量
  • 在方法内部,通过 变量名=变量值 方式定义的变量,称为局部变量

 

类属性


类属性在类中的定义

class 类名:
    类属性1 = 值
    类属性2 = 值
    def func(self): 
        ...        


类属性、类方法注意点

  • 无论是类属性还是类方法,都无法像普通变量或者函数那样,在类的外部直接使用它们(类方法后面详解)
  • 可以将类看做一个独立的空间,类属性其实也是在类体中定义的变量,类方法是在类体中定义的函数
  • 需要通过类对象/实例对象来调用类属性 ClassName.classProperty (类方法后面详解)

 

类属性的栗子

# 类属性
class PoloBlog:
    # 这就是在所有方法之外 下面定义了 2 个类变量
    name = "小菠萝测试笔记"
    blog = "https://www.cnblogs.com/poloyy/"
# 通过类名调用类属性
print(PoloBlog.name)
print(PoloBlog.blog)
# 输出结果
小菠萝测试笔记
https://www.cnblogs.com/poloyy/


通过 Pycharm 的代码联想,可以看到 blog、name、__doc__ 三个类属性

image.png

类属性的调用方式

有两种

  • 直接通过类名调用
  • 也可以通过类的实例对象调用

 

调用类属性的栗子

# 调用类属性的两种方式
class PoloBlog:
    # 这就是在所有方法之外 下面定义了 2 个类变量
    name = "小菠萝测试笔记"
    blog = "https://www.cnblogs.com/poloyy/"
# 通过类名直接调用
print(PoloBlog.name)
print(PoloBlog.blog)
# 修改类属性
PoloBlog.name = "blogyuan"
PoloBlog.blog = "https://www.cnblogs.com/"
# 通过实例对象调用修改后的类属性
poloBlog = PoloBlog()
print(poloBlog.name)
print(poloBlog.blog)
# 输出结果
小菠萝测试笔记
https://www.cnblogs.com/poloyy/
blogyuan
https://www.cnblogs.com/


通过类名修改类属性的值,会影响所有的实例化对象

 

实例对象修改类属性

# 修改类属性
poloBlog.name = "小菠萝回来了"
# 再看看类对象调用修改后的类属性
print(PoloBlog.name)
print(poloBlog.name)
# 输出结果
blogyuan
小菠萝回来了


  • 会发现,类名.name 仍然返回之前的值,而 实例对象.name 会返回修改的值
  • 原因: 实例对象.name 本质上并不是修改类属性的值,而是在定义一个新的实例属性(下面详解)

 

动态添加类属性

PoloBlog.age = 24
print(PoloBlog.age)
print(poloBlog.age)
# 输出结果
24
24


  • age 没有在类体中定义
  • 可以直接通过 类名.new_property_name 的方式定义一个新的类属性

 

实例属性


  • 属于具体对象的属性,用于描述具体的对象
  • 只能通过实例对象访问,无法通过类名访问

 

实例属性的栗子

class PoloBlog:
    def __init__(self):
        # 在方法内部,通过 self.name 的方式定义的变量就是实例变量
        self.name = "小菠萝测试笔记"
        self.add = "https://www.cnblogs.com/poloyy/"
    # 下面定义了一个 say 实例方法
    def say(self):
        self.age = 13
# 实例化对象
blog = PoloBlog()
blog.say()
print(blog.name, blog.add, blog.age)
# 输出结果
小菠萝测试笔记 https://www.cnblogs.com/poloyy/ 13


  • 重点:__init__ 会在实例化对象的时候自动调用,因此 blog 创建成功就有 name、add 两个实例属性
  • 调用 say() 方法之后才有第三个实例属性 age

 

修改实例属性的栗子

blog.name = "小菠萝"
blog.add = "xiaopolo.com"
blog.age = 24
print(blog.name, blog.add, blog.age)
# 输出结果
小菠萝 xiaopolo.com 24



动态添加实例属性

blog.phone = 13501489999
print(blog.phone)
# 输出结果
13501489999


上面也有说到,通过 实例对象.属性名 的方式并不会给类变量赋值,而是定义一个新的实例变量

 

综合栗子

# 综合栗子
class PoloBlogObjectTest:
    # 类变量
    sum = 0
    # 初始化方法
    def __init__(self, name, age):
        # 实例变量
        self.name = name
        self.age = age
        # 类变量
        PoloBlogObjectTest.sum += 1
    # 实例方法
    def printNameAge(self):
        print(self.name, self.age)
poloTest1 = PoloBlogObjectTest("小菠萝一号", 24)
poloTest2 = PoloBlogObjectTest("小菠萝二号", 14)
print(PoloBlogObjectTest.sum)
# 调用实例方法
poloTest1.printNameAge()
poloTest2.printNameAge()
# 输出结果
2
小菠萝一号 24
小菠萝二号 14


不推荐实例属性和类属性同名


  • 类中,实例属性和类属性可以同名
  • 但这种情况下使用实例对象将无法调用类变量,它会首选实例变量,无论这个变量是否已定义
  • 实例独享绑定新的实例属性时,会直接覆盖掉重名的类属性

 

实例属性、类属性同名栗子

class Person:
    # 只有一个类变量
    name = "cool guy"
# 实例化一个对象
p = Person()
# 打印实例属性 name,因为实例对象并没有name属性,所以会继续查找class的name属性
print(p.name)
# 打印类属性 name
print(Person.name)
# 给实例绑定 name、age 属性
p.name = "bad guy"
p.age = 12
# 打印 name、age 属性
print(p.age)
# 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的 name 属性
print(p.name)
# 仍然打印类的 name 属性
print(Person.name)
# 输出结果
cool guy
cool guy
12
bad guy
cool guy


实例对象属性引用的查找过程


image.png

相关文章
|
3月前
|
Java 程序员 C++
Python 面向对象详解!
本文详细介绍了Python中的面向对象编程(OOP),包括类、对象、继承、封装、多态和抽象等核心概念。通过具体示例,解释了如何使用类定义对象的属性和方法,以及如何通过继承实现代码重用。文章还探讨了封装和多态的重要性,并介绍了私有属性和抽象类的使用方法。最后,总结了OOP的四大支柱:封装、抽象、继承和多态,强调了这些概念在Python编程中的应用。适合Java程序员扩展Python编程知识。
85 2
|
1月前
|
关系型数据库 开发者 Python
Python编程中的面向对象设计原则####
在本文中,我们将探讨Python编程中的面向对象设计原则。面向对象编程(OOP)是一种通过使用“对象”和“类”的概念来组织代码的方法。我们将介绍SOLID原则,包括单一职责原则、开放/封闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则有助于提高代码的可读性、可维护性和可扩展性。 ####
|
3月前
|
Python
Python面向对象(2)
【10月更文挑战第14天】
Python面向对象(2)
|
3月前
|
设计模式 程序员 C语言
Python面向对象
【10月更文挑战第13天】
Python面向对象
|
3月前
|
Java C# Python
Python学习七:面向对象编程(中)
这篇文章是关于Python面向对象编程的中级教程,涵盖了析构函数、对象的三大特征(封装、继承、多态)、类属性与实例属性、以及类方法与静态方法的对比。
41 2
|
3月前
|
设计模式 安全 JavaScript
Python学习八:面向对象编程(下):异常、私有等
这篇文章详细介绍了Python面向对象编程中的私有属性、私有方法、异常处理及动态添加属性和方法等关键概念。
30 1
|
4月前
|
前端开发 Python
Python编程的面向对象有哪些(二)
Python编程的面向对象(二)—类的多态
30 7
|
4月前
|
IDE Java 开发工具
Python类与面向对象
Python类与面向对象
|
4月前
|
存储 Java 程序员
30天拿下Python之面向对象编程
30天拿下Python之面向对象编程
24 3
|
4月前
|
Java Python
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
【9月更文挑战第18天】在 Python 中,虽无明确的 `interface` 关键字,但可通过约定实现类似功能。接口主要规定了需实现的方法,不提供具体实现。抽象基类(ABC)则通过 `@abstractmethod` 装饰器定义抽象方法,子类必须实现这些方法。使用抽象基类可使继承结构更清晰、规范,并确保子类遵循指定的方法实现。然而,其使用应根据实际需求决定,避免过度设计导致代码复杂。