面对对象2

一. 面对对象三大特征介绍

  • 封装(隐藏)

通过私有属性,私有方法的方式进行封装

  • 继承

继承可以让子类继承父类特性,提高代码重用性
是一种增量进化,在父类基础上增加功能,改进算法

  • 多态

同一种方法调用对象不同会产生不同行为

1. 继承

  1. 已有的类称为父类或基类,新的类称为子类或派生类
  2. Python支持多重继承,一个子类可以继承多个父类
  3. 类定义中若没有指定父类,则默认是object类,它是所有类的父类,里面定义了一些类共有的默认操作,比如__new__
  4. 定义子类时,必须在其构造函数内调用父类的构造函数
#测试继承的基本使用
class Person:     #可以不定义构造器

    def say_age(self):
        print("年龄我不知道")

class Student(Person):
    pass

print(Student.mro())   #查看继承结构

s=Student()
s.say_age()


# 测试继承的基本使用
class Person:

    def __init__(self,name,age):
        self.name=name
        self.__age=age    #父类的私有属性,子类也会继承,但是要带上父类名去调用

    def say_age(self):
        print("年龄我不知道")


class Student(Person):

    def __init__(self,name,age,score):
        Person.__init__(self,name,age)    #子类必须显示调用父类构造器,共享父类代码
        self.score=score    #自己特有的属性


print(Student.mro())  # 查看继承结构

s = Student("gao",18,72)
s.say_age()
print(s.name)
#print(s.age) #'Student' object has no attribute 'age'
print(s.__dict__)   #{'name': 'gao', '_Person__age': 18, 'score': 72}说明继承了,不过名字里有父类
print(s._Person__age)

1. 类成员的继承与重写

  1. 子类继承了父类除构造方法之外的所有成员(包括私有属性和方法,但要通过父类名来调用
  2. 方法重写:子类可以重新定义父类中的方法,这样会覆盖父类的方法
class Person:

    def __init__(self, name, age):
        self.name = name
        self.__age = age  # 父类的私有属性,子类也会继承,但是要带上父类名去调用

    def say_age(self):
        print("我的年龄是:",self.age)
    def say_name(self):
        print("我的名字是:{0}".format(self.name))


class Student(Person):

    def __init__(self, name, age, score):
        Person.__init__(self, name, age)  # 子类必须显示调用父类构造器,共享父类代码
        self.score = score  # 自己特有的属性
    def say_name(self):
        print("报告老师,我的名字是:",self.name)


s = Student("gao", 18, 72)
s.say_name()

2. 常用方法

3. 多重继承

  1. 多重继承使类的整体层次异常复杂,尽量避免使用
  2. 父类出现相同名字方法,从左至右搜索
  3. mro也是按从左至右的顺序
class A:
    def aa(self):
        print("aa")
    def say(self):
        print("AAA")
class B:
    def bb(self):
        print("bb")
    def say(self):
        print("BBB")
class C(B,A):     #没有构造函数,也可以继承
    def __init__(self,name):
        self.name=name
    def cc(self):
        print("cc")

c=C(3)
print(C.mro())  #[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
c.aa()
c.bb()
c.cc()
c.say()   #父类中出现名称相同的方法,按从左向右搜索


4. super()获得父类定义

  1. 子类中想获得父类方法,可以通过super()
  2. 和直接用父类名调用效果一样
class A:
    def say(self):
        print("A:",self)
        print("say AAA")
        
class B(A):
    def say(self):
        super().say()   #和直接用A.say()效果一样
        print("B:",self)


b=B()
b.say()

2. 多态

  1. 多态指同一方法调用由于对象不同会产生不同行为
  2. 方法有多态,属性没有多态
  3. 多态必要条件:继承,方法重写
class Man:
    def eat(self):
        print("饿了,吃饭")

class Chinese(Man):
    def eat(self):
        print("用筷子吃饭")

class English(Man):
    def eat(self):
        print("用叉子吃饭")
class Indian(Man):
    def eat(self):
        print("用右手吃饭")
    
def manEat(m):
    if isinstance(m,Man):
        m.eat()
    else:
        print("不能吃饭")
#Chinese.eat()    #TypeError: eat() missing 1 required positional argument: 'self'
manEat(Chinese)
manEat(English())   #有没有括号都可以

二. 特殊方法和属性

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

  1. Python的运算符实际上是通过调用对象的特殊方法实现的
  2. 常见的特殊方法:

__init __: 构造方法 (对象创建:p=Person())
__del __:析构方法
__call __:函数调用(函数名(参数)直接调用被__call __定义过的方法)
__len __:长度

  1. 每个运算符都对应了相应方法:

+:__add __
-:__sub __
<,<=,==,>,>=,!=:__lt __, __le __, __eq __, __gt __, __ge __, __ne __
|,^,&:__or __, __xor __, __and __
<<,>>:__lshift __, __rshift __
*,/,%,//:__mul __, __truediv __, __mod __, __floordiv __
** : __pow __

  1. 可以重写上述特殊方法,实现运算符重载
class Person:
    def __init__(self,name):
        self.name=name
    def __add__(self,other):
        if isinstance(other,Person):
            return("{0}--{1}".format(self.name,other.name))   #注意是other.name
        else:
            return "不是同类"
    def __mul__(self,other):
        if isinstance(other,int):
            return self.name*other
        else:
            return"不是同类对象"
        

p1=Person("gao")
p2=Person("peng")

x=p1+p2     #加号调用的是__add__函数
print(x)

print(p1*3)     #乘号调用的是__mul__函数

2. 特殊属性

class A:
    def aa(self):
        print("aa")
    def say(self):
        print("AAA")
class B:
    def bb(self):
        print("bb")
    def say(self):
        print("BBB")
class C(B,A):     #没有构造函数,也可以继承
    def __init__(self,name):
        self.name=name
    def cc(self):
        print("cc")

c=C(3)
c.aa()
c.bb()
c.cc()
c.say()   #父类中出现名称相同的方法,按从左向右搜索
print(dir(c))     #dir()是内置函数
print(c.__dict__)
print(c.__class__)
print(C.__bases__)  #只有一个父类用base,必须用C(类型名),而不是c
print(C.mro())    #必须用C(类型名),而不是c
print(A.__subclasses__)  #用类型名

三. 浅拷贝与深拷贝

  1. 变量的赋值:只是形成两个变量指向同一对象
  2. 浅拷贝:对象包含的子对象内容不拷贝,源对象与拷贝对象引用同一子对象
  3. 递归拷贝对象中包含的子对象,源对象与拷贝对象的子对象不同
#测试对象的浅拷贝,深拷贝
import copy     #copy要导入copy包
class MobilePhone:
    def __init__(self,CPU,screen):
        self.CPU=CPU
        self.screen=screen

class CPU:
    def calculate(self):
        print("算1234567")
        print("cpu对象:",self)

class Screen:
    def show(self):
        print("显示一个好看的画面")
        print("screen对象:",self)

#测试变量赋值
c1=CPU()
c2=c1
print(c2)
print(c1)
'''地址相同
<__main__.CPU object at 0x000001870105EC48>
<__main__.CPU object at 0x000001870105EC48>
'''

#测试浅复制
s1=Screen()
m1=MobilePhone(c1,s1)
m2=copy.copy(m1)
print(m1,m1.CPU,m1.screen)
print(m2,m2.CPU,m2.screen)
'''
m1和m2不同,cpu和screen相同
<__main__.MobilePhone object at 0x0000018701066088> <__main__.CPU object at 0x000001870105EC48> <__main__.Screen object at 0x000001870105EB88>
<__main__.MobilePhone object at 0x0000018701066108> <__main__.CPU object at 0x000001870105EC48> <__main__.Screen object at 0x000001870105EB88>
'''
#测试深复制
m3=copy.deepcopy(m1)
print(m1,m1.CPU,m1.screen)
print(m3,m3.CPU,m3.screen)
'''
都不相同
<__main__.MobilePhone object at 0x0000018701066088> <__main__.CPU object at 0x000001870105EC48> <__main__.Screen object at 0x000001870105EB88>
<__main__.MobilePhone object at 0x0000018700FE97C8> <__main__.CPU object at 0x0000018700FEB048> <__main__.Screen object at 0x0000018701066148>
'''

四. 组合

is关系用继承,has关系用组合

#测试组合
#继承:
class A1:
    def say_a1(self):
        print("a1,a1,a1")
    
class A2(A1):
    pass

a2=A2()
a2.say_a1()

#组合:
class A1():
    def say_a1(self):
        print("a1,a1,a1")
    
class A2:
    def __init__(self,a):
        self.a=a    

a1=A1()
a2=A2(a1)  #或直接写成a2=A2(A1())
a2.a.say_a1()

五. 练习

1. 工厂模式

class CarFactory:
    def create_car(self,brand):
        if brand=="奔驰":
            return Benz()
        elif brand=="宝马":
            return BMW()
        elif brand== "比亚迪":
            return BYD()
        else:
            return "未知品牌,无法创建"
        
    
class Benz:
    pass

class BMW:
    pass

class BYD:
    pass

factory=CarFactory()
c1=factory.create_car("奔驰")
c2=factory.create_car("宝马")
print(c1,c2)

2. 单例模式

class MySingleton:
    
    __obj=None  #类属性
    
    def __new__(cls,*args,**kwargs):
        if cls.__obj==None:
            cls.__obj=object.__new__(cls)     #调用object类的__new__方法创建对象
        return cls.__obj
    def __init__(self,name):
        print("init...")
        self.name=name
        
a=MySingleton("aa")
b=MySingleton("bb")
print(a)
print(b)
'''创建了一次,但是初始化两次'''

class MySingleton:
    
    __obj=None  #类属性
    __init_flag=True
    
    def __new__(cls,*args,**kwargs):
        if cls.__obj==None:
            cls.__obj=object.__new__(cls)     #调用object类的__new__方法创建对象
        return cls.__obj
    def __init__(self,name):
        if MySingleton.__init_flag:
            print("init...")
            self.name=name
            MySingleton.__init_flag=False   #不能写成self.__init_flag
a=MySingleton("aa")
b=MySingleton("bb")
print(a)
print(b)

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页