面向对象基础
面向对象基础
01-面向对象的基本概念
面向过程——怎么做
我们之前的编程思路,都是面向过程的编程思路,它是把一个需求的所有步骤从头到尾逐步实现,功能独立就用函数封装
缺点是遇到复杂项目就很难,原因是函数之间互相调用,改需求的时候需要把所有调用的函数的参数都改变
面向对象——谁来做
面向对象可以理解为更大的封装,通过职责的区分封装多个方法,在运行时让不同的对象调用不同的方法,适应更复杂的需求,
不会像面向过程一样互相调用不同的方法,彼此方法独立
02-类和对象
2.1 类
类是对一群具有相同特征或行为的事物的统称,是抽象的,不能直接使用,相当于图纸、模板,负责创建对象
2.2 对象
对象是由类创建出来的具体存在,对象拥有在类中定义的属性和方法,对象相当于图纸制造出来的事物
2.3 类和对象的关系
先有类,再有方法,类有一个但对象可以有很多个,类中有什么属性和方法,对象中就有相同数量的属性和方法
如飞机图纸就是一个类,由飞机图纸创造出来的飞机就是对象,不同的飞机可以有不同的颜色和大小,但是不可能多或者少一种属性
03-类的设计
3-1 类名的确定
分析整个业务的流程,通常出现的名词就是类,命名满足大驼峰命名法
大驼峰命名法:每一个单词首字母大写,且连接没有下划线,如:CapWords
3-2 属性和方法的确定
特征描述为属性,对象具有的行为(动词)为方法
eg1:
小明今年 18 岁,身高 1.75,每天早上跑完步,会去吃东西
小美今年 17 岁,身高 1.65,小美不跑步,小美喜欢吃东西
定义 人 类
属性包含 name, age, height
方法包含 run(), eat()
eg2:
一只黄颜色的狗叫大黄,看见生人汪汪叫,看到家人摇尾巴
定义 狗 类
属性包含 color, name
方法包含 shout(), shake()
04-面向对象的基础语法
4.1 dir()内置函数
使用 内置函数 dir() 传入 标识符 / 数据,可以查看对象内的 所有属性及方法
eg: print(dir(demo()))
__方法名__ 格式的方法是python提供的内置方法/属性
常用方法
1.__new__ # 创建对象时,会被自动调用
2.__init__ # 对象被初始化时,会被自动调用
3.__del__ # 对象被从内存中销毁前,会被自动调用,相当于在对象销毁先做的事
4.__str__ # print对象时默认为16进制的地址,可以用__str__方法在print对象时自定义内容,但必须返回字符串
4.2 定义类和创建对象
定义类
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass
创建对象
对象变量 = 类名()
简单定义类和对象
eg:
class cat:
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫爱喝牛奶")
tom = cat()
tom.eat()
tom.drink()
4.3 引用概念
在面向对象的语言中,引用同样适用,以上例解释
1.在 python 中使用类 创建对象之后,tom 变量中仍然记录的是 对象在内存中的地址,也就是 tom 变量 引用 了 新建的猫对象
2.使用 print 输出 对象变量,默认情况下,是能够输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示)
3.%d输出10进制,%x输出16进制
注意:如果使用Cat类再创建一个对象,两个对象的内存地址并不同,即同样的类为两个对象创建了不同的内存空间
4.4 self参数
4.4.1 给对象增加属性
要给对象增加属性,只要在类的外部通过 . 设置属性即可
tom.name = "Tom"
lazy_cat.name = "大懒猫"
注意: 由于对象属性的封装应该封装在类的内部,在类外部添加属性不推荐
4.4.2 使用 self 在函数内部输出属性
在封装函数的内部,self 表示调用方法的对象自己,但在方法内部,可以通过 self. 访问对象的属性和其他对象的方法
即在类外部,可以通过 变量名. 访问对象的属性和方法,在类封装的方法中,可以通过 self. 访问对象的属性和方法
eg:
class cat:
def eat(self):
print("%s 小猫爱吃鱼" % self.name)
tom = cat()
tom.name = "Tom"
tom.eat()
lazy_cat = cat()
lazy_cat.name = "大懒猫"
lazy_cat.eat()
4.5 初始化参数
4.5.1 之前在类外设置属性的问题
如果在运行时,没有找到属性,程序就会报错,所以建议还是将属性封装在内部
tom = cat()
tom.eat()
tom.name = "Tom"
4.5.2 初始化方法
当创建对象时,会自动分配空间,并使用__init__方法进行初始化,而__init__方法就是定义类具有哪些属性的方法
class cat:
def __init__(self):
print("初始化方法")
tom = cat()
4.5.3 初始化内部属性并定义初始值
在__init__方法内部,通过 self.属性名 = 初始值 来定义属性
在方法内部使用 self.属性 = 形参 接收外部数据,并在创建对象时使用 类名(属性) 进行调用
class cat:
def __init__(self, name):
self.cat_name = name
def eat(self):
print("%s 小猫爱吃鱼" % self.cat_name)
tom = cat("Tom")
tom.eat()
05-面向对象封装案例
5.1 摆放家具
需求:1. 房子(House) 有 户型、总面积 和 家具名称列表(初始为空)
2.家具(HouseItem) 有 名字 和 占地面积,其中席梦思(bed) 占地 2 平米,衣柜(chest) 占地 2 平米,餐桌(table) 占地 1.5 平米
3.将以上三件 家具添加到房子中
4. 打印房子时,要求输出:户型、总面积、剩余面积、家具名称列表
class HouseItem:
def __init__(self, name, area):
self.name = name
self.area = area
def __str__(self):
return "[%s]的面积是%.1f" % (self.name, self.area)
class House:
def __init__(self, house_type, area):
self.house_type = house_type
self.area = area
self.free_area = area
self.item_list = []
def __str__(self):
return "房子的户型是%s, 总面积是%.1f, 剩余面积为%.1f, 家具名称列表" \
"为%s" % (self.house_type, self.area, self.free_area,
self.item_list)
def add_item(self, item):
if item.area > self.free_area:
return "面积不够, 无法摆放"
else:
self.free_area = self.area - item.area
self.item_list.append(item.name)
bed = HouseItem("席梦思", 4)
chest = HouseItem("衣柜", 2)
table = HouseItem("餐桌", 1.5)
print(bed)
print(chest)
print(table)
my_house = House("三室一厅", 120)
my_house.add_item(bed)
my_house.add_item(chest)
my_house.add_item(table)
print(my_house)
5.2 士兵突击
需求:1.士兵 XXX 有一把 AK47
2.士兵 可以 开火
3.枪 能够 发射 子弹 # shoot 方法需求:判断是否有子弹,没有子弹无法射击;使用 print 提示射击,并且输出子弹数量
4.枪 装填 装填子弹(增加子弹数量) # fire 方法需求:判断是否有枪,没有枪没法冲锋;喊一声口号、装填子弹并射击
注意:一个对象的属性可以是另一个类创建的对象
class Gun:
def __init__(self, module):
self.module = module
self.buttle_count = 0
def __str__(self):
return "枪的型号为%s, 当前子弹数为%d" % (self.module, self.buttle_count)
def shoot(self):
if self.buttle_count <= 0:
print("没有子弹, 无法射击!")
else:
self.buttle_count -= 1
print("使用%s射击!还剩%d发子弹" % (self.module, self.buttle_count))
def add_bullet(self, buttle):
self.buttle_count += buttle
class Soldier:
def __init__(self, name):
self.name = name
self.gun = None
def fire(self):
if self.gun is None:
print("%s还没有枪" % self.name)
else:
print("冲锋!")
self.gun.add_bullet(30)
self.gun.shoot()
ak47 = Gun("ak47")
ak47.shoot()
ak47.add_bullet(30)
ak47.shoot()
soldier = Soldier("小虎")
soldier.fire()
# 我觉得这个代码还是有问题的,比如如果捡了枪该如何表示呢?我尝试了使用bool值,捡枪bool值为True,刚开始为False,但提示'bool' object has no attribute 'add_bullet',如果有思路还请赐教
5.3 身份运算符
身份运算符用于 比较 两个对象的 内存地址 是否一致 —— 是否是对同一个对象的引用
is 用于判断 两个变量引用对象是否为同一个,而 == 用于判断 引用变量的值 是否相等
A is B <=> id(A) == id(B) A is not B <=> id(A) != id(B)
06-私有属性和私有方法
在 定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法,使其只可以 在对象的内部被使用,而 不希望在外部被访问到
class woman:
def __init__(self, name):
self.name = name
self.__age = 18
def __secret(self):
print("我的年龄是%d" % self.__age)
但在python中并没有完全的私有,只是对名称进行了特殊处理,使外界无法访问,我们可以在名称前加上 _类名,组成 _类名__名称,但实际开发中不推荐
# 私有属性
print(xiaofang._woman__age)
# 私有方法
xiaofang._woman__secret()
本文来自博客园,作者:icui4cu,转载请注明原文链接:https://www.cnblogs.com/icui4cu/p/15270753.html