简易的Python面向对象教程

前言

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取

python免费学习资料以及群交流解答点击即可加入


实例属性和类属性

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

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

也可以在后续代码中通过实例名再额外添加,比如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)。

类属性不能通过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,还有自加(+=),自减(-+)运算符,不熟悉请自行补充相关知识,或者加入讨论群讨论。

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。
  • 调用静态方法通过类名。

猜你喜欢

转载自blog.csdn.net/pythonxuexi123/article/details/112849702
今日推荐