Python面向对象之类详解

本文详细介绍了Python面向对象编程的概念,包括类和实例的定义、普通方法、类方法、静态方法以及魔术方法的使用。强调了self参数的重要性,类属性和实例属性的区别,以及如何通过__init__、__del__等魔术方法实现对象的初始化和销毁。同时,还讨论了静态方法和类方法在类中的角色和调用规则,并通过案例展示了如何在实际编程中应用这些概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一. 类和实例

面向对象最重要的概念就是类(class)和实例(instance),类是抽象的模板,比如学生这个抽象的事物,可以用一个Student类来表示。而实例是根据类创建出来的一个个具体的“对象”,每一个对象都从类中继承有相同的方法,但各自的数据可能不同。

类的结构在大的方向上分为两部分

  • 静态变量
  • 动态方法

对象是从类中出来的,只要是类名加上(),这就是实例化的过程,就会实例化一个对象。
实例化的过程

  • 在内存中开辟一个对象空间
  • 自动执行类中的__init__方法,并将这个对象空间(内存地址)传给__init__()
  • 方法的第一个位置参数self 在__init__方法中通过 self 给对象空间添加属性

类的定义和调用

class Chinese(object):     ##(Object)表示该类从哪个类继承下来的,Object类是所有类都会继承的类。
    color = "yellow"      # 这里定义一个数据属性

    def make_money():     # 定义函数属性
        print("Can make money...")

    def impolite(self):
        print("Do something is impolite")

print(Chinese.color)      # 这种加上 . 的调用形式,本质上就是在属性字典中调用
Chinese.make_money()

print(dir(Chinese))       # 查看所有的变量(列表的形式)

print(Chinese.__dict__)   # 查看属性字典(包含数据属性和函数属性)
print(Chinese.__dict__["color"])
Chinese.__dict__["make_money"]()       # 这样就相当于直接去调用make_money函数
Chinese.__dict__["impolite"](Chinese)  # 这样调用impolite函数,因为这个函数中接受一个self参数,所以要将Chinese传入

print(Chinese.__name__)   # 显示类名
print(Chinese.__doc__)    # 类中的文档
print(Chinese.__module__) # 显示类所在的模块

在这里插入图片描述

二. 普通方法

  • 和普通数相比,在类中定义函数只有一点不同,就是第一参数永远是类的本身实例变量self,并且调用时,不用传递该参数。除此之外,类的方法(函数)和普通函数没啥区别
  • self代表类的实例,而非类
  • 在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。

对于属性的查找规则

  • 对象查找属性的顺序:对象空间栈 ——> 类空间栈 ——> 父类空间栈
  • 类名查找属性的顺序:本类空间栈 ——> 父类空间栈 ——> …

初始化方法:
类名() 就可以创建一个对象 类名() 创建对象的时候,python解释器会自动执行以下操作

  1. 为对象在内存中分配空间–创建对象
  2. 调用初始化方法为对象的属性设置初始值 这个初始化方法是内置方法,是专门用来定义一个类据有哪些属性和方法的

定义一个类

class Person:
	name = '张三'
	def __init__(self, name, age):   #这里涉及初始化方法,会在魔术方法部分详述
		self.name = name
		self.age = age
	def eat(self, food):
		print('{}正在吃{} !。。。'.format(self.name, food))
	def run(self):
		print('{},今年}岁,正在跑步'.format(self.name, self.age))

进行调用

p = Preson()
print(p)

使用 类名() 创建对象,创建对象 的动作有两步:

  • 在内存中为对象 分配空间
  • 调用初始化方法 init 为 对象初始化
  • 创建出来的 对象 叫做 类 的 实例
  • 创建对象的 动作 叫做 实例化
  • 对象的属性 叫做 实例属性
  • 对象调用的方法 叫做 实例方法
  • 每一个对象 都有自己 独立的内存空间,保存各自不同的属性

  • 多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部

在这里插入图片描述

类属性的增删改查

# 查看类属性
print(Person.name)

# 增加
Person.age = 20
print(Person.age)

# 修改类属性
Person.name = "Bob"
print(Person.name)

# 删除类属性
del Person.name

# 给类增加一个函数属性
def working(self, work):
    print("Now, %s is eating %s" %(self.name, work))
# 在类中添加一个eat的方法,其地址指向eating函数的地址

实例属性的增删改查

p1 = Person("hgzero", "male") # 创建一个实例
print(p1.__dict__)             # 查看实例的字典

# 查看
print(p1.name)

# 增加
p1.age = 21                    # 这里的age是被加入到了实例的字典中
print(p1.__dict__)
print(p1.age)

#不建议去直接修改属性字典结构
# 这些属性的添加和修改删除无非就是通过操作底部的字典实现的,但是不建议直接去修改属性字典结构
p1.__dict__['sex'] = 'male'
print(p1.__dict__)
print(p1.sex)


# 修改
p1.age = 23
print(p1.__dict__)
print(p1.age)

# 删除
del p1.age
print(p1.__dict__)

在这里插入图片描述

三. 类方法

  • 在程序运行时,类 同样 会被加载到内存

  • 在 Python 中,类 是一个特殊的对象 —— 类对象

  • 在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例

  • 除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法

  • 通过 类名. 的方式可以 访问类的属性 或者 调用类的方法

在这里插入图片描述

  • 类属性 就是针对 类对象 定义的属性

  • 使用 赋值语句 在 class 关键字下方可以定义 类属性

  • 类属性 用于记录 与这个类相关 的特征

  • 类方法 就是针对 类对象 定义的方法

  • 在 类方法 内部可以直接访问 类属性 或者调用其他的 类方法

class Dog:

	def __init__ (self, nickname) :
		self.nickname = nickname
	def run(self):
		print('{}在院子里跑来跑去!'.format(self.nickname))
	def eat(self) :
		print('吃饭。。')
		self.run()    #类中方法的调用,需要通过self.方法名
	@classmethod
	def test(cls):   #cls class
		print(cls)   # <class


#类方法
特点:
1.定义需要依赖装饰器@classmethod
2.类方法中参数不是一个对象,而是类
print(cls) # <class’__ main_. Dog’ >
3. 类方法中只可以使用类属性
4. 类方法中可否使用普通方法? 不能

类方法作用:
因为只能访问类属性和类方法,所以可以在对象创建之前,如果需要完成一些动作 (功能)

def show(self) :
	print( --------->,Person.age)
@classmethod
def update_age(cls):
	cls.__age = 20
	print( --------->类方法”)
@classmethod
def show_age(cls) :
	print('修改后的年龄是:',cls.__age)


Person.update_age()
Person.show_age()
class Phone:
	brand = xiaomi
	price = 4999
	type = 'mate 80'

	def call(self) :
		print('self---->', self)
		print('正在打电话..')
		print('留言')
phone1 = Phone ()
phone1.note ='我 是phonel的note'
print (phone1,'1')
phone1.call()
print('*'*30)
phone2 = Phone()
phone2.note ='我是phone22222222的note'
print(phone2,'2')
phone2.call()
#补充类方法
cLass.Person:
	__age = 18
	def shew(self):
		print( '------〉', Person.age)

	@classmethod
	def update_age(cls) :
		cls.__age = 20
		print('--------->类方法')

	@classmethod
	def show_age(cls) : 
		print('修改后的年龄是:',cls.__age)

  • 类模板就是我们所定义的类。在普通情况下,不使用类方法对类进行实例化,类本身是不具有记忆性的。只是当一个静态模板被套用多次而已。如果我们想让类在每一次实例化之后,都能记载一些记忆,是否会对很多操作很有用?
class Man:
    id = 0 # 类变量
    def __init__(self, name):
        self.name = name
        self.id = self.id_number()
 
    @classmethod
    def id_number(cls):
        cls.id += 1
        return cls.id
 
a = Man('A')
print(a.id)
b = Man('B')
print(b.id)

在这里插入图片描述

我对Man这个类进行实例化2次,每个实例的id都不一样。这就依靠类方法来实现了:首先,用@classmethod描述类方法,然后用"cls"代表本类。类方法对类属性进行的处理是有记忆性的。

需要注意的是,类方法处理的变量一定要是类变量。因为在类方法里你用不了self来寻址实例变量,所以需要把类变量放到最前面描述,如上面的"id=0"所示。类变量是可以被self访问的,所以,在类变量定义好了以后,不需要在_init_函数里对类变量再一次描述。所以,上面代码里self.id不一定需要。

摘自 python中的类方法(@classmethod)
在这里插入图片描述

四. 静态方法

静态方法:很类似类方法

  1. 需要装饰器@staticmethod
  2. 静态方法是无需传递参数(cls, self)
  3. 也只能访问类的属性和方法,对象的是无法访问的
  4. 加载时机同类方法
  • 既 不需要 访问 实例属性 或者调用 实例方法
  • 也 不需要 访问 类属性 或者调用 类方法
  • 静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法

普通方法与两者区别:
不同:

  1. 没有装饰器
  2. 普通方法永远是要依赖对象,因为每个普通方法都有一个self
  3. 只有创建了对象才可以调用普通方法,否则无法调用。

在这里插入图片描述

五. 魔术方法

普通方法需要调用,而魔术方法是在特定的时刻触发

__init__ :         构造函数,在生成对象时调用
__del__ :          析构函数,释放对象时使用
__repr__ :         打印,转换
__setitem__ :      按照索引赋值
__getitem__:       按照索引获取值
__len__:           获得长度
__cmp__:           比较运算
__call__:          函数调用
__add__:           加运算
__sub__:           减运算
__mul__:           乘运算
__truediv__:       除运算
__mod__:           求余运算
__pow__:           乘方

下面详细讲解比较常用的几个魔术方法

init

  • __init__方法的第一参数永远是self,表示创建的类实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
  • 有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器会自己把实例变量传进去
  • 这里self就是指类本身,self.name就是Student类的属性变量,是Student类所有。而name是外部传来的参数,不是Student类所自带的。故,self.name = name的意思就是把外部传来的参数name的值赋值给Student类自己的属性变量self.name。

new

class Person:
    def __init__(self):
        print('------>init')
        print('self =',self)
    def __new__(cls, *args, **kwargs):
        print('------>new')
        position = object.__new__(cls,*args,**kwargs)
        print('position =',position)
        return position
p = Person()
print('p =',p)

在这里插入图片描述

  • new的作用就是开辟内存空间,并返回内存地址给init,最后给p实例
  • 以上相当于重写子类的new方法,所有子类默认继承object类,所以也默认执行object的new方法

call

将对象当做函数调用

class Person:
    def __init__(self):
        print('------>init')

    def __call__(self, *args, **kwargs):
        print('-------->call')
        print('执行对象得到的参数是',args)
p = Person()
p('hello')

在这里插入图片描述
del

析构魔术方法
当对象没有任何变量引用的时候触发

如果希望在对象被销毁之前,再做一些事情,可以考虑一下__del__ 当一个对象被从内存中销毁前(把这个对象从内存中删除掉), 会自动调用__del__方法

import sys

class Person:
    def __init__(self,name):
        self.name = name
        print('------>init')
p = Person('jack')
p1 = p
p2 = p
print(p1.name)
print(p2.name)
print('p =',p)
print('p1 =',p1)
print('p2 =',p2)
print(sys.getrefcount(p))

在这里插入图片描述

p,p1,p2都指向同一个地址

p.name='tom'
print(p1.name)
print(p2.name)

在这里插入图片描述

  • 一旦其中一个实例发生更改,就会改变该实例指向地址的值,其他两个实例的值也会改变。
  • 比如老大把家里的旧电视换成新的,老二和老三看到的电视是新的。
del p2  #删除引用的时候调用del方法
print('删除p2后','p =',p.name,'引用的个数:',sys.getrefcount(p))

del p1
print('删除p1后','p =',p.name,'引用的个数:',sys.getrefcount(p))

在这里插入图片描述

  • del删除的只是地址的引用,并没有删除那个地址
  • 如果把p也删除了,python解释器就会回收该地址空间

str

  • 在python中 使用print输出对象变量时候,默认情况下 ,会输出这个变量引用的对象是由哪一个类创建的对象以及在内存中的地址
  • 如果在开发中,希望使用print输出变量的时候,能够打印自定义内容 就可以利用__str__这个内置的方法了
class Person:
    def __init__(self,name):
        self.name = name

    def __str__(self):
        return '姓名是:'+self.name+', 其他详细信息....'

p = Person('jack')
print(p)

在这里插入图片描述

  • 打印该类的其他信息,即编写程序的人想告诉其他人的信息
  • return后面的内容才是输出的信息

六. 案例解析

属性:

  • 定义一个 类属性 top_score 记录游戏的 历史最高分

  • 定义一个 实例属性 player_name 记录 当前游戏的玩家姓名

方法:

  • 静态方法 show_help 显示游戏帮助信息

  • 类方法 show_top_score 显示历史最高分

  • 实例方法 start_game 开始当前玩家的游戏

class Game(object):

    # 游戏最高分,类属性
    top_score = 0

    @staticmethod
    def show_help():
        print("帮助信息:让僵尸走进房间")
        
    @classmethod
    def show_top_score(cls):
        print("游戏最高分是 %d" % cls.top_score)

    def __init__(self, player_name):
        self.player_name = player_name

    def start_game(self):
        print("[%s] 开始游戏..." % self.player_name)
        
        # 使用类名.修改历史最高分
        Game.top_score = 999

# 1. 查看游戏帮助
Game.show_help()

# 2. 查看游戏最高分
Game.show_top_score()

# 3. 创建游戏对象,开始游戏
game = Game("小明")

game.start_game()

# 4. 游戏结束,查看游戏最高分
Game.show_top_score()

摘自 Python 类属性和类方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值