相比较函数,面向对象 是 更大 的 封装,根据 职责 在 一个对象中 封装 多个方法
• 类 是对一群具有 相同 特征 或者 行为 的事物的一个统称,是抽象的,不能直接使用
– 特征 被称为 属性
– 行为 被称为 方法
• 类 就相当于制造飞机时的图纸,是一个 模板,是 负责创建对象的
• 对象 是 由类创建出来的一个具体存在,可以直接使用
• 由 哪一个类 创建出来的 对象,就拥有在 哪一个类 中定义的:
• 类是模板,对象 是根据 类 这个模板创建出来的,应该 先有类,再有对象
• 类 只有一个,而 对象 可以有很多个
– 不同的对象 之间 属性 可能会各不相同
• 类 中定义了什么 属性和方法,对象 中就有什么属性和方法,不可能多,也不可能少
在使用面相对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类!
在程序开发中,要设计一个类,通常需要满足一下三个要素:
1 类名 这类事物的名字,满足大驼峰命名法
2 属性 这类事物具有什么样的特征
3 方法 这类事物具有什么样的行为
驼峰命名法
CapWords
1 每一个单词的首字母大写
2 单词与单词之间没有下划线
3.1 类名的确定
名词提炼法 分析 整个业务流程,出现的 名词,通常就是找到的类
3.2 属性和方法的确定
• 对 对象的特征描述,通常可以定义成 属性
• 对象具有的行为(动词),通常可以定义成 方法
提示:需求中没有涉及的属性或者方法在设计类时,不需要考虑
#!/usr/bin/python
# author X_Dragon
# E-mail:[email protected]
class Person:
def __init__(self, name, age, height):
self.name = name
self.age = age
self.height = height
def introduce(self):
print("我是:%s,今年%d岁,身高%.2f" % (self.name, self.age, self.height))
def run(self):
print("%s爱跑步,跑步锻炼身体" % self.name)
def eat(self):
print("%s是吃货,吃完再减肥" % self.name)
xiaoming = Person("小明", 18, 180)
xiaoming.introduce()
xiaoming.run()
xiaoming.eat()
print(xiaoming)# 打印地址 0x0000015E2D92BFD0
xiaomei=Person("小美",20,168)
xiaomei.introduce()
xiaomei.run()
xiaomei.eat()
print(xiaomei) # 0x0000015E2D92BE50
#!/usr/bin/python
# author X_Dragon
# E-mail:[email protected]
class Gun:
def __init__(self,gun_model):
# 枪的型号
self.model=gun_model
# 剩余子弹
self.bullet_count=0# 默认0
# 填充子弹
def Add_bullet(self,count):
self.bullet_count+=count
# 射击
def Shoot(self):
if(self.bullet_count>0):
self.bullet_count -= 1
print("开始射击,剩余子弹:%d"%self.bullet_count)
else:
print("枪没有子弹了,请填充子弹")
# 创建枪的对象 AK47
ak47=Gun("ak47")
ak47.Add_bullet(50)
ak47.Shoot()
# 开发士兵类
class Soldier:
def __init__(self,name):
self.name=name
self.gun=None# 默认新兵没枪
def fire(self):
if(self.gun is None):
print("%s还没有枪...."%self.name)
return
# 到这一步 ,满足有枪的条件
print("冲锋......我是:[%s]"%self.name)
# 装子弹
print("装子弹....")
self.gun.Add_bullet(50)
# 发射
self.gun.Shoot()
# 创建实例
M4=Gun("M4")
XUSANDUO=Soldier("许三多")
XUSANDUO.gun=M4# 如果是新兵 就不配枪
XUSANDUO.fire()
应用场景
• 在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而不希望在外部被访问到
• 私有属性 就是 对象 不希望公开的 属性
• 私有方法 就是 对象 不希望公开的 方法定义方式
• 在 定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是私有 属性或方法
在Python中,你可以将对象的属性设为私有属性,以防止直接访问和修改它们。要将属性设置为私有属性,通常在属性名称前面添加一个下划线前缀(单个下划线),这是一种约定,表示该属性是私有的,应该在类的内部使用,而不是在外部直接访问。虽然这不会强制阻止外部访问,但它是一种约定,告诉其他开发者应该将其视为私有属性。
下面是一个示例,演示如何在Python类中使用私有属性:
class Person:
def __init__(self, name, age):
self._name = name # 前面添加下划线,表示私有属性
self._age = age
def introduce(self):
print(f"我是{self._name},今年{self._age}岁。")
def change_name(self, new_name):
self._name = new_name # 类的内部可以修改私有属性
# 创建对象
xiaoming = Person("小明", 20)
# 访问私有属性
print(xiaoming._name) # 仍然可以访问,但不建议在外部直接访问
# 通过对象方法修改私有属性
xiaoming.change_name("小红")
# 再次访问私有属性
print(xiaoming._name) # 仍然可以访问,但不建议在外部直接访问
在上面的示例中,我们将 name 和 age 属性设为私有属性,添加了一个下划线前缀。虽然我们仍然可以在外部访问和修改这些属性,但是约定是在类的内部使用它们,而不要在外部直接访问。此外,我们还提供了一个对象方法 change_name,允许在类的内部修改私有属性的值。这种方法提供了更好的封装和控制,以防止意外的外部访问和修改。
继承的概念:子类继承父类的方法和属性
#!/usr/bin/python
# author X_Dragon
# E-mail:[email protected]
class Animal:
def eat(self):
print("吃-------")
def sleep(self):
print("睡-------")
class Dog(Animal):
# 狗叫
def bark(self):
print("汪汪旺-------")
d=Dog()
d.bark()
d.sleep()
d.eat()
#!/usr/bin/python
# author X_Dragon
# E-mail:[email protected]
class Animal:
def eat(self):
print("吃-------")
def sleep(self):
print("睡-------")
class Dog(Animal):
# 狗叫
def bark(self):
print("汪汪旺-------")
class xiaotianquan(Dog):
def fly(self):
print("我会飞........")
# 重写 bark
def bark(self):
print("哮天犬在咆哮........")
xtq=xiaotianquan()
xtq.bark()
xtq.fly()
xtq.sleep()
xtq.eat()
1 子类对象不能 在自己的方法内部,直接 访问父类的 私有属性 或 私有方法
2 子类对象 可以通过 父类 的 公有方法间接 访问到 私有属性 或 私有方法(父类在自己的公有方法中调用私有方法)
• 私有属性、方法 是对象的隐私,不对外公开,外界 以及 子类 都不能直接访问
• 私有属性、方法 通常用于做一些内部的事情
示例
B的对象不能直接访问 num2 属性
• B 的对象不能在demo 方法内访问 num2 属性
• B 的对象可以在demo 方法内,调用父类的test 方法
• 父类的test 方法内部,能够访问 num2 属性和 test 方法
测试代码:
class A:
def __int__(self):
self.num1=100
self._num2=200
def _test(self):
print("这是一个内部方法")
class B(A):
def demo(self):
pass
b=B()
print(b)
print(b._test())
print(b._num2)
• 在搜索方法时,是按照 mro 的输出结果 从左至右 的顺序查找的
• 如果在当前类中 找到方法,就直接执行,不再搜索
• 如果 没有找到,就查找下一个类 中是否有对应的方法,如果找到,就直接执行,不再搜索
• 如果找到最后一个类,还没有找到方法,程序报错
class 类名(object): pass
而这个 MRO 列表的构造是通过一个 C3 线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的 MRO 列表并遵循如下三条准则:
面向对象三大特性
1 封装 根据 职责 将 属性 和 方法封装 到一个抽象的 类 中
– 定义类的准则
2 继承实现代码的重用,相同的代码不需要重复的编写
– 设计类的技巧
– 子类针对自己特有的需求,编写特定的代码
3 多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
– 多态 可以 增加代码的灵活度
– 以 继承 和 重写父类方法 为前提
– 是调用方法的技巧,不会影响到类的内部设计单一职责,开放 封闭—对扩展开放,对修改封闭
#!/usr/bin/python
# author X_Dragon
# E-mail:[email protected]
class Dog:
def __init__(self,name):
self.name=name
def game(self):
print("普通狗 普通玩耍 在地面哇哇哇....")
class XIAOTIANQUAN(Dog):
def game(self):
print("我是哮天犬,我在天上玩耍,芜湖.....")
class Person:
def __init__(self,name):
self.name=name
def game(self,dog):
print("和%s快乐玩耍"%dog.name)
wangcai=Dog("旺财")
XTQ=XIAOTIANQUAN("哮天犬")
xiaoming=Person("小明")
xiaoming.game(XTQ)
1 使用面向对象开发,第 1 步 是设计 类
2 使用 类名() 创建对象,创建对象 的动作有两步:
– 1) 在内存中为对象 分配空间
– 2) 调用初始化方法 init 为 对象初始化
3 对象创建后,内存 中就有了一个对象的 实实在在 的存在—— 实例
因此,通常也会把:
1 创建出来的 对象 叫做 类 的 实例
2 创建对象的 动作 叫做 实例化
3 对象的属性 叫做 实例属性
4 对象调用的方法 叫做 实例方法
在程序执行时:
1 对象各自拥有自己的 实例属性
2 调用对象方法,可以通过self.
– 访问自己的属性
– 调用自己的方法
Python 中 一切皆对象:
• class AAA: 定义的类属于 类对象
• obj1 = AAA() 属于 实例对象
• 在程序运行时,类 同样 会被加载到内存
• 在Python 中,类 是一个特殊的对象—— 类对象
• 在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例
• 除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法
d) 类属性
e) 类方法
• 通过 类名. 的方式可以 访问类的属性 或者 调用类的方法
• 类属性不会用于记录 具体对象的特征
• 类方法需要用 修饰器 @classmethod 来标识,告诉解释器这是一个类方法
• 类方法的 第一个参数 应该是cls
– 由 哪一个类 调用的方法,方法内的cls 就是 哪一个类的引用
– 这个参数和 实例方法 的第一个参数是self 类似
– 提示 使用其他名称也可以,不过习惯使用cls
• 通过 类名. 调用 类方法,调用方法时,不需要传递cls 参数
• 在方法内部
– 可以通过cls. 访问类的属性
– 也可以通过cls. 调用其他的类方法示例需求
• 在开发时,如果需要在 类 中封装一个方法,这个方法:
– 既 不需要 访问 实例属性 或者调用 实例方法
– 也 不需要 访问 类属性 或者调用 类方法
• 这个时候,可以把这个方法封装成一个 静态方法,例如打印一些帮助语法如下
@staticmethod
def 静态方法名(): pass
• 静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法
• 通过 类名. 调用 静态方法