Python学习-面向对象进阶

面向对象三大特征:封装、继承、多态

封装:将细节封装起来,只对外暴露调用方法,增加整体的安全性。通过前面所学的私有属性和私有方法即可实现。

继承:使得子类可以继承父类的方法和属性,提高了代码的复用性

多态:同一个方法被调用时会因为对象不同而产生不一样的结果。

一.封装

可以使用私有属性和私有方法对数据进行隐藏封装,使得只有调用方法会对外暴露。

二.继承

继承是面向对象程序设计的重要特征,也是实现“代码复用”的重要手段。 如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,就大大降低了工作 难度。已有的类,我们称为“父类或者基类”,新的类,我们称为“子类或者派生类”。

1.语法格式

Python 支持多重继承,一个子类可以继承多个父类。继承的语法格式如下:

class 子类类名(父类 1[,父类 2,...]):

                                     类体

如果在类定义中没有指定父类,则默认父类是 object 类。也就是说,object 是所有类的父 类,里面定义了一些所有类共有的默认实现,比如:__new__()。

定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下: 父类名.__init__(self, 参数列表)

class Person():
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def print(self):
        print(self.name,"-",self.age,"-",self.attribute)
class Lhx(Person):
    def __init__(self,name,age,attribute): #此处要将和父类重复但是需要使用的属性重新书写
        self.attribute=attribute
        Person.__init__(self,name,age)
lhx=Lhx("林海馨","18","可爱")
lhx.print()
print(dir(lhx))

2.类成员的继承和重写

1. 成员继承:子类继承了父类除构造方法之外的所有成员。

2. 方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为“重写”。直接在类对象中写出即可。

class Person():
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def say_name(self):
        print("我的名字是:",self.name)
    def say_age(self):
        print(self.name,'-',self.age)

class Lhx(Person):
    def __init__(self,score,name,age):
        self.score=score
        Person.__init__(self,name,age)
    def say_score(self):
        print(self.score)
    def say_name(self):
        print("老师好!我叫",self.name)

lhx=Lhx(90,"林海馨",18)
lhx.say_name()
lhx.say_score()
lhx.say_age()

3.查看类的继承层次结构

通过类的方法 mro()或者类的属性__mro__可以输出这个类的继承层次结构。

class A():
    pass
class B(A):
    pass
class C(B):
    pass
print(C.mro())

 

object 类是所有类的父类,因此所有的类都有 object 类的属性和方法。

class Person():
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def say_name(self):
        print(self.name)

obj=object()
print(dir(obj))
p1=Person("林海馨",18)
print(dir(p1))

从上面我们可以发现这样几个要点:

1. Person 对象增加了六个属性: __dict__ __module__ __weakref__ age name say_age

2. object 的所有属性,Person 类作为 object 的子类,显然包含了所有的属性。

3. 我们打印 age、name、say_age,发现 say_age 虽然是方法,实际上也是属性。只不过, 这个属性的类型是“method”而已。 

4.重写__str__()方法

class Person():
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return "名字是{0},年龄是{1}".format(self.name,self.age)

p1=Person("林海馨",18)
print(p1)

5.多重继承

Python 支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父 类”的特点。但是由于,这样会被“类的整体层次”搞的异常复杂,尽量避免使用。

MRO()方法:MRO(Method Resolution Order):方法解析顺序。 我们可以通过 mro()方法获得 “类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找的。

class A():
    def aa(self):
        print("aa")
    def print(self):
        print("1230")
class B():
    def bb(self):
        print("bb")
    def print(self):
        print("4567")
class C(A,B):
#class C(B,A):
    def cc(self):
        print("cc")
c=C()
c.aa()
c.bb()
c.cc()
c.print()
print(C.mro())

7.super()获得父类定义

class A():
    def print(self):
        print("aa")
class B(A):
    def print(self):
        print("bb")
        super().print()
b=B()
b.print()

在子类中,如果想要获得父类的方法时,我们可以通过 super()来做。 super()代表父类的定义,不是父类对象。 

三.多态

关于多态要注意以下 2 点:

1. 多态是方法的多态,属性没有多态。

2. 多态的存在有 2 个必要条件:继承、方法重写。

class Animal():
    def shout(self):
        print("动物叫了一声!")
class Dog(Animal):
    def shout(self):
        print("汪汪汪")
class Cat(Animal):
    def shout(self):
        print("喵~")
class Mice(Animal):
    def shout(self):
        print("吱吱吱")
def Animalshout(a):
    if isinstance(a,Animal):  #判断a是不是Animal的子类,isinstance用于判断是否有继承关系
        a.shout()
Animalshout(Dog())
Animalshout(Cat())
Animalshout(Mice())

1.特殊方法和运算符重载

class Person():
    def __init__(self,name):
        self.name=name
    def __add__(self, other):
        if(isinstance(other,Person)):
            print("{0}-{1}".format(self.name,other.name))
        else:
            print("两个对象格式不同!")
    def __mul__(self, other):
        if(isinstance(other,int)):
            print(self.name*other)
        else:
            print("不可相乘!")
p1=Person("林海馨")
p2=Person("任国亮")
p2+p1  #此处调用_add_函数
p2*3

Python 对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。这 里我们列出常见的特殊属性: 

class A():
    pass
class B():
    pass
class C(A,B):
    def print(self):
        print("cc")
c=C()
print(dir(c)) #对象的全部属性
print(c.__dict__) #对象属性的字典展示
print(c.__class__) #对象所属的类
print(C.__base__) #类的基类
print(C.mro()) #打印所有父类 此处必须使用类来调用函数,对象调用会出错
print(A.__subclasses__())#打印所有子类

2.特殊属性

class A():
    pass
class B():
    pass
class C(A,B):
    def print(self):
        print("cc")
c=C()
print(dir(c)) #对象的全部属性
print(c.__dict__) #对象属性的字典展示
print(c.__class__) #对象所属的类
print(C.__base__) #类的基类
print(C.mro()) #打印所有父类 此处必须使用类来调用函数,对象调用会出错
print(A.__subclasses__())#打印所有子类

4.对象的浅拷贝和深拷贝

  • 变量的赋值操作:只是形成两个变量,实际还是指向同一个对象。
  • 浅拷贝 :Python 拷贝一般都是浅拷贝。拷贝时,对象包含的子对象内容不拷贝。因此,源对象和拷贝对象会引用同一个子对象。
  • 深拷贝 : 使用 copy 模块的 deepcopy 函数,递归拷贝对象中包含的子对象。源对象和拷贝对象所有的子对象也不同。
import copy
class MobilePhone():
    def __init__(self,cpu,screen):
        self.cpu=cpu
        self.screen=screen

class Cpu():
    def calculate(self):
        print("计算。。。")
        print("CPU:",self)

class Screen():
    def show(self):
        print("展示。。。")
        print("Screen:",self)

c1=Cpu()
s1=Screen()

m1=MobilePhone(c1,s1)
n=m1 #此处应该被赋值的是变量n,n应该写在=前面
print(n)
print(m1)

#测试浅复制
print("测试浅复制","#"*20)
m2=copy.copy(m1)
print(m2)
print(m1)
m2.cpu.calculate()
m1.cpu.calculate()  #不同地址对象中的子对象地址相同

#测试深复制
print("测试深复制","#"*20)
m3=copy.deepcopy(m1)
print(m3)
print(m1)
m1.cpu.calculate()
m3.cpu.calculate()  #不同地址的对象中的子对象地址不同

 

5.组合

“is-a”关系,我们可以使用“继承”。从而实现子类拥有的父类的方法和属性。“is-a” 关系指的是类似这样的关系:狗是动物,dog is animal。狗类就应该继承动物类。

“has-a”关系,我们可以使用“组合”,也能实现一个类拥有另一个类的方法和属性。” has-a”关系指的是这样的关系:手机拥有 CPU。 MobilePhone has a CPU。


import copy
class MobilePhone():
    def __init__(self,cpu,screen):
        self.cpu=cpu
        self.screen=screen

class Cpu():
    def calculate(self):
        print("计算。。。")
        print("CPU:",self)  #展现方法的地址

class Screen():
    def show(self):
        print("展示。。。")
        print("Screen:",self)

c1=Cpu()
s1=Screen()
m1=MobilePhone(c1,s1)
m1.cpu.calculate()  #此处通过组合就可以调用cpu对象,相当于手机对象简介拥有了CPU类的方法

四.设计模式_工厂模式实现、设计模式_单例模式实现

工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进 行统一的管理和控制。

1.设计模式_工厂模式实现

class CarFactory():
    def car(self,brand):
        if(brand=="奔驰"):
            return Benz()

        if(brand=="宝马"):
            return  BMV()

        if(brand=="比亚迪"):
            return BYD()

        else:
            print("版本无效,无车!")
class Benz():
    pass

class BMV():
    pass

class BYD():
    pass

factory=CarFactory()
print(factory.car("奔驰"))
print(factory.car("比亚迪"))

2.设计模式_单例模式实现

单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一 个访问该实例的全局访问点。

单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较 多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久 驻留内存中,从而极大的降低开销。

这里我们推荐重写_init_方法

class Mysingleton():  #单例模式一般通过重写_new()_方法来实现
    __obj=None
    __singleflag=True  #定义类属性
    def __new__(cls, *args, **kwargs):  #定义构造方法
        if cls.__obj==None:  #cls对象进行调用__obj属性
            cls.__obj=object.__new__(cls)  #通过object对象调用构造方法创建cls对象,此处__object属性不为空
        return cls.__obj
    def __init__(self,name):
        if Mysingleton.__singleflag:
            print("init...")
            self.name=name
            Mysingleton.__singleflag=False  #使得不会再输出print语句,此处对__singleflag重新复制,不需要写双等号,双等号只需要再循环语句中写出

a=Mysingleton("aa")
print(a)
b=Mysingleton("bb")
print(b)

注意:==只用在循环的判断条件中,在别处不可使用==进行赋值

设计模式称之为“模式”,就是一些固定的套路。我们很容易用到其他场景上,比如前面讲 的工厂模式,我们需要将工厂类定义成“单例”,只需要简单的套用即可实现:

class CarFactory():
    __obj = None
    __singleflag = True  # 定义类属性
    def car(self,brand):
        if(brand=="奔驰"):
            return Benz()

        if(brand=="宝马"):
            return  BMV()

        if(brand=="比亚迪"):
            return BYD()

        else:
            print("版本无效,无车!")



    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:  # cls对象进行调用__obj属性
            cls.__obj = object.__new__(cls)  # 通过object对象调用构造方法创建cls对象,此处__object属性不为空
        return cls.__obj
    def __init__(self):
        if CarFactory.__singleflag:
            print("init...")
            CarFactory.__singleflag = False  # 使得不会再输出print语句,此处对__singleflag重新复制,不需要写双等号,双等号只需要再循环语句中写出
class Benz():
    pass

class BMV():
    pass

class BYD():
    pass

factory=CarFactory()
factory1=CarFactory()

print(factory)
print(factory1)

#要注意全篇的缩进,否则不能识别为函数

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值