8-2-类的属性和方法
三、类的属性和方法
上面我们定义了一个 MyClass
类,这个类只有一些说明信息,没有什么使用价值。要用来解决实际问题,就需要在其内部定义一些属性和方法。
1. 类的方法
用类来解决实际问题
类中方法的定义和调用与函数的定义、调用方式基本相同,区别在于:
- 方法的第一个参数必须是
self
,且不可省略 - 方法在调用前必须实例化类,调用形式为:
实例名.方法名(参数列表)
例一:
class SmplClass: #定义一个类SmplClass
def hello(self): #定义一个方法hello()
print('hello world')
def sum(self, x, y): #定义一个方法sum()
z = x + y
return z
#接下来是调用
sc = SmplClass() #实例化类
sc.hello() #调用方法hello()
a = sc.sum(1, 2) #调用方法sum()
print(a)
输出如下:
hello world
3
注意:
-
方法在调用时提供的参数不会分配给
self
-
定义方法时就像定义函数那样。
构造方法
另外,python中,可以定义一个特殊的方法 __init__()
,叫构造方法(构造在这里可不是动词,是名词),注意前后都有两个下划线,用于在类实例化时,初始化一些相关数据,如果这个 __init__()
方法有参数(除了self
),则在实例化时必须提供参数。
例二:
class Demo:
def __init__(self, x, y): #定义构造方法,有两个参数(不包含self)
self.a = x
self.b = y
def sum(self): #定义一个方法,没有参数,
c = self.a + self.b
return c
dia = Demo(11,22) #用2个参数实例化类
s = dia.sum()
print(s)
输出:
33
对于上面这个例子,看到第7行,有人可能会产生疑问,在sum()
方法中为什么可以引用构造方法__init__()
里面定义的函数,由于我也在学python,不能很清楚将这个问题讲明白。
不过,你只需要记住,带有 在类内部self
的变量,可以被这个类内部所有的方法使用,也就是说,在这个类内部,带self的变量相当于是这个类的”全局变量“。
在类内部调用函数或方法
在类内部,可以调用类外部的全局函数,也可以调用本类里面的方法。调用形式:
- 在类内部调用全局函数的形式与在类外部调用一样;
- 调用本类下的方法的形式:
self.方法名(参数列表)
。参数列表的参数不会分配给self
例三:(写个程序模拟坐标值变换)
def coord_chng(x,y): #定义全局函数
return (abs(x), abs(y)) #返回一个元组
class Ant:
def __init__(self, x=0, y=0): #定义构造方法,含有默认参数
self.x = x
self.y = y
self.disp_point() #调用本类内部的方法(在后面)
def move(self, x, y):
x, y = coord_chng(x, y)
self.edit_point(x, y)
self.disp_point()
def edit_point(self, x, y):
self.x = self.x + x
self.y = self.y + y
def disp_point(self):
print('当前位置:(%d, %d)'%(self.x, self.y))
ant_a = Ant() #实例化Ant()类,不提供参数,使用默认参数
ant_a.move(2, 4) #调用实例ant_a的方法move()
ant_a.move(-9, 6) #调用实例ant_a的方法move()
输出:
当前位置:(0, 0)
当前位置:(2, 4)
当前位置:(11, 10)
一般来说,为了方便程序阅读、理解、维护,函数或方法的行数不宜过多。
2. 类的属性
属性,可以把它理解为变量。上面这个例子(即例三)实际上就定义了Ant类的两个属性 self.x
和self.y
,它们是在构造方法中以直接赋值的方式定义的。因此,python中定义属性就是先直接使用它(如赋值给它),可以在构造方法中定义属性,也可以在类内部的其他方法中定义属性。
python中类的属性有两类:
-
实例属性
即同一个类的不同实例,其值是互不关联的。定义时使用
self.属性名
,调用时用实例名.属性名
。 -
类属性
类属性是同一个类的所有实例所共有的,直接在类体中直接定义,引用时要使用
类名.类变量名
的形式,只要是某个实例对其进行修改,就会影响其他所有这个类的实例。
例四:
先定义类:
class Demo:
class_name = 'Demo' #定义类属性(也叫类变量)
def __init__(self, x=1): #构造函数
self.x = x #实例属性
def class_info(self):
print('类变量值:',Demo.class_name) #输出类属性信息
print('实例变量值:',self.x) #输出实例属性信息
def chng(self, a): #定义修改实例属性的方法
self.x = a
def chng_cn(self, name): #定义修改类属性的方法
Demo.class_name = name
实例化:
dpa = Demo() #创建实例 dpa
dpb = Demo() #创建实例 dpb
修改前查看类属性和实例属性信息:
print('************修 改 前************')
print('dpa:')
dpa.class_info()
print('dpb:')
dpb.class_info()
#输出如下,可以看到dpa\dpb的类变量值和属性变量值都分别一样
************修 改 前************
dpa:
类变量值: Demo
实例变量值: 1
dpb:
类变量值: Demo
实例变量值: 1
修改dpa实例属性值:
print('******修改实例 dpa 的属性值******')
dpa.chng(222)
print('dpa:')
dpa.class_info()
print('dpb:')
dpb.class_info()
#输出如下,可以看到dpa\dpb的类变量值与之前一样,但dpa的属性变量值改变了,dpb的没变
******修改实例 dpa 的属性值******
dpa:
类变量值: Demo
实例变量值: 222
dpb:
类变量值: Demo
实例变量值: 1
修改dpb实例属性值:
print('******修改实例 dpb 的属性值******')
dpb.chng(444)
print('dpa:')
dpa.class_info()
print('dpb:')
dpb.class_info()
#输出如下,可以看到dpa\dpb的类变量值与之前一样,但dpa的属性变量值还是222,dpb的则变为444
******修改实例 dpb 的属性值******
dpa:
类变量值: Demo
实例变量值: 222
dpb:
类变量值: Demo
实例变量值: 444
上面这两次修改的都是实例属性值,可见,修改实例属性值不会影响类属性值,也不会影响另一个实例的属性值。
接下来修改类属性值:
从dpa进入修改类属性值
print('******从 dpa 修改类属性值******')
dpa.chng_cn('FFF')
print('dpa:')
dpa.class_info()
print('dpb:')
dpb.class_info()
#输出如下,从dpa入口修改类变量值,
#可以看到dpa\dpb的类变量值同时发生变化,但dpa的实例变量值还是222,dpb的实例变量值还是444
******从 dpa 修改类属性值******
dpa:
类变量值: FFF
实例变量值: 222
dpb:
类变量值: FFF
实例变量值: 444
从dpb进入修改类属性值:
print('******从 dpb 修改类属性值******')
dpb.chng_cn('GGG')
print('dpa:')
dpa.class_info()
print('dpb:')
dpb.class_info()
#输出如下,从dpb入口修改类变量值,
#可以看到dpa\dpb的类变量值同时发生变化,但dpa的实例变量值还是222,dpb的实例变量值还是444
******从 dpb 修改类属性值******
dpa:
类变量值: GGG
实例变量值: 222
dpb:
类变量值: GGG
实例变量值: 444
综上,类属性值只要在任一实例中被改变,其他实例的类属性值也会改变,因此,有时为了不让某个属性或方法在类外被调用或修改,可以在变量命名前使用双下划线 "__"
,但这不保证一定不能从类外调用,它只是一种标志。
3. 类成员方法与静态方法
类的属性有类属性和实例属性之分,类的方法也有不同种类,主要有:
- 实例方法
- 类方法
- 静态方法
前文定义的所有类的方法都是实例方法,其隐含调用的参数self
实际上就是类的实例;
类方法隐含调用参数cls
则是类;
静态方法没有隐含调用参数。
所以逻辑上,类方法被类调用(也可以被实例调用),实例方法被实例调用,静态方法两者都能调用。
如何定义
静态方法定义时要用装饰器(以后将会介绍)@staticmethod
进行修饰,它是没有默认参数的;
类方法定义时应使用装饰器 @classmethod
修饰,必须有默认参数 cls
例五:(演示如何定义类方法和静态方法)
class Demomthd: #定义一个类
@staticmethod #静态方法的装饰器
def sta_mth(): #静态方法没有隐含参数
print('调用了静态方法')
@classmethod #类方法的装饰器
def cla_mth(cla): #类方法有隐含参数cla
print('调用了类方法')
Demomthd.sta_mth() #未实例化类,通过类名来调用静态方法
Demomthd.cla_mth() #未实例化类,通过类名来调用类方法
dm = Demomthd() # 实例化类
dm.sta_mth() #通过实例来调用静态方法
dm.cla_mth() #通过实例来调用类方法
输出:
调用了静态方法
调用了类方法
调用了静态方法
调用了类方法
本文来自博客园,作者:aJream,转载请记得标明出处:https://www.cnblogs.com/ajream/p/15383603.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人