【0828 | Day 25】类的组合/多态与多态性/封装

组合

一、什么是组合

对象的某个属性是另外定义的一个类的对象

#举个栗子
class Animal:
	def __init__(self, level):
        self.level = level
        
class Level:
        pass
    
#Animal类的属性level是另一个类的对象
level = Level()
l = Animal(level) 

二、为什么使用组合

  • 减少代码冗余

    class Person:
        school = 'oldboy'
    
    class Teacher(Person):
        def __init__(self,name,age,level,course):
            self.name = name
            self.age = age
            self.level = level
            #course是课程对象,表示老师教授的课程
            self.course = course
    
    class Student(Person):
        def __init__(self,name,age,course):
            self.name = name
            self.age = age
            # course是课程对象,表示学生选的课程
            self.course = course
    
    class Course:
        def __init__(self,course_name,course_price,course_period):
            self.name = course_name
            self.price = course_price
            self.period = course_period
    
            
    course=Course('Python', 20000, 6)
    stu=Student('nick', 19, course)
    teacher=Teacher('nick', 19, '高级', course)
    
    #查看老师教授的课程名
    print(teacher.course.name)  #Python
    

三、如何使用组合

class Person:
    school = 'oldboy'
    
class Teacher(Person):
    def __init__(self, name, age, level, course):
        self.name = name
        self.age = age
        self.level = level
        #course是课程对象,表示老师教授的课程
        self.course = course

class Student(Person):
    # course=[]  #错误
    def __init__(self, name, age):
        self.name = name
        self.age = age
        # course是课程对象,表示学生选的课程
        self.course_list = []
    def choose_course(self, course):
        # self.course=[]  #错误
        #把课程对象追加到学生选课的列表中
        self.course_list.append(course)

    def tell_all_course(self):
        #循环学生选课列表,每次拿出一个课程对象
        for course in self.course_list:
            #课程对象.name  取到课程名字
            print(course.name)

class Course:
    def __init__(self,course_name,course_price,course_period):
        self.name = course_name
        self.price = course_price
        self.period = course_period



course = Course('Python',20199,7)
stu1 = Student('nick',19)
stu1.choose_course(course)
stu2 = Student('王二丫',19)
stu2.choose_course(course)
stu2.choose_course(Course('linux',19999,5))


#查看stu1选的所有课程名称
#方式一(通过普通函数)
 def tell_all_course(student):
     for course in student.course_list:
        print(course.name)

tell_all_course(stu1)
tell_all_course(stu2)

#方式二(通过对象的绑定方法)
stu1.tell_all_course()
stu2.tell_all_course()

多态和多态性

一、什么是多态

表示一类事物具有多种形态,例如class Animal,这个Animal类里又分为人、猪、猫等等

二、什么是多态性

表示向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)

class Animal:
    def run(self):  # 子类约定俗称的必须实现这个方法  #def click(self):....等
        raise AttributeError('子类必须实现这个方法')


class People(Animal):
    def run(self):
        print('人正在走')


class Pig(Animal):
    def run(self):
        print('pig is walking')


class Dog(Animal):
    def run(self):
        print('dog is running')


peo1 = People()
pig1 = Pig()
d1 = Dog()     

# 多态性:一种调用方式,不同的执行效果(多态性)
def func(obj):
    obj.run()
 	#obj.click()
    #ocj.bite()
    ...


func(peo1)
func(pig1)
func(d1)

#人正在走
#pig is walking
#dog is running

总结:多态性是一个接口(函数func)的多种实现(如obj.run(),obj.talk(),obj.click(),len(obj))

三、多态性的优点

  1. 增加了程序的灵活性:以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
  2. 增加了程序额可扩展性:通过继承Animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
class Cat(Animal):  # 属于动物的另外一种形态:猫
    def talk(self):
        print('say miao')


def func(animal):  # 对于使用者来说,自己的代码根本无需改动
    animal.talk()


cat1 = Cat()  # 实例出一只猫
func(cat1)  # 甚至连调用方式也无需改变,就能调用猫的talk功能

四、鸭子类型

可以用一个函数去调用任意定义的类中的方法,例如:

#崇尚鸭子类型:只要走路像鸭子(对象中有某个绑定方法),那你就是鸭子

class Pig:
    def speak(self):
        print('哼哼哼')
class People:
    def speak(self):
        print('say hello')

pig=Pig()
pe=People()

def animal_speak(obj):  #同一函数调用
    obj.speak()

    
animal_speak(pig)
animal_speak(pe)

封装

一、什么是封装

封装即将许多东西装进麻袋,然后封口隐藏,使得外部无法访问。

二、如何隐藏属性/方法

  1. 隐藏属性:通过__变量名来隐藏(可以内部调用)

    • 更安全
    class Person:
        def __init__(self, name):
            self.__name = name
        def check_name(self):
            return '%s' %self.__name   #可以内部调用
    
    p = Person('nick')
    
    #访问name
    print(p.name)
    print(p.__name)
    #以上两种无法获取,已被隐藏。
    print(p.get_name())  #可通过函数内部调用获取
    
    #获取方法
    ①--> print(p.__dict__)  #获取隐藏名
    ②--> print(p._Person__name) 
    
    
  2. 隐藏方法:通过__方法名来隐藏

    • 隔离复杂度
    class Person:
        def __init__(self,name,age):
            self.__name = name
            self.__age = age
        def __speak(self):
            print('6666')
    
    p=Person('nick',89)
    #p.__speak() 无法调用
    
    #获取方法
    ①--> print(Person.__dict__)
    ②--> p._Person__speak()
    
    

    注意:在类内部以__变量名命名的变量,都会被隐藏。在外部放入的__变量名,属性不隐藏。

    举个栗子:

    class Person:
        def __init__(self,name,age):
            self.__name = name
            self.__age = age
        def set_xx(self,xx):
            self.__xx = xx
            print(self.__xx)
    
    p=Person('nick',18)
    
    p.__level = 5 #在类外__变量名放入新变量,不会隐藏属性
    
    p.set_xx('6688')
    

property装饰器

一、什么是property

将方法包装成数据属性

#计算人的bmi指数
#property装饰器:把方法包装成数据属性

class Person:
    def __init__(self, name, height, weight):
        self.name = name
        self.height = height
        self.weight = weight
    
    @property
    def bmi(self):
        return self.weight/(self.height**2)


p = Person('lqz', 1.82, 70)
# print(p.bmi()) #用了@property,不需要再加括号调用
print(p.bmi)

p.name='ppp'
print(p.name)  #ppp

p.bmi=90
print(p.bmi) #报错,因为此时的bmi已转为数据属性,是会随着参数而改变的,所以不可修改。

二、property之setter和deleter

class Person:
    def __init__(self, name, height, weight):
        self.__name = name
        self.__height = height
        self.__weight = weight
    
    @property
    def name(self):
        return '[我的名字是:%s]' %self.__name
    #用property装饰的方法名.setter
    
    @name.setter
    def name(self,new_name):
        # if not isinstance(new_name,str):
        if type(new_name) is not str:
            raise Exception('改不了')
        if new_name.startswith('sb'):
            raise Exception('不能以sb开头')
        self.__name = new_name

    # 用property装饰的方法名.deleter
    
    @name.deleter
    def name(self):
        # raise Exception('不能删')
        print('删除成功')
        # del self.__name

p=Person('lqz',1.82,70)
# print(p.name)
# p.name='pppp'
# p.name='xxx'
#改不了,直接抛一异常
# p.name=999
# p.name='sb_nick'

# print(p.name)

del p.name
print(p.name)
posted @ 2019-08-28 21:00  fxyadela  阅读(159)  评论(2编辑  收藏  举报