Python核心编程:面向对象编程
面向对象
根据B站大学和廖雪峰的python整理而来
原文链接Serendipity
什么是面向对象
面向过程:思考的重点在于步骤。
面向对象:把问题分解成各个对象,描述对象在整个事情的行为。
引子
-
人狗大战
-
先创建很多狗,每个狗有各自的名字,品种,攻击力等
-
# 面向过程的思考 dog1 = { "name": "小红", # 创建dog1 "d_type": "京巴", "attack_val": 40 } def bite1(person): # dog1咬人 person.life_val -= 40 dog2 = {"name": "小明", # 创建dog2 "d_type": "牧羊犬", "attack_val": 50 } def bite2(person): # dog2咬人 person.life_val -= 50 print(dog1) print(dog2) #以此类推创建dog3,doe4...... #可以看到每当创建一个dog3就要重复很多代码,很是麻烦,有没有更好的办法的呢? #很负责任的跟大家说—— 没有 # 是不可能的! #下面就是另一种编程思想
-
# 面向对象的思考 #写一个函数,包含了每个狗的共同点 attack_vals = { "京巴":40, "牧羊犬":50, "藏獒":60 } def dog(name, d_type): data = { "name": name, "d_type": d_type, "life_val": 80 } if d_type in attack_vals: # 根据品种添加攻击力 data["attack_val"] = attack_vals[d_type] return data dog1 = dog("小红", "京巴") # 实体1 dog2 = dog("小明", "牧羊犬") # 实体2 print(dog1) print(dog2)
-
-
创建很多人
-
# 人也按照共同点创造 def person(name, age): data = { "name": name, "age": age, "life_val": 100 } if age > 18: data["attack_val"] = 50 else: data["attack_val"] = 20 return data P1 = person("阿福", 21) P2 = person("小璇", 17) P3 = person("小岚", 21) P4 = person("小乐", 21) print(P1) print(P2) print(P3) print(P4)
-
-
人可以打狗,狗可以打人
-
#狗咬人 def bite(dog_obj,person_obj): print(f"{dog_obj['name']}的攻击力:{dog_obj['attack_val']}") print(f"{person_obj['name']}的血量:{person_obj['life_val']} ") person_obj['life_val'] -= dog_obj['attack_val'] print(f"{dog_obj['name']}咬了{person_obj['name']},人掉了{dog_obj['attack_val']}血量,还剩下{person_obj['life_val']}") bite(dog1,P1)
-
#打狗 def fight_dog(person_obj,dog_obj): print(f"{person_obj['name']}的攻击力:{person_obj['attack_val']}") print(f"{dog_obj['name']}的血量:{dog_obj['life_val']} ") dog_obj['life_val'] -= person_obj['attack_val'] print(f"{person_obj['name']}打了{dog_obj['name']},狗子没有了{person_obj['attack_val']}血量,还剩下{dog_obj['life_val']}") print() fight_dog(P1,dog1)
-
-
思考
-
上文的打狗函数是bite(dog_obj,person_obj),我们在实际传参的时候写成bite(person_obj,dog_obj)可以吗? 从现实的角度来说,肯定是不可以的。因为bite()函数的狗咬人,理应传入狗的伤害值和人的生命值。 但是从程序的角度来说,这样运行也没什么问题,因为计算机不知道你是人是狗。 那么怎么让计算机知道你是人是狗呢?这就是这篇文章探讨的主要内容了!
-
-
类
类的语法
语法格式: class 类的名称():
class dog(): #创建一个狗类
d_type = "藏獒"
def say_hi(self):
print(f"各位你们好,我的品种是{self.d_type}")
dog1 = dog() #类的一个实例化
print(dog1.d_type) #调用类的属性,属性一个静态的
dog1.say_hi() #该实列调用方法,方法是一个动作
类的初始化
class dog(): #创建一个狗类
def __init__(self,name,d_type): #初始化方法,构造方法,实例化时会自动执行,完成一些初始化操作
self.name = name
self.d_type = d_type
self.life_val = 100
def say_hi(self):
print(f"各位你们好,我的品种是{self.d_type}")
dog1 = dog("小红","藏獒") #类的一个实例化
print(dog1.d_type) #调用类的属性,属性一个静态的
dog1.say_hi() #该实列调用方法,方法是一个动作
类属性的应用场景
类属性:类变量,也就是公共属性,所有实列共享
实例属性:实例变量,成员变量,每个实例独享
#类属性和实例调用类属性,若数值也是一样,内存空间是一样的
print(id(dog1.life_val))
print(id(dog2.life_val))
dog.life_val变量是一样,都是100,所以可以单独设置
class dog(): #创建一个狗类
life_val = 100
def __init__(self,name,d_type):
self.name = name
self.d_type = d_type
def say_hi(self):
print(f"各位你们好,我的品种是{self.d_type}")
实列属性对自己不满意也可以改属性
#dog.life_val = 100
dog2.life_val = 200
print(id(dog2.life_val))
类之间的关系
- 依赖关系
- 关联关系
- 组合关系
- 聚合关系
- 继承关系,类的三大特性之一
访问限制
访问保护
在类的应用场景我们说到实例属性对自己不满意也可以改属性。
如果要让内部属性不被外部访问,可以在属性前面加上一些东西,如__
需要注意:变量名__xxx__
的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__
、__score__
这样的变量名。
class dog(): #创建一个狗类
def __init__(self,name,d_type):
self.__name = name
self.__d_type = d_type
self.life_val = 100
#这样的话dog2.val = 200就不能成功。因为无法访问
如果说我们有时候真的需要修改life_val怎么办?可以给dog增加一个set_life_val
方法:
class dog(): #创建一个狗类
# life_val = 100
def __init__(self,name,d_type):
self.__name = name
self.__d_type = d_type
self.__life_val = 100
def set_life_val(self,life):
self.__life_val = life
除了修改,我们还需要访问life_val。但是现在显然是不能访问的,解决方案如下:
def set_life_val(self):
return self.__life_val
继承
当我们新定义一个class,可以从现有的class继承,新的这个class也就是子类。
比如我们定义一个二哈继承狗类。
class erha(dog):
pass
这样的话,二哈拥有父类dog的全部功能。
获取对象信息
使用type()
使用type()可以判断类型
type(12345)
type(dog1)
使用isinstance()
对于class的继承关系。使用type()
不方便。
>>> isinstance(erha1,erha)
True
因为erha
是从dog
继承下来的,所以erha1也是属于dog
>>> isinstance(erha1,dog)
True
使用dir()
获取一个对象的所有属性和方法,它返回一个包含字符串的list。
>>>dir(123)
['__abs__', '__add__',....... 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']