# 02_Python基础到实战一飞冲天(三)-python面向对象(二)--初始化方法和内置方法
## 一、初始化方法-01-在类的外部给对象增加属性的隐患
### 1、在类的外部给对象增加属性,会存在隐患。
1)如果**先调用方法 再设置属性**,观察一下执行效果,程序会报错。
```python
tom = Cat()
tom.drink()
tom.eat()
tom.name = "Tom"
print(tom)
```
2)程序执行报错如下:
```python
AttributeError: 'Cat' object has no attribute 'name'
属性错误:'Cat' 对象没有 'name' 属性
```
3)**提示**
* 在日常开发中,不推荐在 **类的外部** 给对象增加属性。
* 如果**在运行时,没有找到属性,程序会报错**。
* 对象应该包含有哪些属性,应该 **封装在类的内部**。
### 2、在类的外部给对象增加属性的隐患 示例 代码(dzs_04_在类的外部设置属性的问题.py)
```python
# dzs_04_在类的外部设置属性的问题.py
class Cat:
"""这是一个猫类"""
def eat(self):
# 由哪一个对象调用的方法,方法内的self就是哪一个对象的引用
# print("小猫爱吃鱼")
print("%s 爱吃鱼" % self.name)
def drink(self):
# print("小猫在喝水")
print("%s 在喝水" % self.name)
tom = Cat()
# 可以使用 .属性名 利用赋值语句就可以了,但要定义在方法调用之前
tom.name = "Tom"
tom.drink()
tom.eat()
print(tom)
# 如果在下面才定义属性,程序会报错
# tom.name = "Tom" #error
```
### 3、示例:
## 二、初始化方法-02-创建对象时自动调用初始化方法
### 1、初始化方法
1)当使用 `类名()` 创建对象时,会 **自动** 执行以下操作:
* 1. 为对象在内存中 **分配空间** —— 创建对象。
* 2. 为对象的属性 **设置初始值** —— 初始化方法(`init`)。
2)这个 **初始化方法** 就是 `__init__` 方法,`__init__` 是对象的**内置方法**。
### 2、 `__init__` 方法是 **专门** 用来定义一个类 **具有哪些属性的方法**!
### 3、示例 代码(dzs_05_初始化方法.py):
在 `Cat` 类中增加 `__init__` 方法,验证该方法在创建对象时会被自动调用。
```python
# dzs_05_初始化方法.py
class Cat:
"""这是一个猫类"""
def __init__(self):
print("初始化方法")
# 使用类名() 创建对象的时候,会自动调用初始化方法 __init__
tom = Cat()
```
### 4、示例:
## 三、初始化方法-03-在初始化方法中定义属性
### 1、在初始化方法内部定义属性
1)在 `__init__` 方法内部使用 `self.属性名 = 属性的初始值` 就可以 **定义属性**。
2)定义属性之后,再使用 `Cat` 类创建的对象,都会拥有该属性。
### 2、初始化方法内部定义属性 示例 代码(dzs_05_初始化方法.py):
在 `Cat` 类中增加 `__init__` 方法,验证该方法在创建对象时会被自动调用。
```python
# dzs_05_初始化方法.py
class Cat:
"""这是一个猫类"""
def __init__(self):
print("这是一个初始化方法")
# 定义用 Cat 类创建的猫对象都有一个 name 的属性
self.name = "Tom"
def eat(self):
print("%s 爱吃鱼" % self.name)
# 使用类名() 创建对象的时候,会自动调用初始化方法 __init__
tom = Cat()
print(tom.name)
tom.eat()
```
### 3、示例:
## 四、初始化方法-04-使用参数设置属性初始值
### 1、改造初始化方法 —— 初始化的同时设置初始值
* 在开发中,如果希望在 **创建对象的同时,就设置对象的属性**,可以对 `__init__` 方法进行 **改造**。
1)把希望设置的属性值,定义成 `__init__` 方法的参数。
2)在方法内部使用 `self.属性 = 形参` 接收外部传递的参数。
3)在创建对象时,使用 `类名(属性1, 属性2...)` 调用。
### 2、初始化的同时设置初始值 示例 代码(dzs_06_利用参数设置属性初始值.py)
```python
# dzs_06_利用参数设置属性初始值.py
class Cat:
"""这是一个猫类"""
def __init__(self, new_name):
print("初始化方法 %s" % new_name)
# self.属性名 = 属性的初始值
# self.name = “Tom”
self.name = new_name
def eat(self):
print("%s 爱吃鱼" % self.name)
# 使用类名() 创建对象的时候,会自动调用初始化方法 __init__
tom = Cat("Tom")
print(tom.name)
tom.eat()
lazy_cat = Cat("大懒猫")
lazy_cat.eat()
...
### 3、示例:
## 五、内置方法-01-del方法和对象的生命周期
### 1、python内置方法和属性
`__del__` 方法 :对象被从内存中销毁前,会被自动调用。
`__str__` 方法 :返回对象的描述信息,`print` 函数输出使用。
### 2、 `__del__` 方法(知道)
1)在 `Python` 中,当使用 `类名()` 创建对象时,为对象 **分配完空间**后,**自动** 调用 `__init__` 方法。
2)当一个 **对象被从内存中销毁** 前,会 **自动** 调用 `__del__` 方法。
### 3、**应用场景**
1) `__init__` 改造初始化方法,可以让创建对象更加灵活。
2)`__del__` 如果希望在对象被销毁前,再做一些事情,可以考虑一下 `__del__` 方法。
### 4、**生命周期**
1)一个对象从调用 `类名()` 创建,生命周期开始。
2)一个对象的 `__del__` 方法一旦被调用,生命周期结束。
3)在对象的生命周期内,可以访问对象属性,或者让对象调用方法。
### 5、__del__方法 示例 代码(dzs_07___del__方法.py)
```python
# dzs_07___del__方法.py
class Cat:
"""这是一个猫类"""
def __init__(self, new_name):
self.name = new_name
print("%s 来了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
# tom 是一个全局变量
tom = Cat("Tom")
print(tom.name)
# del 关键字可以删除一个对象
del tom
print("-" * 50)
```
### 6、示例:
## 六、内置方法-02-str方法定制变量输出信息
### 1、 `__str__` 方法
1)在 `Python` 中,使用 `print` 输出 **对象变量**,默认情况下,会输出这个变量 **引用的对象** 是 **由哪一个类创建的对象**,以及 **在内存中的地址**(**十六进制表示**)。
2)如果在开发中,希望使用 `print` 输出 **对象变量** 时,能够打印 **自定义的内容**,就可以利用 `__str__` 这个内置方法了。
> 注意:`__str__` 方法必须返回一个字符串。
### 2、`__str__` 方法 示例 代码:
```python
# dzs_08___str__方法.py
class Cat:
def __init__(self, new_name):
self.name = new_name
print("%s 来了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
def __str__(self):
return "我是小猫:%s" % self.name
tom = Cat("Tom")
print(tom)
```
### 3、示例:
## 七、小明爱跑步-01-封装特性和需求分析
### 1、面向对象封装案例 学习目标:
* 封装
* 小明爱跑步 案例
* 存放家具 案例
### 2、封装
1)**封装** 是面向对象编程的一大特点。
2) 面向对象编程的 **第一步** —— 将 **属性** 和 **方法** **封装** 到一个抽象的 **类** 中。
3)**外界** 使用 **类** 创建 **对象**,然后 **让对象调用方法**。
4)**对象方法的细节** 都被 **封装** 在 **类的内部**。
> 提示:在 **对象的方法内部**,是可以 **直接访问对象的属性** 的!
### 3、小明爱跑步 案例 需求分析:
**需求**
1)**小明** **体重** `75.0` 公斤
2)小明每次 **跑步** 会减肥 `0.5` 公斤
3)小明每次 **吃东西** 体重增加 `1` 公斤
## 八、小明爱跑步-02-案例完成
### 1、小明爱跑步 案例 代码实现(dzs_09_小明爱跑步.py):
```python
# dzs_09_小明爱跑步.py
class Person:
"""人类"""
def __init__(self, name, weight):
# self.属性 = 形参
self.name = name
self.weight = weight
def __str__(self):
return "我的名字叫 %s 体重 %.2f 公斤" % (self.name, self.weight)
def run(self):
"""跑步"""
print("%s 爱跑步,跑步锻炼身体" % self.name)
self.weight -= 0.5
def eat(self):
"""吃东西"""
print("%s 是吃货,吃完这顿再减肥" % self.name)
self.weight += 1
xiaoming = Person("小明", 75.0)
xiaoming.run()
xiaoming.eat()
xiaoming.eat()
print(xiaoming)
```
### 2、示例:
## 九、小明爱跑步-03-扩展-多个对象属性之间互不干扰
### 1、小明爱跑步 案例 扩展 —— 小美也爱跑步
1)**需求**
* 1. **小明** 和 **小美** 都爱跑步
* 2. **小明** **体重** `75.0` 公斤
* 3. **小美** **体重** `45.0` 公斤
* 4. 每次 **跑步** 都会减少 `0.5` 公斤
* 5. 每次 **吃东西** 都会增加 `1` 公斤
2)类示意图
3)**提示**
* 1. 在 **对象的方法内部**,是可以 **直接访问对象的属性** 的。
* 2. **同一个类** 创建的 **多个对象** 之间,**属性** 互不干扰!
### 2、小明爱跑步 案例 扩展:小美也爱跑步 示例 代码(dzs_10_小明爱跑步扩展.py
):
```python
# dzs_10_小明爱跑步扩展.py
class Person:
"""人类"""
def __init__(self, name, weight):
# self.属性 = 形参
self.name = name
self.weight = weight
def __str__(self):
return "我的名字叫 %s 体重 %.2f 公斤" % (self.name, self.weight)
def run(self):
"""跑步"""
print("%s 爱跑步,跑步锻炼身体" % self.name)
self.weight -= 0.5
def eat(self):
"""吃东西"""
print("%s 是吃货,吃完这顿再减肥" % self.name)
self.weight += 1
xiaoming = Person("小明", 75.0)
xiaoming.run()
xiaoming.eat()
print(xiaoming)
xiaomei = Person("小美", 45)
xiaomei.run()
xiaomei.eat()
print(xiaomei)
print(xiaoming)
```
### 3、示例:
## 十、摆放家具-01-需求分析-被使用的类应该先开发
### 1、摆放家具案例 需求分析
**需求**
1)**房子(House)** 有 **户型**、**总面积** 和 **家具名称列表**。
* 新房子没有任何的家具。
2)**家具(HouseItem)** 有 **名字** 和 **占地面积**,其中
* **席梦思(bed)** 占地 `4` 平米
* **衣柜(chest)** 占地 `2` 平米
* **餐桌(table)** 占地 `1.5` 平米。
3)将以上三件 **家具** **添加** 到 **房子** 中。
4)打印房子时,要求输出:**户型**、**总面积**、**剩余面积**、**家具名称列表**。
### 2、摆放家具案例 :房子**剩余面积**分析
1)在创建房子对象时,定义一个 **剩余面积的属性**,**初始值和总面积相等**。
2)当调用 `add_item` 方法,向房间 **添加家具** 时,让 **剩余面积** -= **家具面积**。
### 3、**思考**:应该先开发哪一个类?
**答案** —— **家具类**
1)家具类简单
2)房子类要使用到家具类,**被使用的类**,通常应该先开发。
`上一节关联链接请点击:`