python 判断类是否有某个属性_【3】类属性,类方法 - 简易的Python面向对象教程...

d680b9d28799248d3509140ffec20b16.png

实例属性和类属性

在下面的例子中,Dog类的属性,比如height(身高),是属于一条具体的狗,如大黄,二黑等。他们各自有各自的height。

这种属性我们成为实例属性,实例属性通常是在init方法中通过http://self.xxx = yyy的形式创建的。在init中创建的实例属性的好处是,所有的实例都有这些实例属性。

b3c4e94c85e8478ad0f24f14725de24c.png

也可以在后续代码中通过实例名再额外添加,比如d1.nickname = '二黑子',但这种实例属性只给当前实例d1添加了。其他实例没有,访问d2.nickname会报错。

class Dog:
 #构造方法
 def __init__(self, name, height, power):
  self.name = name
  self.height = height
  self.power = power
  self.blood = 10
  # --省略--

d1 = Dog('大黄', 0.7, 3) #创建第1个实例
d2 = Dog('二黑', 0.5, 4) #创建第2个实例

还有一些属性,它们不属于一个特定的实例,而是所有的实例所共享的。比如狗的数量这个值,他是属于整个狗类的,而不是属于某一条狗。这种属性,我们称为类属性

添加类属性

我们现在给Dog类添加狗的数量属性(num_of_dogs)。

类属性不能通过http://self.xxx = yyy的形式创建,因为这样创建出来的是实例属性。

类属性的创建方式很简单:直接写在类中,不要写在init函数中,也不要加self.

#类是一个模板
class Dog:
 num_of_dogs = 0  # 类属性

 #构造方法 - 添加实例属性,做其他的初始化工作
 def __init__(self, name, height, power):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
        print(f"{self.name}出生了,汪汪!")

使用类属性

类属性是属于类的,访问类属性要通过类名访问。下面的代码做了几件事情:

  1. 在init函数中,一旦创建一个新的Dog,给num_of_dogs加一.
  2. 添加了一个die()方法,表示一个Dog去世了,一旦调用了die(),num_of_dogs就会减1。
  3. 创建了多个dog,测试numer_of_dogs数量变化;循环30次,随机选择一个Dog,调用die方法。

这里用到了随机模块random,还有自加(+=),自减(-+)运算符,不熟悉请自行补充相关知识,或者加入讨论群讨论。

本案例有点血腥,请动物爱好者不要入戏太深,一切为了学习编程。可以把Dog改成其他,比如蟑螂(小强)。说到这里,我好想念我曾经的那些狗狗 。
import random

#类是一个模板
class Dog:
    num_of_dogs = 0  # 类属性

 #构造方法 - 添加实例属性,做其他的初始化工作
    def __init__(self, name, height, power):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
        print(f"{self.name}出生了,汪汪!")
        Dog.num_of_dogs += 1
    
    def die(self):
        print(f"{self.name}已安息!")
        Dog.num_of_dogs -= 1

# 创建100条狗,放到列表中
dogs = []
for i in range(100):
    d = Dog(f"dog{i}", random.randint(30, 80), random.randint(1,12))
    print(Dog.num_of_dogs)
    dogs.append(d)

# 循环30次,每次随机选择一条狗,让它死掉
for i in range(30):
    dog = random.choice(dogs)
    dog.die()
    print(Dog.num_of_dogs)

再加1个类属性

假设我们要判定一条狗是否可以成为警犬,我们用身高height来判定,如果height超过了60就可以。这个60就是警犬的标准。这个数字是对所有的Dog是通用的,是一个类属性。

import random

#类是一个模板
class Dog:
    num_of_dogs = 0  # 类属性
    police_height = 60 # 成为警犬的身高标准

    # --省略init和die方法

    # 判定是否可以成为警犬,返回True或者False
    def can_be_police(self):
        return self.height > Dog.police_height

# 创建100条狗,放到列表中
dogs = []
for i in range(100):
    d = Dog(f"dog{i}", random.randint(30, 80), random.randint(1,12))
    print(Dog.num_of_dogs)
    dogs.append(d)

print(f'成为警犬的身高标准是:{Dog.police_height}')
for d in dogs:
    if(d.can_be_police()):
        print(f'{d.name} 可以成为警犬')

代码说明:

  • 添加了一个police_height类变量
  • 添加了一个实例方法,判定当前的dog是否可以成为警犬
  • 代码最下方打印出可以成为警犬的狗的名字

代码实践技巧

你可能会想,这个60直接写在代码里不可以吗?还要定义成变量?

直接写数字60不是不可以,但有诸多弊端:

  • 多个地方用到,可能会写错,出现不一致。
  • 如果标准从60提高到了62,要修改多个地方
  • 定义成了变量,代码更容易懂。要不然看到60个这个数字,不一定理解是什么意思。

实际上,polic_height通常不会改变,我们也可以称他为常量

常量和变量没什么区别,一般常量的名字都是全大写的,仅此而已。看到全大写就知道这个值是不会改变的,实际上是可以改变的,只是一个约定。

这里的不会改变是指不会在程序运行中动态改变。把常量的值从60改成62属于修改代码,任何时候都可以的。

类方法

仔细看一下前面定义的方法,他们都有两个特征:

  • 方法的第一个参数都是self
  • 它们都使用了实例变量,脱离了具体的实例,这些方法是无法运行的,是没有意义的

这些方法虽然都是共同的,但是他们的运行过程依赖了实例变量,所以他们都是实例方法。类中的方法默认就是实例方法。

import random

#类是一个模板
class Dog:
    num_of_dogs = 0  # 类属性
    police_height = 60 # 成为警犬的身高标准

 #构造方法 - 添加实例属性,做其他的初始化工作
    def __init__(self, name, height, power):
        self.name = name
        self.height = height
        self.power = power
        self.blood = 10
        print(f"{self.name}出生了,汪汪!")
        Dog.num_of_dogs += 1
    
    def die(self):
        print(f"{self.name}已安息!")
        Dog.num_of_dogs -= 1

    # 判定是否可以成为警犬,返回True或者False
    def can_be_polic(self):
        return self.height > Dog.police_height

这3个方法都是实例属性有关,都是实例方法。

但有的方法和具体的实例无关,而是和整个狗类有关。比如有方法狗类宣言,它的功能是:

  • 打印狗类宣言
  • 介绍狗类的数量

看代码:

import random

#类是一个模板
class Dog:
    num_of_dogs = 0  # 类属性
    police_height = 60 # 成为警犬的身高标准

    #--省略--
    
    # 类方法
    @classmethod 
    def wangwang(cls):
        print('我们是狗,我们是人类的朋友')
        print('''
^..^      /
/_/_____/
/   /
/   /  
        ''')
        print(f'我们共有{cls.num_of_dogs}个成员')

# --省略--    

Dog.wangwang()

代码说明:

  • 添加的类方法wangwang()
  • 类方法的前面要添加:@classmethod。这是一个装饰器。不懂装饰器?请看本文最后的文章列表。
  • 类方法的第一个参数是cls,是class的缩写,表示当前类。使用cls可以访问类属性或者其他类方法。
  • 调用类方法使用类名:Dog.wangwang()

静态方法

我们可以看到类方法对类属性有所依赖,有些方法对实例属性和类属性都没有依赖,也不需要传入self或者cls,这些方法就是静态方法。

假设我们有另外几个方法:只是打印狗类的字符画,不用打印狗的数量或者其他。没有任何类属性或者实例属性的依赖。

看代码:

import random

#类是一个模板
class Dog:
    num_of_dogs = 0  # 类属性
    police_height = 60 # 成为警犬的身高标准

    # --省略--
    
    # 类方法
    @classmethod 
    def wangwang(cls):
        print('我们是狗,我们是人类的朋友')
        print('''
^..^      /
/_/_____/
/   /
/   /  
        ''')
        print(f'我们共有{cls.num_of_dogs}个成员')

    #静态方法:小狗的图像
    @staticmethod
    def pic_little():
        print('''
  /^ ^ 
 / 0 0  
 V Y /V
  / -  
 /    |
V__) ||
        ''')

    #静态方法:大狗的图像
    @staticmethod
    def pic_big():
        print('''
    ___
 __/_  `.  .-"""-.
 _,` | -'  /   )`-')
  "") `"`      ((`"`
 ___Y  ,    .'7 /|
(_,___/...-` (_/_/ 
        ''')
    
    #静态方法:长的图像
    @staticmethod
    def pic_long():
        print('''
                                    .-.
     (___________________________() `-,
     (   ______________________   /''"`
     //                      //
     "" ""                     "" ""

        ''')


#--省略--

Dog.wangwang()
Dog.pic_little()
Dog.pic_big()
Dog.pic_long()

代码说明:

  • 添加了3个静态方法,分别打印3种不同的狗的图像
  • 静态方法前面必须加:@staticmethod,这是一个装饰器。不懂装饰器,看本文最后的文章列表。
  • 静态方法不强制要求传入self或者cls。
  • 调用静态方法通过类名。

练习:

今天的练习:

1. 给Dog类添加一个类属性dog_list,它是一个列表,用来保存所有创建出来的类。
2. 修改init函数,把每个新建的Dog添加到dog_list中。
3. 修改die函数,从dog_list中移除去世的Dog。
4. 删掉num_of_dogs属性,添加一个类方法num_of_dogs,返回狗的数量。提示:通过dog_list的长度确定狗的数量。
5. 修改所有值钱用到num_of_dogs的地方,改成使用新定义的方法,而不是变量名。

下一节课学习继承,请保持关注!

https://mp.weixin.qq.com/s/yDOv4z_iw8rXX_i2s2Kj1Q​mp.weixin.qq.com

你可以在文章下面打卡,分享你的看法。

我是麦叔:教你学编程,陪你走职场的路!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值