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.xself.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()             #通过实例来调用类方法

输出:

调用了静态方法
调用了类方法
调用了静态方法
调用了类方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

[小G]

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值