python之面向对象

1.封装

1.封装是面向对象编程的一大特点
2.面向对象编程的第一步 将属性和方法封装到一个抽象的类中(为什么说是抽象的,因为类不能直接使用)
3.外界使用类创建对象,然后让对象调用方法
4.对象方法的细节都被封装在类的内部

  • 面向过程:强调过程,怎么做
  • 面向对象:强调过程,谁来做
    相对于函数来说是一个更大的封装,根据职责将对象所能实现的功能封装到一起
    1.确定对象要做的事情(方法->多个)
    2.让对象调用方法

    例:植物大战僵尸
    对象:向日葵 豌豆射手 僵尸

2. 类

  • 类:是一群具有相同特征和行为事物的一个统称(抽象的,不能直接使用)
    特征:被称为属性
    行为:被称为方法

    上 例:植物大战僵尸
    向日葵的方法:生产阳光()
    豌豆射手的方法:发射子弹()
    僵尸的方法: 移动() 咬()

对象

对象:由类创建出来的一个具体的存在,由哪一个类创建出来的
对象,就拥有哪一个类中定义的方法和属性

先有类–>再有对象

类和对象的关系:
类是模板,对象是根据这个模板创建出来的,先有类再有对象
类只需要有一个,对象可以有很多个
不同对象(由同一类创建出来的对象)之间的属性可以不相同
类中定义了什么属性和方法,使用这个类创建出来的对象就有什么
属性和方法,不可能多也不可能少

类的设计
1. 类名:这类事物的名字(大驼峰命名法)
大驼峰命名法:
1. 每一个单词的首字母大写
2. 单词与单词之间没有下划线
2. 属性:这个类创建出来的对象有什么样的特征
3. 方法:这个类创建出来的对象有什么样的行为
类名的确定:
名词提炼法分析整个业务流程,出现的名词,通常就是找到的类
属性和方法的确定
对 对象的特征描述,通常可以定义成属性
对象具有的行为(动词),通常可以定义为方法
提示:需求中没有涉及的属性或方法在设计类时,不需要考虑

练习1:

需求:
小明今年18岁,身高1.75,每天早上要跑步,小明吃东西
小美今年17岁,身高1.65 小美不跑步,小美吃东西
分析:
一个Person类,
属性:姓名,年龄,身高
方法:跑步,吃东西
这个Person类实例化两个对象小明和小美

练习2:

一只黄颜色的狗狗叫大黄,看见生人旺旺叫,看见家人摇尾巴
分析:
一个Dog类
属性:颜色,名字
方法:叫,摇尾巴

练习3:

猫爱吃鱼,猫要喝水
分析:
猫类
方法:吃,喝

代码实现:

# 哪一个对象调用的方法,self就是哪一个对象的引用
# 在类封装方法的内部,self就表示当前调用方法的对象自己
# 在的方法内部 可以通过 self.属性 来访问对象的属性
class Cat:
    def eat(self):
        print('%s 爱吃鱼' %(self.name))

    def drink(self):
        print('猫要喝水')
tom = Cat()
# 在类的外部 对象.属性 可以给对象添加属性
# 不推荐使用
# 对象包含哪些方法,应该封装在类中
tom.name = 'Tom'
print(tom) # <__main__.Cat object at 0x7fa417961c18>
tom.eat() # Tom 爱吃鱼
tom.drink() # 猫要喝水

# 再创建一个猫对象
lazy_cat = Cat()
lazy_cat.name = 'miaomiao'
print(lazy_cat) # <__main__.Cat object at 0x7fa417961c88>
lazy_cat.eat() # miaomiao 爱吃鱼
lazy_cat.drink() # 猫要喝水

lazy_cat2 =lazy_cat
print(lazy_cat2)# <__main__.Cat object at 0x7fa417961c88>

3. 初始化方法

我们现在已经知道了使用 类名() 就可以创建一个对象
当使用类名()创建对象时,python的解释器会自动执行以下操作:

1.为对象在内存中分配空间–创建对象
2.调用初始化方法为对象的属性设置初始值–初始化方法(init)
这个初始化方法就是__init__方法,__init__是对象的内置方法
__init__方法是专门用来定义一个类具有哪些属性的方法

改造初始化方法–初始化的同时设置初始值:
在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对__init__方法进行改造

1.把希望设置的属性值,定义成__init__方法的参数
2.在方法内部使用self.属性名 = 形参 接收外部传递的参数
3.在创建对象时,使用类名(属性1,属性2…)调用

class Cat:
    def __init__(self,new_name):
        print('这是一个初始化方法')
        # self.属性名 = 属性的初始值
        #self.name = 'Tom'
        self.name = new_name
    # 在类中,任何方法都可以使用self.name
    def eat(self):
        print('%s 爱吃鱼' %(self.name))

# 使用类名()创建对象的时候,会自动调用初始化方法__init__
tom = Cat('tom')
# 定义属性之后,再用Cat创建对象的时候,都会拥有该属性
print(tom.name)# tom
tom.eat()# tom 爱吃鱼

lazy_cat = Cat('miaomiao')
print(lazy_cat.name)# miaomiao
lazy_cat.eat()# miaomiao 爱吃鱼

4. __del__方法

__ del __:对象被从内存中销毁前,会被自动调用

在python中
当使用类名()创建对象时,为对象分配完空间后,自动调用__init__方法
当一个对象被从内存中销毁前(把这个对象从内存中删除掉),
会自动调用__del__方法

应用场景
__init__改造初始化方法,可以让创建对象更加灵活
__del__如果希望在对象被销毁前,再做一些事情,可以考虑一下__del__方法

生命周期(出生到死亡)
一个对象从调用类名()创建,生命周期开始
一个对象的__del__方法一但被调用,生命周期结束
在对象的生命周期内,可以访问对象属性,或者让对象调用方法

class Cat:
    def __init__(self,new_name):
        self.name = new_name
        print('%s 来了' %(self.name))
    def __del__(self):
        print('%s 走了' %(self.name))

cat = Cat('tom')
print(cat.name)
# del关键字可以删除一个对象,del关键字自己调用__del__方法
del cat
print('*' * 50)

在这里插入图片描述

5. __str__方法

__ str __:返回对象的描述信息 print函数输出使用

在python中,使用python输出对象变量,默认情况下,
会输出这个变量引用的对象是由哪一个类创建的对象,
以及在内存中的地址(十六进制表示)
如果在开发中,希望使用print输出对象变量时,
能够打印自定义的内容,就可以利用__str__这个内置方法了

class Cat:
    def __init__(self,new_name):
        self.name = new_name
    def __str__(self):
        # 必须返回一个字符串
        return '我是 %s' %(self.name)

cat = Cat('tom')

# 如果没有__str__方法,输出的是<__main__.Cat object at 0x7fa8435896a0>
print(cat) #我是 tom

小应用

实现简单的栈

class Stack:
    def __init__(self):
        self.stack=[]

    def push(self,value):
        self.stack.append(value)
        return True
    def pop(self):
        if self.stack:
            # 获取出栈元素,并返回
            item = self.stack.pop()
            return item
        else:
            return False

    def top(self):
        if self.stack:
            return self.stack[-1]
        else:
            return False

    def length(self):
        return len(self.stack)

    def isempty(self):
        return self.stack == []

    def view(self):
        return ','.join(self.stack)

s = Stack()
s.push('1')
s.push('2')
print(s.view())# 1,2
item = s.pop()
print(item)# 2
print(s.view())# 1

一个对象的属性可以是另外一个类创建的对象

示例:士兵射击
需求:
1.士兵瑞恩有一把AK47
2.士兵可以开火(士兵开火扣动的是扳机)
3.枪 能够 发射子弹(把子弹发射出去)
4.枪 能够 装填子弹 --增加子弹的数量

class Gun:
    def __init__(self,model):
        # 枪的型号
        self.model = model
        # 子弹的数量(调用增加子弹的方法来增加子弹数量)
        self.bullet_count = 0

    def add_bullet(self,count):
        self.bullet_count += count

    def shoot(self):
        # 判断子弹数量
        if self.bullet_count <= 0:
            print('[%s] 没有子弹了...' %(self.model))
            return
        # 发射子弹 子弹数量变化
        self.bullet_count -= 1
        print('[%s] tututu~ [%d]' %(self.model,self.bullet_count))

class Soldier:
    def __init__(self,name):
        self.name = name
        # 枪(新兵没有枪)
        self.gun = None

    def fire(self):
        # 1.判断士兵是否有枪
        if self.gun == None:
            print('[%s] 还没有枪..' %(self.name))
            return
        print('go!!![%s]' %(self.name))
        self.gun.add_bullet(50)
        self.gun.shoot()


# 创建枪对象
ak = Gun('ak47')
# ak.add_bullet(50)
# ak.shoot()
# ak.shoot()

# 创建士兵对象
ryan = Soldier('Ryan')
# 通过主程序的赋值语句,士兵有枪了
ryan.gun = ak
ryan.fire()
#print(ryan.gun)

面向对象三大特性

面向对象三大特性
1.封装:根据职责将属性和方法封装到一个抽象的类中
2.继承:实现代码的重用,相同的代码不需要重复的写

单继承:

子类拥有父类的所有方法和属性(子类只需封装自己特有的方法)

class Animal:
    def eat(self):
        print('吃')
    def drink(self):
        print('喝')
    def run(self):
        print('跑')
    def sleep(self):
        print('睡')

class Cat(Animal):
    def call(self):
        print('喵喵~')

class Hellokitty(Cat):
    def speak(self):
        print('我可以说日语~')

# 创建猫对象
fentiao = Cat()
fentiao.eat()
fentiao.drink()
fentiao.run()
fentiao.sleep()
fentiao.call()

hk = Hellokitty()
hk.speak()
# 子类可以继承父类的所有属性和方法
hk.call()

# 继承的传递性,子类拥有父类的父类的属性和方法
hk.eat()
hk.drink()
hk.run()
hk.sleep()

当父类的方法不能满足子类的需求的时候,可以对父类的方法进行重写
1.覆盖父类方法
2.对父类方法进行扩展

class Hellokitty(Cat):
    def speak(self):
        print('我可以说日语~')
    def call(self):
        # 调用原本在父类中封装的方法
        #Cat.call(self)
        super().call() # 只在python3中支持
        print('#@!#@!#@!')
hk = Hellokitty()
hk.call()

输出:
喵喵~
#@!#@!#@!

多继承

子类拥有一个父类叫做单继承
子类可以拥有多个父类,并且具有所有父类的属性和方法
例如:孩子会继承自己父亲和母亲的特性

class A:
    def test(self):
        print('test 方法')
class B:
    def demo(self):
        print('demo 方法')
class D:
    def haha(self):
        print('!!!!!!!!!!!!')
class C(A,B,D):
    """多继承可以让子类对象,同时具有多个父类的属性和方法"""
    pass

c = C()
c.test()
c.demo()
c.haha()

输出结果:
test 方法
demo 方法
!!!

多继承的注意事项:
问题的提出:
如果不同的父类中存在同名的方法,子类对象在调用方法时,会调用哪一个父类中的方法呢?
提示:开发时,应尽量避免这种容易产生混淆的情况
如果父类之间存在同名的属性或方法,因该尽量避免使用多继承

class A:
    def test(self):
        print('A----test 方法')
    def demo(self):
        print('A----demo 方法')

class B:
    def test(self):
        print('B----test 方法')
    def demo(self):
        print('B----demo 方法')


class C(B,A):
    pass

c = C()
c.test()
c.demo()

输出结果:
B----test 方法
B----demo 方法

新式类和旧式(经典)类:
object是Python为所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看
新式类:以object为基类的类,推荐使用
经典类:不以object为基类的类,不推荐使用
在python3.X中定义的类时,如果没有指定父类,会默认使用object作为基类–python3.x中定义的类都是新式类
在python2.x中定义类时,如果没有指定父类,则不会以object作为基类
####推荐使用新式类#############

新式类和旧式类在多继承时—会影响到方法的搜索顺序

为保证编写的代码能够同时在python2.x和python3.x运行
今后在定义类时,如果没有父类,建议统一继承自object

super()类

新式类:调用的顺序为广度优先
旧式类:调用顺顺序为深度优先
super()类:不重复的调用父类,解决了钻石继承(多继承)的难题

super实现原理:通过c3算法,生成mro(method resolution order)列表,根据列表中元素顺序查询调用
super()不是指父类 而是指以实例化对象为起点的mro序列中的下一个
  
简洁点的三个原则就是:
子类在父类前,所有类不重复调用,从左到右

class Person(object):
    def __init__(self):
        print('我要好好学习')
    def study(self):
        print('我要好好学习语言')

class Man(Person):
    def __init__(self):
        print('我是男的我要好好学习')
    def study(self):
        print('我要学好数学')
        #super().study()
class Womam(Person):
    def __init__(self):
        print('我是女的我要好好学习')
    def study(self):
        print('我要学好英语')
        super().study()

class Son(Man,Womam):
    def __init__(self):
        print('我是儿子我要好好学习')

    def study(self):
        print('我要学好化学和物理')
        #Womam.study(self)
        #Man.study(self)
        super().study()
print(Son.mro())
son1 = Son()
son1.study()
class A():
    def go(self):
        print ("go A go!")
    def stop(self):
        print ("stop A stop!")
    def pause(self):
        raise Exception("Not Implemented")
class B(A):
    def go(self):
        super(B, self).go()# 继承
        print ("go B go!")
class C(A):
    def go(self):
        super(C, self).go()
        print ("go C go!")
    def stop(self):
        super(C, self).stop()
        print ("stop C stop!")
class D(B,C):
    def go(self):
        super(D, self).go()
        print ("go D go!")
    def stop(self):
        super(D, self).stop()
        print ("stop D stop!")
    def pause(self):
        print ("wait D wait!")
a = A()
a.go()#go A go!
b = B()
b.go()
# go A go!
# go B go!
c = C()
c.go()
# go A go!
# go C go!

d = D()
d.go()
# go A go!
# go C go!
# go B go!
# go D go!
私有属性和私有方法

应用场景:
在实际开发中,对象的某些属性或方法可能只希望在对象的内部使用,而不希望在外部被访问到
私有属性 就是 对象 不希望公开的 属性
私有方法 就是 方法 不希望公开的 方法
定义方法:
在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性或方法

class Women(object):
    def __init__(self,name):
        self.name = name
        self.__age = 18

    def __secret(self):
        print('%s 的年龄是 %d' %(self.name,self.__age))

lily = Women('lily')
print(lily.age)#AttributeError: 'Women' object has no attribute 'age'
lily.__secret()#AttributeError: 'Women' object has no attribute '__secret'


类属性和类方法

类是一个特殊的对象
Python中一切皆对象
class AAA: 定义的类属性属于类对象
obj1 =AAA: 属于实例对象
在运行程序时,类 同样会被加载到内存
在python中,类 是可以创建出很多个对象实例
除了封装 实例 的属性和方法外,类对象还可以有自己的属性和方法
1.类属性
2.类方法
通过 类名 . 的方式可以直接访问类的属性或者调用类的方法

类方法需要用修饰器@classmethod来标示,告诉解释器这是一个类方法
类方法的第一个参数应该是cls
由哪一个类调用的方法,方法内的cls就是哪一个类的引用
这个参数和实例方法的第一个参数是self类似(哪一个对象调用的方法,self就是哪一个对象的引用)

通过类名调用类方法,调用方法时,不需要传递cls参数

在方法内部
也可以通过cls.访问类的属性
也可以通过cls.调用其他的类方法

class Tool(object):
    # 1.使用赋值语句定义类属性,记录所有工具的数量
    count = 0

    def __init__(self,name):
        self.name = name
        # 让类属性的值 +1
        Tool.count += 1
    @classmethod
    def show_tool_count(cls):
        # cls.count 在类方法内部,访问当前的类属性
        print('工具对象的数量 %d' %(cls.count))

# 创建工具对象(对象在创建的时候,会自动调用初始化方法)
#print(Tool.count)
tool1 = Tool('斧头')
#tool2 = Tool('榔头')
tool1.show_tool_count()#工具对象的数量 1
# 输出工具对象的属性
# 使用 类名.属性名 的方式来获取属性名
#print(Tool.count)
静态方法
class Cat(object):
    @staticmethod
    def call():
        print('喵~')

# 不需要创建对象,直接就可以使用
Cat.call()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值