inullbyte 发表于 2021-1-9 15:22

【笔记08】类与对象,武装到牙齿

欢迎来到我的《Python 扫盲栏目》,力求用最短的时间,最简明的文字,让你了解、掌握 Python 基础语法。

我分享的笔记都是自己学习时的记录整理而成,不保证有多厉害,但还是那两句话:

**不要嫌弃内容简陋,循序渐进嘛!**
**不要嫌弃知识简单,动手敲敲吧!**

第 0 期:[《做个尝试,从零到一》](https://www.52pojie.cn/thread-1316697-1-1.html)
第 1 期:[《铺石造路,我学会了输入输出》](https://www.52pojie.cn/thread-1317221-1-1.html)
第 2 期:[《玩转数据,这是第一步》](https://www.52pojie.cn/thread-1317496-1-1.html)
第 3 期:[《学会判断,告诉电脑怎么做》](https://www.52pojie.cn/thread-1318454-1-1.html)
第 4 期:[《数据升级,列表字典能处理》](https://www.52pojie.cn/thread-1319099-1-1.html)
第 5 期:[《打破重复,循环解放双手》](https://www.52pojie.cn/thread-1330081-1-1.html)
第 6 期:[《亦真亦假,布尔值和四种语句》](https://www.52pojie.cn/thread-1335850-1-1.html)
第 7 期:[《制造轮子,函数反复调用》](https://www.52pojie.cn/thread-1340000-1-1.html)
第 8 期:《类与对象,武装到牙齿》

---

# 两种编程思维

面向过程编程看重的是解决问题的过程,它通过分析解决问题所需要的步骤,然后按照这些步骤来解决问题。

而面向对象直接面对的是帮我们解决问题的东西(对象),而不是解决问题这一过程。

面向过程编程主要使用函数的知识,而面向对象则主要使用类与对象的知识。

其中,类是对象的母系,只有拥有了类,才能创造各种对象。

# 什么是类?

我们可以把类理解成一个函数包,在类中直接存放着函数和变量,这样类中的函数就可以很方便的使用类中的变量。

我们要定义一个类需要使用 `class` 语句:

eg.

```python
# 类名一般首字母大写
class Dog():
    # 在类里面定义函数
    def function():
      ...
```

在类中被定义的函数被称为类的**方法**,方法描述了一个类可以作什么,我们使用 `类名.函数名()` 的方式就可以调用类的方法了。

同时,类中也可以存放很多变量:

eg.

```python
class Dog():
    color = yellow
    weight = 20
```

在类中被定义的变量被称为类的**属性**,使用`类名.变量名` 的方式就可以获得类的属性的值,而且可以对其进行修改和增加。

在类中定义函数和单独定义函数是有区别的,即类方法可以调用类属性。

eg.

```python
class Flag():
    num1 = 111
    num2 = 222
   
    @classmethod
    def put(cls):
      print(cls.num1)

Flag.put()
```

output:

> 111

在以上代码中:

- `@classmethod` 的作用是声明 put 是类方法,这样才能允许 put 使用类属性的数据。
- 如果 put 想要使用类属性的数据,就必须以cls 作为自己的第一个参数,即把这个类作为参数传递给 put,这样就能允许使用类属性的数据。
- 当类方法 put 想要使用类属性时,必须使用 `cls.变量名` 的方式。

**注意:**当类方法不需要使用类属性的数据时,就不能使用以上 3 点。

# 给类方法传参

函授都能传递参数,类方法也是可以传递参数的。

当类方法只使用外部参数:

eg.

```python
class Add():
    def add(num):
      sum = num + 1
      print(sum)
      
num = 1
Add.add(num)
```

output:

> 2

与函数不同,类方法还可以使用类属性作为参数,即类方法使用内部参数:

eg.

```python
class Read():
    paper = ['Are', 'U', 'OK!', 'Thank', 'U']
    @classmethod
    def read(cls):
      for i in cls.paper:
            print(i)
            
Read.read()
```

output:

> Are
>
> U
>
> OK!
>
> Thank
>
> U

类方法也可以同时使用内部参数和外部参数:

eg.

```python
class Add():
    num = 1
    @classmethod
    def add(cls, times):
      sum = cls.num + times
      print(sum)
      
times = 3
Add.add(times)
```

output:

> 4

# 增加/修改类属性

我们可以通过类方法和直接对类属性赋值进行修改增加。

从外部增加/修改类属性:

eg.

```python
class Add():
    pass
   
Add.num = 2
```

类 Add 是一个空类,使用 `Add.num = 2` 就可以给 Add 增加一个类属性 num,当然这种方法也可以用来修改类属性。

从内部增加/修改类属性:

eg.

```python
class Add():
    @classmethod
    def add_thing(cls):
      cls.thing = input('输入要增加的类属性名:')
      
Add.add_thing()
```

要从类的内部增加/修改类属性就得使用类方法来完成。

# 类与对象

类是对象的母版,要先有了类,才可以有对象,我们可以以类为模板,复制生成更多的实例对象,虽说类也可以说是对象,但并不是实例对象,从类变成实例对象的过程叫做实例化。

eg.

```python
class Score():
    def add_score(self):
      self.name = input('please input name: ')
      self.chinese = int(input('please input chinese: '))
      self.math = int(input('please input math: '))
    def draw(self):
      print(self.name + '的成绩:')
      print('Chinese: ' + str(self.chinese))
      print('Math: ' + str(self.math))

# 实例化对象
score_list1 = Score()
score_list2 = Score()
score_list3 = Score()

# 录入成绩
score_list1.add_score()
score_list2.add_score()
score_list3.add_score()

# 打印成绩
score_list1.draw()
score_list2.draw()
score_list3.draw()
```

当类被实例化后使用与直接使用类是不同的方式,直接使用类需要使用 `@classmethod` 声明类函数,而实例化后再使用不需要声明类函数,而且类函数需要带上 `self` 参数,变量也需要先赋值再调用。

- 直接使用类函数:

!(https://i.loli.net/2021/01/09/ftESVF3GirnBIZg.png)

- 实例化后再使用:

!(https://i.loli.net/2021/01/09/bUoy16l24Q7KFqn.png)

当我们打算实例化后再使用类,就必须先为类创建一个实例(也就是对象),再使用 `实例名.函数()` 的方式调用对应的方法。

Tips:`cls` 表示类,`self` 表示实例,但是这并不是强制要求,只需要有一个变量占位就行。

当类支持实例化时,`self` 是所有类方法位于第一位的、默认的一个特殊的参数,也就是在实例化之后,只要类中用了 def 语句定义函数,那么该函数的第一个参数都必须是 `self`。

并且,当类支持实例化时,不能再直接使用类方法,所以一般都是把类实例化之后再调用。

## 实例属性与类属性

当一个类完成实例化之后,对于一个实例的属性和方法被称之为实例属性和实例方法,不再称为类属性和类方法。

因为实例是通过复制类得到的,所以当一个类实例化为多个实例之后,实例的属性则与类属性完全一致。

如果我们修改类属性,所有由这个类实例化而来的实例的属性也将同步发生变化,但是如果我们只修改某一个实例的属性,其他实例以及类的属性将不会有任何变化,因为每个实例都是一个独立的个体。

## 实例方法与类方法

和类属性一样,如果我们修改类方法,所有实例方法也会同步变化。

如果要重写类方法有两个步骤:

1. 在类外部写一个函数
2. 把新函数名赋值给 `类.原始函数`

!(https://i.loli.net/2021/01/09/osRUxDYeynPOLGu.png)

**注意:**这里重写类方式是在对类方法进行替换,而不是调用函数,所以只能是 `类.原始函数 = 新函数` 而不是 `类.原始函数() = 新函数()`。

我们可以重写类方法,但是并不能重写实例方法。

## 初始化函数

初始化函数是一个很使用的类方法:

eg.

```python
class 类():
    def __init__(self):
      print('实例化成功!')

实例 = 类()
```

初始化函数的意思是,当你创建一个实例的时候,这个函数就会被调用,所以当 `实例 = 类()` 被执行时,`__init__()` 函数就被调用了。

`__init__(self)` 是初始化函数的固定格式,不能改变,而且这个初始化函数一样的可以传递参数。

eg.

```python
class Score():
    def __init__(self, name, chinese, math):
      self.name = name
      self.chinese = chinese
      self.math = math

    def draw(self):
      print(self.name + '的成绩单如下:')
      print('chinese:'+ str(self.chinese))
      print('math:'+ str(self.math))


Score1 = Score('张三',99,88)
Score2 = Score('李四',64,73)
Score3 = Score('王五',33,22)

Score1.draw()
Score2.draw()
Score3.draw()
```

这里的初始化函数 `__init__(self, name, chinese, math)`,会在实例化时自动创建实例属性。

# 继承

继承可以避免很多重复代码的编写。

eg.

```python
class Father():
    def __init__(self, num):
      self.num = num
    def out(self):
      print('数字是:')
      print(self.num)
      
class Son(Father):
    pass

new_son = Son(123)
new_son.out()
```

子类可以直接继承父类的所有类方法,并且在父类的基础上定义新的类方法,同时也可以直接覆盖父类的类方法,只需要在子类中使用与父类相同的方法名进行定义就可以了。

当子类只从一个父类处继承类方法时,这叫单继承,当然还有多重继承,继承语句就是:`class 子类(父类1, 父类2, ..., 父类n)`。

**给个免费评分我能写得更好!**

Newzzz 发表于 2021-1-9 15:40

虽然看不懂,但是感觉很厉害。哈哈哈

lvcaolhx 发表于 2021-1-9 15:45

总是在这个内容上弄不明白

zz1181 发表于 2021-1-9 16:51

不明觉厉,谢谢
页: [1]
查看完整版本: 【笔记08】类与对象,武装到牙齿