前言

Python 语言在设计之初,就定位为一门面向对象的编程语言,“Python 中一切皆对象”就是对 Python 这门编程语言的完美诠释。

本文不仅会教你掌握 Python 类和对象的基本语法,还可以带你深入底层,了解 Python 面向对象的实现原理,并且会通过面向对象编程的方式带你了解类与对象的属性方法以及应用场景,并通过魔术方法实现面向对象的部分逻辑实现。


什么是面向对象,Python面向对象(一切皆对象)

面向对象编程是在面向过程编程的基础上发展来的,它比面向过程编程具有更强的灵活性和扩展性。面向对象编程是程序员发展的分水岭,很多初学者会因无法理解面向对象而放弃学习编程。

面向对象编程(Object-oriented Programming,简称 OOP),是一种通过组织对象来设计程序的编程方法,也可以把它理解为封装代码的方式。

Python天生就是面向对象的模块化编程

初识类和对象

类和对象的概念

在进入面向对象编程前我们要先了解类和对象之间的基本关系

核心思想类比:蓝图与房子
想象一下你要建造房子:
类 (Class) - 蓝图:它不是一个具体的房子,而是定义了房子应该是什么样子、有什么属性、能做什么事情的一套设计图纸或模板。
这张蓝图会详细说明:
—属性 (Attributes/Properties/Fields): 房子有几个房间?多大面积?什么颜色?什么结构?(例如:房间数、面积、颜色、结构类型)。
—行为 (Methods/Functions): 房子能做什么?或者说,可以对房子做什么操作?(例如:开门()、关灯()、装修()、计算房产税())。

蓝图(类)本身不能住人,它只是定义了房子的规格和功能。
对象 (Object) - 具体的房子:它是根据蓝图(类)实际建造出来的、真实存在的、具体的房子。
每栋根据同一张蓝图建造出来的房子(对象):
—都拥有蓝图里定义的所有属性,但这些属性的具体值可以不同。比如,蓝图定义了要有颜色属性,但房子A可以是红色,房子B可以是蓝色。
—都能够执行蓝图里定义的所有行为。比如,蓝图定义了开门()方法,那么房子A和房子B都可以执行开门这个动作。
—对象是实际占用内存空间的实体,你可以与它交互(调用它的方法,查看或修改它的属性)。

类的定义

前面讲到类是对一类对象的抽象,是对象的模板或蓝图。它定义了对象的属性(特征)和方法(功能)。

  • 数据成员:表明事物的特征。 相当于变量

  • 方法成员:表明事物的功能。 相当于函数

  • 通过class关键字定义类。

  • 类的创建语句语法:

class 类名 (继承列表):
	实例属性(类内的变量) 定义
    实例方法(类内的函数method) 定义
    类变量(class variable) 定义
    类方法(@classmethod) 定义
    静态方法(@staticmethod) 定义

注意:无论是类属性还是类方法,对于类来说,它们都不是必需的,可以有也可以没有。另外,Python 类中属性和方法所在的位置是任意的,即它们之间并没有固定的前后次序。
我们通过一个示例来定义一个类:

class Student:
	def __init__(self, name, age):
        self.name = name
        self.age = age
    def study(self):
    	return f'{self.name}正在学习。。。'

作为一名合格的程序员,我们必须还要考虑程序的可读性。因此,在给类起名字时,最好使用能代表该类功能的单词,如用“Student”作为学生类的类名;甚至如果必要,可以使用多个单词组合而成。
注意:如果由单词构成类名,建议每个单词的首字母大写,其它字母小写。
在上述定义的Student作为一个类,类中包含了Student的一些属性:name,age,还要属于Student的类方法study()。

类对象的创建和使用

对象是类的实例化,是类的实际数据存储,具有类所定义的属性和方法。我们已经学会如何定义一个类,但要想使用它,必须创建该类的对象。

创建类对象的过程,又称为类的实例化。
创建对象的基本格式:

对象名=类名(参数)

示例:

#定义一个名为Student的类
class Student(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def study(self):
        return f'{self.name}正在学习。。。'

#创建一个对象实例化类
stu1=Student('小枫',19)
print(type(stu1))
#输出:<class '__main__.Student'>

最后打印出stu1的类型输出显示<class '__main__.Student'>stu1是属于Student这个类

属性和方法

类的属性和方法是类的核心组成部分,它们用于定义类的状态和行为。

构造方法__init__()和self初识化对象属性

在创建类时,我们可以手动添加一个 __init__() 方法,该方法是一个特殊的类实例方法,称为构造方法(或构造函数)。

init()的存在是为了在实例化类的同时调用构造方法:

class Student(object):
    def __init__(self, name, age):
    	print('构造方法被调用。。')
        self.name = name
        self.age = age
stu1=Student('小枫'19)

上述代码中stu1=Student('小枫',19)这一行被执行,表示类被一个对象实例化了,此时就会打印“构造方法被调用。。”但是构造方法必须至少需要一个参数才能被执行,所以这里我们就用到了**self**

self 参数的具体作用是什么呢?打个比方:
如果把类比作造房子的图纸,那么类实例化后的对象是真正可以住的房子。根据一张图纸(类),我们可以设计出成千上万的房子(类对象),每个房子长相都是类似的(都有相同的类变量和类方法),但它们都有各自的主人,那么如何对它们进行区分呢?

当然是通过 self 参数,它就相当于每个房子的门钥匙,可以保证每个房子的主人仅能进入自己的房子(每个类对象只能调用自己的类变量和类方法)。
示例:

class Person:
    name = "xxx"
    def __init__(self,name):
        self.name=name
zhangsan = Person("zhangsan")
print(zhangsan.name)
lisi = Person("lisi")
print(lisi.name)
#输出:
#zhangsan
#lisi

可以看到,zhangsan 在进行初始化时,调用的构造函数中 self 代表的zhangsan;而 lisi 在进行初始化时,调用的构造函数中 self 代表的是 lisi。
显然,self 所表示的都是实际调用该方法的对象。

实例属性和实例方法

实例属性:
每个实例有自己的变量,称为实例变量(也叫属性)
示例:

class Persion(object):
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    def eating(self):
        return '%s正在吃饭。。。' % (self.name)
    def __str__(self):
        return f'姓名:{self.name} 年龄:{self.age} 性别:{self.gender}'
#创建一个示例对象:
p1=Persion('小枫','19','男')
#实例属性
print(p1.name)#小枫
print(p1.age)#19
p1.age=18
print(p1.age)#18

上述代码中的p1.name和p1.age就是实例对象的属性,他们可以通过键值的方式对属性值进行修改
实例方法:
实例方法就是函数,至少有一个指向实例对象的形参self
基本格式:

class 类名(继承列表):
    def 实例方法名(self, 参数1, 参数2, ...):
        "文档字符串"
        语句块

示例:

class Persion(object):
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    def eating(self):
        return '%s正在吃饭。。。' % (self.name)
    def __str__(self):
        return f'姓名:{self.name} 年龄:{self.age} 性别:{self.gender}'

p1=Persion('小枫','19','男')
print(p1)
print(p1.eating())
p2=Persion('追风','22','男')
print(p2)
print(p2.eating())

输出结果:

姓名:小枫 年龄:19 性别:男
小枫正在吃饭。。。
姓名:追风 年龄:22 性别:男
追风正在吃饭。。。

上述def eating(self)就是实例方法,根据我们讲过的self这里的方法调用参数self是用于实例化对象的

类属性和类方法定义

  • 类属性是类的属性,此属性属于类,不属于此类的实例
  • 作用:
    • 通常用来存储该类创建的对象的共有属性
  • 类属性说明
    • 类属性,可以通过该类直接访问
    • 类属性,可以通过类的实例直接访问
  • 类属性示例:
class Human:
    total_count = 0  # 创建类属性  self.name = name
    def __init__(self, name):
        self.name = name

print(Human.total_count)
h1 = Human("小张")
print(h1.total_count)
  • 类方法是用于描述类的行为的方法,类方法属于类,不属于该类创建的对象

  • 说明

    • 类方法需要使用@classmethod装饰器定义
    • 类方法至少有一个形参用于绑定类,约定为 cls
    • 类和该类的实例都可以调用类方法
    • 类方法不能访问此类创建的对象的实例属性
  • 类方法示例:

class A:
    v = 0
    @classmethod
    def set_v(cls, value):
        cls.v = value
    @classmethod
    def get_v(cls):
        return cls.v
print(A.get_v())
A.set_v(100)
print(A.get_v())
a = A()
print(a.get_v())

类属性和类方法应用场景

通过类方法改变类属性的值

示例:

class BankAccount:
    #类属性最开始定义的全局变量(利率)
    inserest_rate = 0.05
    #对象属性初始化(定义对象时初始化)
    def __init__(self, balance):
        self.balance = balance
    #对象方法(计算获利后的账户金额)
    def get_inserest_balance(self):
        return self.balance*(1+self.inserest_rate)
    #类方法(改变类中利率的数值)改变类中全局变量,可以通过类直接调用,依然可以通过对象调用不过改变的时类的属性值
    @classmethod
    def set_inserest_rate(cls, inserest_rate):
        cls.inserest_rate = inserest_rate
        return cls.inserest_rate
    #类中的静态方法可通过类直接调用,也可以通过对象调用
    @staticmethod
    def add(account, amount):
        return account+ amount

Account1 = BankAccount(10000)
print(Account1.inserest_rate)
print(Account1.get_inserest_balance())
BankAccount.set_inserest_rate(0.15)
print(Account1.inserest_rate)
print(Account1.get_inserest_balance())
print(Account1.add(Account1.get_inserest_balance(), 100))
Account2 = BankAccount(100000)
print(Account2.inserest_rate)#0.15因为BankAccount.set_inserest_rate(0.15)将类中的类属性改变

上述代码中BankAccount.set_inserest_rate(0.15)改变了类属性利率的属性值inserest_rate,所以子最后计算Account2
的利率值也为0.15
输出结果如下:

0.05
10500.0
0.15
11500.0
11600.0
0.15

应用于工厂模式:

class Dog:
    def __init__(self, name, color, age, **kwargs):
        self.name = name
        self.color = color
        self.age = age

    def eat(self, food):
        print(self.name, '正在吃', food)

    def speak(self):
        print(self.name, '正在叫')

    def run(self):
        print(self.name, '正在跑')

class Cat():
    def __init__(self, name, color, age, **kwargs):
        self.name = name
        self.color = color
        self.age = age

    def eat(self, food):
        print(self.name, '正在吃', food)

    def speak(self):
        print(self.name, '正在叫')

    def run(self):
        print(self.name, '正在跑')


class Animal():
    
    @classmethod
    def create(cls, info):
        if info['type'] == 'Dog':
            return Dog(**info)
        elif info['type'] == 'Cat':
            return Cat(**info)
info1 = {
    'name':'京巴',
    'color':'黑白',
    'age':10,
    'type':'Dog'
}
info2 = {
    'name':'小猫',
    'color':'灰白',
    'age':10,
    'type':'Cat'
}
animal1 = Animal.create(info1)
animal1.run()
animal2 = Animal.create(info2)

animal2.eat('小鱼')

通过这种模式可以根据要求快速的构建业务的数据结构

魔术方法以及常用方法

魔术方法是一种特殊的方法,用双下划线包裹,例如__init____str____add__等。这些方法允许您自定义类的行为,以便与内置Python功能(如+运算符、迭代、字符串表示等)交互。
这里我们用一些示例来解释:
通过魔术方法实现两个对象的值相加:

class Number:
    def __init__(self,value):
        self.value=value
    def __str__(self):
        return str(self.value)
    def __add__(self,other):
        return Number(self.value+other.value)
number1=Number(3)
number2=Number(4)
print(number1+number2)
#输出结果为7

通过魔术和普通方法实现对列表对象的增删改:

class List:
    def __init__(self,value):
        self.items=value
        self.len=len(self.items)
        #打印时返回数值
    def __str__(self):
        return str(self.items)
    #返回对象的长度
    def __len__(self):
        return len(self.items)
    #通过索引删除对象的值
    def __delitem__(self, key):
        del self.items[key]
    #删除对象
    def __del__(self):
        del self
    #通过索引访问对象的值
    def __getitem__(self,key):
        return self.items[key]
    #通过索引改变访问对象的值
    def __setitem__(self, key, value):
        self.items[key] = value
    #在对象列表后添加元素的普通方法
    def append(self,value):
        self.items.append(value)
lst=List([1,2,3,4])
print(lst)
print(len(lst))
del lst[0]
print(lst)
# del lst.value
print(lst[1])
lst[0]=9
lst.append(9)
print(lst)

输出结果如下:

[1, 2, 3, 4]
4
[2, 3, 4]
3
[9, 3, 4, 9]

还有更多常用的魔术方法如下:

  1. __init__(self, ...): 初始化对象,通常用于设置对象的属性。
  2. __str__(self): 定义对象的字符串表示形式,可通过str(object)print(object)调用。例如,您可以返回一个字符串,描述对象的属性。
  3. __repr__(self): 定义对象的“官方”字符串表示形式,通常用于调试。可通过repr(object)调用。
  4. __len__(self): 定义对象的长度,可通过len(object)调用。通常在自定义容器类中使用。
  5. __getitem__(self, key): 定义对象的索引操作,使对象可被像列表或字典一样索引。例如,object[key]
  6. __setitem__(self, key, value): 定义对象的赋值操作,使对象可像列表或字典一样赋值。例如,object[key] = value
  7. __delitem__(self, key): 定义对象的删除操作,使对象可像列表或字典一样删除元素。例如,del object[key]
  8. __iter__(self): 定义迭代器,使对象可迭代,可用于for循环。
  9. __next__(self): 定义迭代器的下一个元素,通常与__iter__一起使用。
  10. __add__(self, other): 定义对象相加的行为,使对象可以使用+运算符相加。例如,object1 + object2
  11. __sub__(self, other): 定义对象相减的行为,使对象可以使用-运算符相减。
  12. __eq__(self, other): 定义对象相等性的行为,使对象可以使用==运算符比较。
  13. __lt__(self, other): 定义对象小于其他对象的行为,使对象可以使用<运算符比较。
  14. __gt__(self, other): 定义对象大于其他对象的行为,使对象可以使用>运算符比较。
  15. __call__(self, other) 是一个特殊的方法(也称为“魔法方法”),它允许一个对象像函数一样被调用。

总结

本文讲解了如何掌握 Python 类和对象的基本语法,还带你深入底层,了解 Python 面向对象的实现原理,并且通过面向对象编程的方式带你了解类与对象的属性方法以及应用场景,并通过魔术方法实现面向对象的部分逻辑实现

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐