1011 笔记

组合

1.什么是组合

在一个类中以另外一个类的对象作为数据属性,称为类的组合。

继承是一个子类是一个父类的关系,而组合则是一个类有另一个类的关系。

组合就是一个类中使用到另一个类,从而把几个类拼到一起。组合的功能也是为了减少重复代码。

2.为什么要使用组合

组合的目的和继承一样,为了减少代码冗余

3.如何使用组合

# 定义父类
class people:
    def __init__(self,name,age):
        self.name = name
        self.age =age
# 定义学生类
class teach(people):
    def __init__(self,name,age):
        super().__init__(name,age)
# 定义老师类
class student(people):
    def __init__(self,name,age):
        super().__init__(name,age)

# 定义一个日期类
class Data:
    def __init__(self,n,y,d):
        self.n = n
        self.y = y
        self.d = d
    def dayin(self):
        print(f'''
        ===打印年月日===
        年:{self.n}
        月:{self.y}
        日:{self.d}
        ''')
# 实例化teach得到对象t
t = teach('aaa','s')
# 实例化Data 得到data_obj对象
data_obj = Data(1999,10,1)
# 将data_obj添加到对象t中,让t 可以调用Data的方法
t.data = data_obj
# t中有data_obj == t中可以使用Data的方法
t.data.dayin()

组合的练习

'''
选课系统需求:
    1.学生类,老师类, 学生和老师都有课程属性, 每一门课程都是一个对象.
        课程: 课程名字,课程周期,课程价钱

    2.学生和老师都有选择课程的功能, 还有打印所有课程的功能.
'''


# 定义父类
class people:
    def __init__(self,name,age,sex):
        self.name = name
        self.age =age
        self.sex = sex
    '''定义选课的方法'''
    def add_kecheng(self,course_obj):
        '''将选择的课程传入'''
        self.course_list.append(course_obj) # self自己的list列表增加传入的课程

    '''得到一个老师学生的对象'''
    def print_all(self): # (传入当前的老师或学生对象)
        '''循环拿到当前对象的课程列表,列表中存放的是一个个的课程对象'''
        for course_obj in self.course_list:  # 对象的课程列表(之前追加的课程)
            '''循环每一个课程对象调用查看课程信息的方法'''
            course_obj.get_info() # 获取到的课程对象直接调用其中的打印方法

# 定义老师类
class teach(people):
    def __init__(self,name,age,sex):
        super().__init__(name,age,sex)
        # 学生选课的功能
        self.course_list = []


# 定义学生类
class student(people):
    def __init__(self,name,age,sex):
        super().__init__(name,age,sex)
        self.course_list = []


# 定义一个课程类
class Course:
    '''定义课程类的名称周期价格'''
    def __init__(self,course_name,course_period,course_prize):
        self.course_name = course_name
        self.course_period = course_period
        self.course_prize = course_prize

    def get_info(self):
        '''打印课程的所有信息'''
        print(f'''
        课程名称:{self.course_name}
        课程周期:{self.course_period}
        课程价格:{self.course_prize}
        ''')


# 实例化老师与学生的对象
tea1 = teach('老师',10,'男性')
stu1 = student('学生',50,'男性')
# 实例化课程的对象
python_obj = Course('python0',6,2.0)
linux_obj = Course('linux',6,1.0)

# 通过老师学生将两门课程对象添加进teach内
'''将整个课程信息实例化的对象传入了add_kecheng方法中
教师类中列表course_list接受课程信息'''
tea1.add_kecheng(python_obj)
tea1.add_kecheng(linux_obj)

'''将保存在tea1中的python获取并使用打印方法'''
# tea1.course_list[0].get_info()
# python_obj.get_info()
'''直接调用查看所有的课程'''
tea1.print_all()

总结

继承:

类与类的关系,一种什么是什么的关系,子类与父类是从属关系

组合:

对象与对象的关系,一种什么有什么的关系,一个对象拥有另一个对象

封装

1.什么是封装

把一堆属性(特征与技能)封装到一个对象中,对象可以通过.的方式获取属性

这就是面向对象的第一个特性(好处)封装

封装特性,可以把复杂的信息,流程,包起来,内部处理,让使用者不去关注细节

2.为什么要封装

目的是为了方便存取,可以通过对象.属性的方式获取属性.

3.如何封装

特征 : 变量 ==> 数据类型
技能 : 函数 ==>方法属性

在类内部定义一堆属性(特征与技能)

通过 对象.属性 = 属性值 方式

访问限制机制

在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问

1.什么是访问限制机制

在类内部定义,凡是以__开头的数据属性与方法属性

都会被python内部隐藏起来,让外部不能直接访问类内部__开头的属性.

比如  __name = 'tank'

2.访问限制的目的

一堆隐私的属性与不能被外部轻易访问的属性,可以隐藏起来,不被外部直接调用

好处: 对重要数据获取的逻辑更加严谨,进而保证了数据的安全.

class Foo:
    # 数据类型
    __name = 'tank'
    # 方法属性
    def __run(self):
        print('runing...')
foo = Foo()
print(Foo.__name)
'''报错type object 'Foo' has no attribute '__name''''

接口

隐私属性可以挺过封装一个接口,在借口内做业务逻辑的处理,再把数据返回给调用者

# 类在定义时执行,使用接口,隐私
class Foo:
    # 数据类型
    __name = 'tank'
    # 方法属性
    def __run(self):
        print('runing...')
    # 接口
    def get_name(self):
        '''在接口里返回出去,类内部访问'''
        # 可以做些业务逻辑判读是否给你访问
        return self.__name
    
foo = Foo()
res = foo.get_name()
print(res)
# tank

'''内部修改'''

    def set_name(self):
        self.__name = 'nick'

foo = Foo()
foo.set_name()
print(foo.get_name())
 # nick

   
'''访问限制判断'''

class ATM:
    # 1.插卡
    def __inster_card(self):
        print('插卡')
        pass
    # 2.输入密码
    def __input_pwd(self):
        print('输入密码')
        pass
    # 3.输入取款
    def __money(self):
        print('输入金额')
        pass
    # 4.开始吐钱
    def __getmoney(self):
        print('开始吐钱')
        pass
    # 5.打印账单
    def flow(self):
        print('流水')
        pass

    # 取钱直接接口,封装所有的隐藏接口
    def withdraw(self):
        self.__inster_card()
        self.__input_pwd()
        self.__money()
        self.__getmoney()
        self.flow()

# 实例化atm
atm = ATM()
atm.withdraw()
    
    

注意: 在python中,不会强制限制属性的访问,类内部__开头的属性,只是做了一种变形

class Foo:
    __name = 'tank'
        # 将__name改成 _student__name了
print(foo._Foo__name)
# tank
_(父类)__(属性名)  可以直接获取

property

1.什么是property

python中内置的装饰器,主要是给类内部的方法使用

2.为什么要用property

将类内部的方法def 方法名()变成def 方法,

在对象调用某个方法是将对象.方法()变成对象.方法,看着像数据属性

3.如何使用property

@ property

注意 不能对呗装饰过的方法属性修改

'''
计算人体bmi, bmi = 体重/身高的平方
'''
class People:
    def __init__(self,name,w,h):
        self.name = name
        self.w = w
        self.h = h

    def bmi(self):
        return self.w / (self.h ** 2 )

t1 = People('wang',160,175)
print( t1.bmi() )  
# 加()像是动词,所以使用property 让其变为名词


'''使用 @ property '''

class People:
    def __init__(self,name,w,h):
        self.name = name
        self.w = w
        self.h = h
        
    @property   # 在想要变成普通的函数上进行调用
    def bmi(self):
        return self.w / (self.h ** 2 )

t1 = People('wang',160,175)
print( t1.bmi )  # 打印时去除括号()



'''不能对被装饰过的方法进行属性修改'''
t1.bmi = 18  
#  会进行报错

了解: 可以通过特殊方法来进行修改(通过修改类中属性)

# 改
class People:
    def __init__(self, name, w, h):
        self.name = name
        self.w = w
        self.h = h

    @property  # 在想要变成普通的函数上进行调用
    def bmi(self):
        return self.w / (self.h ** 2)

    @property
    def get_name(self):
        return self.name

    @get_name.setter
    def set_name(self, val):
        self.name = val


t1 = People('wang', 160, 175)
print(t1.get_name)
t1.set_name = 'tank'
print(t1.set_name)
'''wang
tank'''

多态

1.什么是多态

多态指的是同一种事物的多种形态,

就是同样的行为,后代们有多种不同的状态

多态就是 从父亲那里继承来的同一个的行为, 孩子们各自的表现状态不一样

2.多态的目的

多态也称之为多态性,在程序中继承就是多态的表现形式

多态的目的是为了, 让多种不同类型的对象, 在使用相同功能的情况下,调用同一个名字的方法名.

父类: 定义一套统一的标准

子类: 遵循父类统一的标准

多态的最终目的: 统一子类编写的规范,为了让使用者更方便调用相同功能的方法

3.如何实现

1.继承父类

在python中不会强制要求子类必须遵循父类的一套标准,所以出现了抽象类

2.抽象类abc

1.是什么:

abc模块 abstract_class

2.使用的目的

强制子类必须遵循父类的一套标准

3.如何使用

import abc

import abc

class animal(metaclass=abc.ABCMeta):

    @abc.abstractclassmethod
    def eat(self):
        pass

    @abc.abstractclassmethod
    def drink(self):
        pass

    @abc.abstractclassmethod
    def speak(self):
        pass


class pig(animal):

    def eat(self):
        pass

    def speak(self):
        pass

    def drnk(self):
        pass

p = pig()

# 只要继承了父类,就必须有父类的方法,可以多不能少

3.鸭子类型

1.什么是鸭子类型

鸭子类型是编程语言中动态类型语言中的一种设计风格,一个对象的特征不是由父类决定,而是通过对象的方法决定的

Python 不检查传入的对象的类型,这种方式通俗的被称为「鸭子类型」,比较高端的方式是叫做「隐式类型」或者「结构式类型」。

==例如迭代器,我们并不需要继承Iterable或者Iterator,只需要实现__iter__ 和 __next__方法的对象都可称之为迭代器,本身可以为任何类==

在不知道当前对象是何物的情况下,但是你长得像鸭子,那么你就是鸭子类型

在python中,不推荐使用抽象类强制限制子类的定义,但推荐类都遵循鸭子类型

鸭子类型就意味着可以向任何对象发送任何的消息,语言只关心这个对象能不能接收该消息,不会去强求该对象是否为某一种特定的类型 —— 该对象的多态表现。

代码

class Animal(object):

    def run(self):
        print("The animal is running...")


class Dog(Animal):

    def run(self):
        print('The dog is running...')


class Cat(Animal):

    def run(self):
        print('The cat is running...')

# 定义一个函数,只需要保证传入的有一个.run方法即可
def makeRun(animalType):
    animalType.run()

dog = Dog()
cat = Cat()
makeRun(dog)
makeRun(cat)
'''
The dog is running...
The cat is running...
'''

我们可以使用一个函数 makeRun() 来访问不同 Animal 子类中的相同方法。但其实对于上面的 makeRun() 函数来说,传入的参数并不一定需要是 Animal 类型的,只需要保证传入的对象有一个 run() 方法即可,如下面代码所示。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

class Person:
    def run(self):
        print("The person is running...")

person = Person()
makeRun(person)
# The person is running...

而在静态语言中,如 Java ,如果需要传入 Animal 类型,则传入的对象就必须是 Animal 类型或者它的子类,否则,将无法调用 run() 方法。

-继承

耦合性太高,程序的可扩展性差

-鸭子类型

耦合性低,程序的可扩展性强

posted @ 2019-10-11 21:17  fwzzz  阅读(171)  评论(0编辑  收藏  举报