面向对象,全栈开发

By admin in 4858.com on 2019年4月12日

面向对象-组合

一、面向进度与面向对象的简介

一、继承

一、多态与多态性

一.怎么是构成

一.面向进程:

  定义:面向进程的次序设计的大旨是经过(流水生产线式思维),进程即消除难点的步骤,面向进度的筹划就好比精心设计好一条流水生产线,思虑周密几时处理什么事物。

  优点:一点都不小的大跌了写程序的复杂度,只必要顺着要履行的手续,堆叠代码即可。

  缺点:1套流水生产线或然流程正是用来消除三个标题,代码牵一发而动全身。

一.怎么样继承

接轨是一种创立新类的方法,新建的类能够一而再3个或多个父类(python援助多三番4回),父类又可称之为基类或超类,新建的类称为派生类或子类。**

1.多态

(1)什么是多态
多态指的是一类东西有三种模样,(三个抽象类有四个子类,由此多态的概念依赖于继续)

  • 队列类型有四种造型:字符串,列表,元组。
  • 动物有各种样子:人,狗,猪
  • 文本有多样形象:文本文件,可执行文件

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')

import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形态之一:文本文件
    def click(self):
        print('open file')

class ExeFile(File): #文件的形态之二:可执行文件
    def click(self):
        print('execute file')

(二)多态的作用是如何
大家领略,封装能够隐蔽达成细节,使得代码模块化;继承能够扩充已存在的代码模块(类);它们的指标都以为了——代码重用。而多态则是为着兑现另2个指标——接口重用!多态的效果,就是为着类在接二连三和派生的时候,有限支撑使用“家谱”中任1类的实例的某一属性时的不易调用。
Pyhon 很多语法都以帮助多态的,比如 len(),sorted(),
你给len传字符串就回去字符串的尺寸,传列表就赶回列表长度。

class Animal(object):
    def __init__(self, name):  # Constructor of the class
        self.name = name

    def talk(self):              # Abstract method, defined by convention only
        raise NotImplementedError("Subclass must implement abstract method")

class Cat(Animal):
    def talk(self):
        print('%s: 喵喵喵!' %self.name)

class Dog(Animal):
    def talk(self):
        print('%s: 汪!汪!汪!' %self.name)

def func(obj): #一个接口,多种形态
    obj.talk()

c1 = Cat('小晴')
d1 = Dog('李磊')

func(c1)
func(d1)

  组合指的是某2个对象拥有1特性质,该属性的值是其它3个类的目的

2.面向对象:

  定义:面向对象的次第设计的中坚是指标(上帝式思维),要了然对象为什么物,必须把团结当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也足以制造出来。

  优点:解决了程序的扩充性。对某三个指标单独修改,会立时反映到总种类统中,如对游戏中1人物参数的特征和技艺修改都很简单。

  缺点:可控性差,不能向面向进程的次第设计流水生产线式的能够很精准的展望难点的拍卖流程与结果,面向对象的顺序1旦初叶就由对象时期的交互化解难点,即就是上帝也心慌意乱臆想最后结出。

2.怎么要有继续

子类会“”遗传”父类的脾性,从而化解代码重用难题,减弱代码的冗余

2.多态性

多态性(polymorphisn)是允许你将父对象设置成为和贰个或更加多的他的子对象相等的技术,赋值之后,父对象就足以依照近期赋值给它的子对象的特征以分化的措施运维。一句话来说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
(一)什么是多态性 (请务必注意:多态与多态性是二种概念。)
多态性是指具备不一致功效的函数能够选择同一的函数名,这样就足以用二个函数名调用不一致效用的函数。

在面向对象方法中1般是那般表述多态性:向分化的目的发送同一条音信(obj.func():是调用了obj的方法func,又称为向obj发送了一条新闻func),差异的指标在收受时会发生分裂的一言一动(即方法)。也正是说,各样对象能够用本人的办法去响应共同的新闻。所谓音讯,正是调用函数,不一样的行事就是指不相同的贯彻,即执行不一的函数。

譬如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生实施的是放学操作,纵然两者新闻无差距于,不过进行的功效差别

多态性分为静态多态性和动态多态性

  • 静态多态性:如别的类型都可以用运算符+举行演算
  • 动态多态性:如下
    4858.com 1

>>> def func(animal): #参数animal就是多态性的体现
...     animal.talk()
... 
>>> people1=People() #产生一个人的对象
>>> pig1=Pig() #产生一个猪的对象
>>> dog1=Dog() #产生一个狗的对象
>>> func(people1) 
say hello
>>> func(pig1)
say aoao
>>> func(dog1)
say wangwang

>>> def func(f):
...     f.click()
... 
>>> t1=Text()
>>> e1=ExeFile()
>>> func(t1)
open file
>>> func(e1)
execute file

综上大家也能够说,多态性是‘一个接口(函数func),多样兑现(如f.click())。

(二)为啥要用多态性(多态性的好处)
实际大家从上边多态性的例证能够看看,大家并未扩张哪些新的学问,也正是说python自个儿正是支撑多态性的,这么做的好处是怎么样啊?

  • 追加了程序的灵活性
    有序,不论对象风云万变,使用者都以1致种情势去调用,如func(animal)
  • 扩展了程序额可扩充性
    因而继承animal类成立了1个新的类,使用者无需更改自个儿的代码,照旧用func(animal)去调用

>>> class Cat(Animal): #属于动物的另外一种形态:猫
...     def talk(self):
...         print('say miao')
... 
>>> def func(animal): #对于使用者来说,自己的代码根本无需改动
...     animal.talk()
... 
>>> cat1=Cat() #实例出一只猫
>>> func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能
say miao

诸如此类我们新增了2个形态Cat,由Cat类产生的实例cat1,使用者能够在一齐不必要修改本身代码的情景下。使用和人、狗、猪一样的法门调用cat一的talk方法,即func(cat1)

 1 class Foo:
 2     xxx = 111
 3 
 4 class Bar:
 5     yyy = 222
 6 
 7 obj = Foo()
 8 obj.attr = Bar()
 9 
10 print(obj.xxx)
11 >>>111
12 print(obj.attr.yyy)
13 >>>222

贰、面向对象的家庭成员介绍

三.怎么选择持续

eg:

class ParentClass1: # 定义父类1
    pass

class ParentClass2: # 定义父类2
    pass

class Subclass1(ParentClass1): # 单继承 父类1
    pass

class Subclass2(ParentClass1,ParentClass2):  # 多继承多个父类  父类1 父类2
    pass

print(Subclass1.__bases__)  # 查看所有父类信息
print(Subclass2.__bases__)  # 查看所有父类信息

结果:以元组的形式返回
(<class '__main__.ParentClass1'>,)
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

 

二、封装

 

一.初识类和指标

对象:

(1)指任何物体(‘万事万物皆为指标’)

(二)分裂的对象有不一致的性质,万物皆有转变——对象的不2法门。

(3)对于其余1个特性都具备一个位置:属性所属的对象,属性的值,属性的名目。对象有个别属性并不是一层不变的。

类:

(壹)物以类聚——类定义对象——饼干模具生产饼干

(二)类是由同样的特色结合,类是概念同一类具有指标的变量和艺术的蓝图。

(三)对象的共性抽象为类,类的实例化正是指标。

四.延续与虚幻(先抽象再持续)

先抽象:抽取对象之间相似之处获得了类,在计算类与类之间的貌似得到父类

再持续:(子类继承父类,子类能够遗传父类属性)是依据抽象的结果,通过编制程序语言去贯彻它,肯定是先经历抽象那么些历程,才能经过持续的艺术去发挥出抽象的组织。

1.怎么着是包裹

装进,相当于把客观事物封装成抽象的类,并且类能够把温馨的数码和方式只让可相信的类还是目的操作,对不可信的开始展览音信隐藏。

面向对象的封装本性:

  • 将内容封装到某处
  • 从某处调用被包裹的内容

二.怎么要用组合

一.类的宣示:

def functionName(args):
     '函数文档字符串'
      函数体 

'''
class 类名:
    '类的文档字符串'
    类体
'''

#我们创建一个类
class Data:
    pass

class Person:   #定义一个人类
    role = 'person'  #人的角色属性都是人
    def walk(self):  #人都可以走路,也就是有一个走路方法,也叫动态属性
        print("person is walking...")

5.派生与重用

派生:子类定义本人新的品质,要是与父类同名,以子类自个儿的为准

4858.com 24858.com 3

# 父类
class People:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def func1(self):
        print('People.func1')


# 子类 派生自己的属性
class Teacher(People):
    def __init__(self, name, age, sex, level, salary):
        self.name = name
        self.age = age
        self.sex = sex

        self.level = level
        self.salary = salary

    def func1(self):
        print('Teacher.func1')


# 实例化
tea1 = Teacher('fixd', 18, 'male', 9, 3.1)
print(tea1.name, tea1.age, tea1.sex, tea1.level, tea1.salary)

# 结果
fixd 18 male 9 3.1

演示代码

录取:在子类派生出的新方式中选定父类的功力

办法一:指名道姓地调用(其实与后续未有怎么关系的)

# 父类
class People:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


# 子类 "指名道姓" 调用父类的属性
class Teacher(People):
    def __init__(self, name, age, sex, level, salary):
        People.__init__(self, name, age, sex)
        self.level = level
        self.salary = salary

方式贰、super()调用(严苛注重于继续)

*面向对象,全栈开发。  ps:super()的重临值是1个破例的对象,该指标尤其用来调用父类中的属性*

*  掌握:在python第22中学,须求super(自个儿的类名,self)*

# 父类
class People:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


# 子类 super() 调用父类的属性
class Teacher(People):
    def __init__(self, name, age, sex, level, salary):       
        super().__init__(name, age, sex)
        self.level = level
        self.salary = salary 

留意:以上三种艺术都能够利用,在其实的编码工作中,推荐应用统壹的一种格局

 

4858.com 44858.com 5

#super()会严格按照mro列表从当前查找到的位置继续往后查找
class A:
    def test(self):
        print('A.test')
        super().f1()
class B:
    def f1(self):
        print('from B')
class C(A,B):
    pass

c=C()
print(C.mro()) #C->A->B->object


c.test()

mro列表

 

二.要卷入什么

您卡包的有稍许钱(数据的包裹)
你的性取向(数据的卷入)
你撒尿的现实成效是怎么落到实处的(方法的卷入)

  通过为某2个指标添加属性(属性的值是此外一个类的指标)的点子,可以直接地将三个类关联/整合/组合到手拉手

二.类有两种功能:

个性引用:

class Person:   #定义一个人类
    role = 'person'  #人的角色属性都是人
    def walk(self):  #人都可以走路,也就是有一个走路方法
        print("person is walking...")


print(Person.role)  #查看人的role属性
print(Person.walk)  #引用人的走路方法,注意,这里不是在调用

实例化:类名加括号就是实例化,会自行触发__init__函数的周转,能够用它来为各类实例定制自身的本性

class Person:   #定义一个人类
    role = 'person'  #人的角色属性都是人
    def __init__(self,name):
        self.name = name  # 每一个角色都有自己的昵称;

    def walk(self):  #人都可以走路,也就是有一个走路方法
        print("person is walking...")


print(Person.role)  #查看人的role属性
print(Person.walk)  #引用人的走路方法,注意,这里不是在调用

实例化的进程正是类——>对象的经过

原本大家唯有多个Person类,在那么些进程中,暴发了贰个egg对象,有投机现实的名字、攻击力和生命值。

语法:对象名 = 类名(参数)

class Person:   #定义一个人类
    role = 'person'  #人的角色属性都是人
    def __init__(self,name):
        self.name = name  # 每一个角色都有自己的昵称;

    def walk(self):  #人都可以走路,也就是有一个走路方法
        print("person is walking...")

aray = Person('zbk')
print(aray.name)   #查看属性直接 对象名.属性名
print(aray.walk())  #调用方法,对象名.方法名()

5.属性查找

'''
1、新式类:
    继承object的类,以及该类的子类,都是新式类

    在python3中,如果一个类没有指定继承的父类,默认就继承object
    所以说python3中所有的类都是新式类

2、经典类(只有在python2才区分经典类与新式类):
    没有继承object的类,以及该类的子类,都是经典类
'''

单继承名称空间的搜索顺序:

对象自作者——–>>当前类——–>>父类——–>>object     
# 查找不到,报错

多再而三名称空间的摸索顺序:

4858.com 6

4858.com 7

在菱形继承的背景下,查找属性
1、经典类:深度优先
2、新式类:广度优先

 

三.怎么要卷入

卷入不是然则意义的藏匿:
(一)
封装数据的首要缘由是:爱慕隐秘(作为男士的你,脸上就写着:作者喜欢男生,你害怕么?)
(二)
封装方法的机要原因是:隔开分离复杂度(快门就是白痴相机为傻瓜们提供的形式,该办法将中间复杂的拍戏功效都掩藏起来了,比如您不要知道您本人的尿是怎么流出来的,你直接掏出团结的接口就能用尿那些效应)

您的肉体未有一处不呈现着包裹的定义:你的肌体把膀胱尿道等等那些尿的效益隐藏了起来,然后为你提供七个尿的接口就足以了(接口便是您的。。。,),你总无法把膀胱挂在身体外面,上洗手间的时候就跟别人炫耀:hi,man,你瞅小编的膀胱,看看笔者是怎么尿的。还有你的头把您的脑力封装到了脑部里,然后提供了双眼那几个接口….再比如说电视机本人是3个黑盒子,隐藏了拥有细节,但是一定会对外提供了一批按钮,这几个按钮也多亏接口的定义,所以说,封装并不是壹味意义的藏身!!!

提示:在编制程序语言里,对外提供的接口(接口可掌握为了一个进口),能够是函数,称为接口函数,那与接口的概念还不一致,接口代表一组接口函数的集合体。

  从而减弱类与类之间代码冗余

关于self

self:在实例化时自动将对象/实例自身传给__init__的第贰个参数,你也能够给他起各自的名字,不过不奇怪人都不会这么做。
因为你瞎改外人就不认得

类属性的补充:

一:我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值

二:特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)

面向对象小结——定义及调用的固化方式

class 类名:
    def __init__(self,参数1,参数2):
        self.对象的属性1 = 参数1
        self.对象的属性2 = 参数2

    def 方法名(self):pass

    def 方法名2(self):pass

对象名 = 类名(1,2)  #对象就是实例,代表一个具体的东西
                  #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
                  #括号里传参数,参数不需要传self,其他与init中的形参一一对应
                  #结果返回一个对象
对象名.对象的属性1   #查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名()     #调用类中的方法,直接用 对象名.方法名() 即可

二、封装

四.封装分为七个范畴

封装其实分为多少个层面,但无论是哪一类范围的包裹,都要对外场提供好走访你内部隐藏内容的接口(接口能够知晓为输入,有了这些进口,使用者无需且不可见一向访问到里面隐藏的细节,只好走接口,并且我们得以在接口的兑现上附加越多的拍卖逻辑,从而严格控制使用者的访问)

先是个层面包车型大巴卷入(什么都并非做):创制类和对象会分别创造二者的名目空间,大家只能用类名.可能obj.的章程去拜谒里面包车型客车名字,那本身正是一种包装

>>> r1.nickname
'草丛伦'
>>> Riven.camp
'Noxus'

<font color=#FF0000> 注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口</font>

第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
在python中用双下划线的方式实现隐藏属性(设置成私有的)。
类中所有双下划线开头的名称如\_\_x都会自动变形成:\_类名\_\_x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

暗藏,并对外提供接口,接口附加类型检查逻辑

class Teacher:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age

    def tell_info(self):
        print('姓名:%s,年龄:%s' %(self.__name,self.__age))
    def set_info(self,name,age):
        if not isinstance(name,str):
            raise TypeError('姓名必须是字符串类型')
        if not isinstance(age,int):
            raise TypeError('年龄必须是整型')
        self.__name=name
        self.__age=age

t=Teacher('egon',18)
t.tell_info()

t.set_info('egon',19)
t.tell_info()
 1 class Foo1:
 2     pass
 3 class Foo2:
 4     pass
 5 class Foo3:
 6     pass
 7 
 8 class Bar:
 9     pass
10 
11 obj_from_bar=Bar()
12 
13 obj1=Foo1()
14 obj2=Foo2()
15 obj3=Foo3()
16 
17 obj1.attr1=obj_from_bar
18 obj2.attr2=obj_from_bar
19 obj3.attr3=obj_from_bar

3、面向对象的组成

一.哪些是包裹

字面上的情致就是,把东西隐藏起来了。

在python中的封装就是把 类中的属性(变量、函数)隐藏起来

五.封装的行使

(一)将内容封装到某处
4858.com 8

self 是叁个款式参数,当执行 obj壹 = Foo(‘wupeiqi’, 18 ) 时,self 等于
obj1
当执行 obj2 = Foo(‘alex’, 78 ) 时,self 等于 obj2
为此,内容其实被包裹到了对象 obj一 和 obj贰 中,每种对象中都有 name 和 age
属性,在内部存款和储蓄器里好像于下图来保存。
4858.com 9

(二)从某处调用被卷入的剧情
调用被包裹的内容时,有二种处境:

  • 透过对象直接调用
  • 通过self直接调用

一)通过对象直接调用被卷入的内容
上海教室显示了目的 obj1 和 obj二在内存中保存的章程,依据保存格式能够如此调用被装进的内容:对象.属性名

class Foo:

    def __init__(self, name, age):
        self.name = name
        self.age = age

obj1 = Foo('wupeiqi', 18)
print obj1.name    # 直接调用obj1对象的name属性
print obj1.age     # 直接调用obj1对象的age属性

obj2 = Foo('alex', 73)
print obj2.name    # 直接调用obj2对象的name属性
print obj2.age     # 直接调用obj2对象的age属性

2)通过self直接调用棉被服装进的内容
实践类中的方法时,需求通过self直接调用被卷入的内容

class Foo:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def detail(self):
        print self.name
        print self.age

obj1 = Foo('wupeiqi', 18)
obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18

obj2 = Foo('alex', 73)
obj2.detail()  # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78

综合,对于面向对象的包装来说,其实正是运用构造方法将内容封装到 对象
中,然后经过对象直接或然self直接获取被包裹的内容。

 

一.怎么是整合?

答:软件重用的重点措施除了一连之外还有此外1种艺术,即:组合

组合指的是,在1个类中以其余一个类的靶子作为数据属性,称为类的构成

组合表现的是:  谁有什么的关系。
例如:  人有武器 、   学校有学生  、 学生有课程

整合例子一:

class Weapon:
    def prick(self, obj):  # 这是该装备的主动技能,扎死对方
        obj.life_value -= 500  # 假设攻击力是500

class Person:  # 定义一个人类
    role = 'person'  # 人的角色属性都是人

    def __init__(self, name):
        self.name = name  # 每一个角色都有自己的昵称;
        self.weapon = Weapon()  # 给角色绑定一个武器;

egg = Person('egon')
egg.weapon.prick() 
#egg组合了一个武器的对象,可以直接egg.weapon来使用组合类中的所有方法

结合例子二:

圆环是由四个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是在那之中圆的周长加上海外国语大学表圆的周长。
这一年,大家就率先完成叁个圆形类,总计三个圆的周长和面积。然后在”环形类”中组成圆形的实例作为自身的属性来用

4858.com 104858.com 11

from math import pi

class Circle:
    '''
    定义了一个圆形类;
    提供计算面积(area)和周长(perimeter)的方法
    '''
    def __init__(self,radius):
        self.radius = radius

    def area(self):
         return pi * self.radius * self.radius

    def perimeter(self):
        return 2 * pi *self.radius


circle =  Circle(10) #实例化一个圆
area1 = circle.area() #计算圆面积
per1 = circle.perimeter() #计算圆周长
print(area1,per1) #打印圆面积和周长

class Ring:
    '''
    定义了一个圆环类
    提供圆环的面积和周长的方法
    '''
    def __init__(self,radius_outside,radius_inside):
        self.outsid_circle = Circle(radius_outside)
        self.inside_circle = Circle(radius_inside)

    def area(self):
        return self.outsid_circle.area() - self.inside_circle.area()

    def perimeter(self):
        return  self.outsid_circle.perimeter() + self.inside_circle.perimeter()


ring = Ring(10,5) #实例化一个环形
print(ring.perimeter()) #计算环形的周长
print(ring.area()) #计算环形的面积

View Code

结合例子三:

用结合的艺术建立了类与组合的类之间的关联,它是一种‘有’的关系,比如助教有出生之日,教授教python课程

4858.com 124858.com 13

class BirthDate:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day

class Couse:
    def __init__(self,name,price,period):
        self.name=name
        self.price=price
        self.period=period

class Teacher:
    def __init__(self,name,gender,birth,course):
        self.name=name 
        self.gender=gender
        self.birth=birth
        self.course=course
    def teach(self): 
        print('teaching')

p1=Teacher('egon','male', 
            BirthDate('1995','1','27'), 
            Couse('python','28000','4 months')
           ) 

print(p1.birth.year,p1.birth.month,p1.birth.day) 

print(p1.course.name,p1.course.price,p1.course.period)
''' 
运行结果: 
1 27 
python 28000 4 months 

View Code

当类之间有醒目差别,并且较小的类是较大的类所急需的零部件时,用整合相比较好

2.怎么要用封装

装进的真谛在于分明内外

对外隐藏(类的外部只可以通过大家提供的接口对类内部的隐藏属性就行走访)

对内开花(在类的个中能够平素动用隐藏属性)

 

封装数据(变量)将数据隐藏并不是大家的指标,能够由此接口的办法将数据暴光给类外面使用,在接口中咱们得以对数据开始展览限定,实现对数据的控制

4858.com 144858.com 15

class Teacher:
    def __init__(self,name,age):
        # self.__name=name
        # self.__age=age
        self.set_info(name,age)

    def tell_info(self):
        print('姓名:%s,年龄:%s' %(self.__name,self.__age))
    def set_info(self,name,age):
        if not isinstance(name,str):
            raise TypeError('姓名必须是字符串类型')
        if not isinstance(age,int):
            raise TypeError('年龄必须是整型')
        self.__name=name
        self.__age=age


t=Teacher('egon',18)
t.tell_info()

t.set_info('egon',19)
t.tell_info()

以身作则代码

包装方法(函数)要害指标隔开分离复杂度,将类中五个函数组合,提供1个对外封装好的接口,供使用者调用,而调用者无需思量接口内复杂的贯彻进度,简化调用

4858.com 164858.com 17

#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print_bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')

    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()

a=ATM()
a.withdraw()

隔离复杂度的例子

以身作则代码

6.封装时变形的意思

那种自动变形的性状:

  • 类中定义的__x只辛亏里边使用,如self.__x,引用的正是变形的结果。
  • 那种变形其实正是本着外部的变形,在外部是力不从心透过__x这么些名字访问到的。
  • 在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线起始的性质在继承给子类时,子类是力不从心掩盖的。

小心:对于那1局面包车型大巴包装(隐藏),大家必要在类中定义两个函数(接口函数)在它在那之中访问被埋伏的性质,然后外部就足以使用了。
也能够用property来化解,即将介绍

那种变形需求注意的标题是:
(一)那种体制也并未当真含义上限定大家从表面间接待上访问属性,知道了类名和天性名就能够拼盛名字:_类名__天性,然后就可以访问了,如a._A__N

>>> a=A()
>>> a._A__N
>>> a._A__X
>>> A._A__N

(二)变形的进度只在类的概念时产生一遍,在概念后的赋值操作,不会变形
4858.com 18

(3)在继承中,父类假使不想让子类覆盖自个儿的措施,能够将艺术定义为私有的

#正常情况
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B

#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A

python并不会真正阻止你拜访私有的性质,模块也依照那种约定,要是模块名以单下划线开端,那么from
module import *时不能够被导入,然而你from module import
_private_module依旧是足以导入的

实际上过多时候你去调用3个模块的意义时会境遇单下划线开首的(socket._socket,sys._home,sys._clear_type_cache),这个都以私人住房的,原则上是供内部调用的,作为外部的您,死不改悔也是足以用的,只但是显得有点傻逼一小点

python要想与别的编制程序语言一样,严控属性的走访权限,只好依靠停放方法如__getattr__。

三.怎么着用结合

4、面向对象的3大特色

叁.怎么用包装

在python中用双下划线早先的方法将质量隐藏起来(设置成私有的)

#其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形
#类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,
#这种,在外部是无法通过__x这个名字访问到。

PS:

*壹.这种体制也并不曾真正意义上限定我们从外表直接待上访问属性,知道了类名和总体性名就能够拼有名字:_类名__个性,然后就足以访问了,如a._A__N,**即那种操作并不是严刻意义上的限量外部访问,仅仅只是1种语法意义上的变形,首要用来限制外部的平素访问。


贰.变形的进程只在类的定义时产生三次,在概念后的赋值操作,不会变形

4858.com 19

三.在后续中,父类借使不想让子类覆盖本身的办法,可以将艺术定义为私有的

 

4858.com 204858.com 21

#正常情况
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B


#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A

演示代码

 

 

 

三、练习

1.练习题1
在终点输出如下新闻:
小明,7岁,男,上山去砍柴
小明,八岁,男,驾车去西北
小明,八岁,男,最爱大保健
老李,八十六周岁,男,上山去砍柴
老李,八十七虚岁,男,驾乘去西北
4858.com ,老李,九十岁,男,最爱大保健
老张…

class Foo:

    def __init__(self, name, age ,gender):
        self.name = name
        self.age = age
        self.gender = gender

    def kanchai(self):
        print("%s,%s岁,%s,上山去砍柴" % (self.name, self.age, self.gender))

    def qudongbei(self):
        print("%s,%s岁,%s,开车去东北" % (self.name, self.age, self.gender))

    def dabaojian(self):
        print("%s,%s岁,%s,最爱大保健" % (self.name, self.age, self.gender))

xiaoming = Foo('小明', 10, '男')
xiaoming.kanchai()
xiaoming.qudongbei()
xiaoming.dabaojian()

laoli = Foo('老李', 90, '男')
laoli.kanchai()
laoli.qudongbei()
laoli.dabaojian()

2.练习题2
娱乐人生程序
(1)创设多少个游戏人物,分别是:
苍井井,女,1捌,初阶战斗力一千
东尼木木,男,20,开始战斗力1800
波多多,女,1玖,开始战斗力2500
(二)游戏场景,分别:
草丛战斗,消耗200战斗力
自家修炼,增进100战斗力
多个人游戏,消耗500战斗力

# #####################  定义实现功能的类  #####################
class Person:

    def __init__(self, na, gen, age, fig):
        self.name = na
        self.gender = gen
        self.age = age
        self.fight =fig

    def grassland(self):
        """注释:草丛战斗,消耗200战斗力"""

        self.fight = self.fight - 200

    def practice(self):
        """注释:自我修炼,增长100战斗力"""

        self.fight = self.fight + 200

    def incest(self):
        """注释:多人游戏,消耗500战斗力"""

        self.fight = self.fight - 500

    def detail(self):
        """注释:当前对象的详细情况"""

        temp = "姓名:%s ; 性别:%s ; 年龄:%s ; 战斗力:%s"  % (self.name, self.gender, self.age, self.fight)
        print temp

# #####################  开始游戏  #####################

cang = Person('苍井井', '女', 18, 1000)    # 创建苍井井角色
dong = Person('东尼木木', '男', 20, 1800)  # 创建东尼木木角色
bo = Person('波多多', '女', 19, 2500)      # 创建波多多角色

cang.incest() #苍井空参加一次多人游戏
dong.practice()#东尼木木自我修炼了一次
bo.grassland() #波多多参加一次草丛战斗

#输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail()

cang.incest() #苍井空又参加一次多人游戏
dong.incest() #东尼木木也参加了一个多人游戏
bo.practice() #波多多自我修炼了一次

#输出当前所有人的详细情况
cang.detail()
dong.detail()
bo.detail()

三.抛出尤其演习

class People:
    def __init__(self,name,age):
        self.__name=name
        self.__age=age

    def tell_info(self):
        print('人的名字是:%s ,人的年龄是:%s' %(
                    self.__name, #p._People__name
                    self.__age))

    def set_info(self,x,y):
        if not isinstance(x,str):
            raise TypeError('名字必须是字符串类型')
        if not isinstance(y,int):
            raise TypeError('年龄必须是整数类型')

        self.__name=x
        self.__age=y

p=People('alex',1000)
p.tell_info()

p.set_info(123,123)
p.tell_info()

运行结果:
Traceback (most recent call last):
  File "E:/s17/day07/test.py", line 26, in <module>
    p.set_info(123,123)
  File "E:/s17/day07/test.py", line 16, in set_info
    raise TypeError('名字必须是字符串类型')
TypeError: 名字必须是字符串类型
人的名字是:alex ,人的年龄是:1000
 1 class OldboyPeople:
 2     school = 'Oldboy'
 3 
 4     def __init__(self, name, age, sex, ):
 5         self.name = name
 6         self.age = age
 7         self.sex = sex
 8 
 9 
10 class OldboyStudent(OldboyPeople):
11     def __init__(self, name, age, sex, score=0):
12         OldboyPeople.__init__(self, name, age, sex)
13         self.score = score
14         self.courses = []
15 
16     def choose_course(self):
17         print('%s choosing course' % self.name)
18 
19     def tell_all_course(self):
20         print(('学生[%s]选修的课程如下' % self.name).center(50, '='))
21         for obj in self.courses:
22             obj.tell_info()
23         print('=' * 60)
24 
25 
26 class OldboyTeacher(OldboyPeople):
27     def __init__(self, name, age, sex, level):
28         OldboyPeople.__init__(self, name, age, sex)
29         self.level = level
30         self.courses = []
31 
32     def score(self, stu, num):
33         stu.score = num
34 
35     def tell_all_course(self):
36         print(('老师[%s]教授的课程如下' % self.name).center(50, '*'))
37         for obj in self.courses:
38             obj.tell_info()
39         print('*' * 70)
40 
41 
42 class Course:
43     def __init__(self, c_name, c_price, c_period):
44         self.c_name = c_name
45         self.c_price = c_price
46         self.c_period = c_period
47 
48     def tell_info(self):
49         print('<课程名:%s 价钱:%s 周期:%s>' % (self.c_name, self.c_price, self.c_period))
50 
51 
52 # 创建课程对象
53 python = Course('python全栈开发', 1900, '5mons')
54 linux = Course('linux架构师', 900, '3mons')
55 
56 stu1 = OldboyStudent('刘二蛋', 38, 'male')
57 stu1.courses.append(python)
58 stu1.courses.append(linux)
59 stu1.tell_all_course()
60 
61 tea1 = OldboyTeacher('egon', 18, 'male', 10)
62 tea1.courses.append(python)
63 tea1.tell_all_course()

1.继承:

此起彼伏是壹种创设新类的办法,在python中,新建的类能够延续3个或三个父类,父类又可称之为基类或超类,新建的类称为派生类或子类

4.特性(property)

怎么是特点

property是一种特殊的性子,访问它时会执行一段功用(函数)然后返回值

eg:

4858.com 224858.com 23

BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)

成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
  体质指数(BMI)=体重(kg)÷身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86

成效描述

4858.com 244858.com 25

class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height

    @property
    def bmi(self):
        return self.weight / (self.height * self.height)

# egon=People('egon',75,1.80)
#
# egon.bmi=egon.weight / (egon.height * egon.height)
# print(egon.bmi)
#
# yl=People('yangli',85,1.74)
# yl.bmi=yl.weight / (yl.height * yl.height)
# print(yl.bmi)


# 首先需要明确。bmi是算出来的,不是一个固定死的值,也就说我们必须编写一个功能,每次调用该功能
#都会立即计算一个值
egon=People('egon',75,1.80)
yl=People('yangli',85,1.74)

# 但很明显人的bmi值听起来更像一个名词而非动词
# print(egon.bmi())
# print(yl.bmi())


# 于是我们需要为bmi这个函数添加装饰器,将其伪装成一个数据属性
# egon.weight=70
# print(egon.bmi) #21.604938271604937,调用egon.bmi本质就是触发函数bmi的执行,从而拿到其返回值
# print(yl.bmi)

以身作则代码

 

为什么要用本性

将一个类的函数定义成特色未来,对象再去采取的时候obj.name,根本无法察觉自身的name是履行了三个函数然后总计出来的,这种特征的施用办法服从了统一访问的标准化

PS:

【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,
但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开

python并未在语法上把它们多少个内建到本身的class机制中,能够透过property方法达成

4858.com 264858.com 27

class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'

以身作则代码

 

四、特性(property)

 

在此起彼伏中, 如果子类有的艺术就实施子类的 即使子类未有的方法就举办父类的。 语法: class 类名(父类名): 假诺不内定继承的父类,私下认可继承 object 子类能够动用父类的装有属性和方式。 借使子类有专家级的点子就进行本人的。 没救就进行父类, 子类,父类都尚未,就报错。 子类中调用父类: 在类内—— super (子类名,self).方法名() 在类外—— super (子类名,对象名)。方法名()

4858.com 28

python中类的存续分为:单继承和多继承

4858.com 294858.com 30

class ParentClass1: #定义父类
    pass

class ParentClass2: #定义父类
    pass

class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
    pass

class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
    pass

View Code

提示:要是未有点名基类,python的类会暗中同意继承object类,object是负有python类的基类,它提供了部分周边方法(如__str__)的实现。

三、多态

一.哪些是特点property

property是壹种独特的习性,访问它时会执行1段作用(函数)然后重返值。

示例1:
BMI指数(bmi是总计而来的,但很鲜明它听起来像是贰个天性而非方法,假使大家将其做成2个属性,更有利于精晓)

成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
尤其肥胖, 高于32

体质指数(BMI)=体重(kg)÷身高^二(m)
EX:70kg÷(1.75×1.75)=22.86

class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height

    @property
    def bmi(self):
        return self.weight / (self.height**2)

p1=People('egon',75,1.85)
print(p1.bmi)

运行结果:
21.913805697589478

示例2:
圆的周长和面积

import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(10)
print(c.radius)
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上

运行结果:
314.1592653589793
62.83185307179586

瞩目:此时的性状area和perimeter不可能被赋值

c.area=3 #为特性area赋值

抛出异常:
AttributeError: can't set attribute

面向对象-多态与多态性

此起彼伏: 大范围到校范围 抽象: 范围越来越大,共性越来越小 派生:父类的底蕴上发生子类——派生类 派生方法: 父类里从未的,可是i子类里1些 派生属性: 方法的重写: 父类里部分艺术,在子类里再次达成。

一、什么是多态

* 多态指的是平等种东西两种样子*

2.为啥要用property

将二个类的函数定义成特色今后,对象再去选用的时候obj.name,根本不能够察觉自身的name是履行了三个函数然后总计出来的,那种特征的采纳办法遵守了统1访问的基准。

除了,面向对象的封装有二种方法:
【public】那种其实正是不封装,是对伯公开的
【protected】那种封装格局对外不公开,但对朋友(friend)大概子类(形象的说法是“儿子”,但小编不精通为啥大家不说“外孙女”,就如“parent”本来是“父母”的情趣,但汉语都以叫“父类”)公开
【private】那种封装对何人都不公开

python并不曾在语法上把它们七个内建到祥和的class机制中,在C++里1般会将具备的数码都安装为个体的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以完成

class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'

壹.怎么样是多态

2.多态:

多态指的是一类东西有二种形态

动物有五种造型:人,狗,猪

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')

 文件有多样形状:文本文件,可执行文件。如下:

import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形态之一:文本文件
    def click(self):
        print('open file')

class ExeFile(File): #文件的形态之二:可执行文件
    def click(self):
        print('execute file')

1 什么是多态动态绑定(在此起彼伏的背景下行使时,有时也称之为多态性)

多态性是指在不思索实例类型的情景下行使实例:

比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同

多态性分为静态多态性和动态多态性:

*  静态多态性:如别的项目都得以用运算符+举行演算*

*  动态多态性:如下*

peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()

  

鸭子类型

逗比时刻:

  Python崇尚鸭子类型,即‘假设看起来像、叫声音图像而且走起路来像鸭子,那么它正是鸭子’

python程序员平日依据这种表现来编写程序。例如,假如想编写现有对象的自定义版本,能够接二连三该指标

也得以创立四个外观和行事像,但与它无任何关系的崭新对象,后者常常用于保存程序组件的松耦合度。

例1:利用标准库中定义的各样‘与公事类似’的靶子,即使这么些指标的办事措施像文件,但她们一向不继承内置文件对象的主意

例二:系列类型有各个形象:字符串,列表,元组,但他们直接未有一贯的持续关系

#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass

二、为啥要用多态   

用基类创制1套统壹的平整,强制子类去根据(使用抽象类完成),这样便能够
在毫无思虑对象实际品种的前提下而间接运用对象下的方式

3.用法

class People:
    def __init__(self,name,permmission=False):
        self.__name=name
        self.permmission=permmission
    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,value):
        if not isinstance(value,str):
            raise TypeError('名字必须是字符串类型')
        self.__name=value

    @name.deleter
    def name(self):
        if not self.permmission:
            raise PermissionError('不允许的操作')
        del self.__name

p=People('egon')

print(p.name)

p.name='egon666'
print(p.name)

p.name=35357
p.permmission=True
del p.name

运行结果:
egon
Traceback (most recent call last):
egon666
  File "E:/s17/day07/test.py", line 31, in <module>
    p.name=35357
  File "E:/s17/day07/test.py", line 15, in name
    raise TypeError('名字必须是字符串类型')
TypeError: 名字必须是字符串类型

  多态指的是同等种/类东西的例外造型

3.封装:

【封装】

         隐藏对象的个性和贯彻细节,仅对外提供公共访问格局。

【好处】 

  1. 将转变隔断; 

  2. 方便人民群众使用;

  3. 增加复用性; 

  4. 增强安全性;

【封装原则】

      一. 将不要求对外提供的内容都隐藏起来;

      贰. 把质量都躲藏,提供公共措施对其访问。

三、如何用多态

动物有多样样子:人,狗,猪

4858.com 314858.com 32

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')

Animal

文本有多样模样:文本文件,可执行文件

4858.com 334858.com 34

import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形态之一:文本文件
    def click(self):
        print('open file')

class ExeFile(File): #文件的形态之二:可执行文件
    def click(self):
        print('execute file')

File

PS:

一.浮泛基类是不能够实例化的

2.持续抽象基类的类,必须重写其抽象父类中的抽象方法

五、封装与扩充性

封装在于明显区分内外,使得类完成者能够修改封装内的事物而不影响外部调用者的代码;而外部使用用者只知道多少个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。那就提供贰个完好无损的同盟基础——或然说,只要接口这些基础约定不变,则代码改变不足为虑。

#类的设计者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length

#使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area
400

#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high

对于依然在利用tell_area接口的人来说,根本无需变更本身的代码,就能够用上新效率

>>> r1.tell_area()
8000

贰.为啥要用多态

个体变量和民用方法:

在python中用双下划线开端的章程将质量隐藏起来(设置成私有的)

#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

那种自发性别变化形的表征:

壹.类中定义的__x只万幸中间使用,如self.__x,**引用的正是变形的结果**。

2.那种变形其实就是本着外部的变形,在表面是心有余而力不足通过__x那个名字访问到的。

3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线起始的本性在继续给子类时,子类是心有余而力不足覆盖的。**

这种变形必要注意的题材是:

壹.这种机制也并未当真含义上限制大家从表面间接待上访问属性,知道了类名和性情名就足以拼知名字:_类名__本性,然后就能够访问了,如a._A__N

二.变形的进度只在类的概念是爆发叁次,在概念后的赋值操作,不会变形

4、多态性

一.怎么是多态动态绑定(在一连的背景下采取时,又叫做多态性)

多态性是指在不考虑实力类型的图景下采用实例

4858.com 354858.com 36

在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同

解释

2.为啥要用多态性(多态性的好处)

  • 日增了先后的油滑

    不变,不论对象变幻莫测,使用者都是同等种样式去调用

  • 增添了先后的可扩充性

    由此继承animal类成立了1个新的类,使用者无需更改自身的代码,照旧用func(animal)去调用

4858.com 374858.com 38

>>> class Cat(Animal): #属于动物的另外一种形态:猫
...     def talk(self):
...         print('say miao')
... 
>>> def func(animal): #对于使用者来说,自己的代码根本无需改动
...     animal.talk()
... 
>>> cat1=Cat() #实例出一只猫
>>> func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能
say miao

'''
这样我们新增了一个形态Cat,由Cat类产生的实例cat1,使用者可以在完全不需要修改自己代码的情况下。使用和人、狗、猪一样的方式调用cat1的talk方法,即func(cat1)
'''

演示代码

 

3.鸭子类型

Python中崇尚鸭子类型(若是看起来像,叫声音图像而且走起路像鸭子,那么它便是鸭子)

透过持续完成的多态性,具有强耦合性;

鸭子类型,通过成立1个外观和行事像,但与原类型毫毫无干系系的全新对象,具有松耦合性;

4858.com 394858.com 40

#其实大家一直在享受着多态性带来的好处,
#比如Python的序列类型有多种形态:字符串,列表,元组,多态性的体现
#
#str,list,tuple都是序列类型
s=str('hello')
l=list([1,2,3])
t=tuple((4,5,6))

#我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)

演示代码

 

  多态性:在多态的背景下,能够在毫无思虑对象实际品种的前提下而直接行使对象

村办方法:

**3.在继承中,父类就算不想让子类覆盖自身的法子,能够将艺术定义为私有的**

 

#正常情况
>>> class A:
...     def fa(self):
...         print('from A')
...     def test(self):
...         self.fa()
... 
>>> class B(A):
...     def fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from B


#把fa定义成私有的,即__fa
>>> class A:
...     def __fa(self): #在定义时就变形为_A__fa
...         print('from A')
...     def test(self):
...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
... 
>>> class B(A):
...     def __fa(self):
...         print('from B')
... 
>>> b=B()
>>> b.test()
from A

三.怎么着用多态

装进与扩张性:

封装在于分明区分内外,使得类实现者能够修改封装内的事物而不影响外部调用者的代码;而外部使用用者只知道2个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需变更。那就提供三个精粹的搭档基础——可能说,只要接口那个基础约定不变,则代码改变不足为虑。

#类的设计者
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length


#使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area


#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self,name,owner,width,length,high):
        self.name=name
        self.owner=owner
        self.__width=width
        self.__length=length
        self.__high=high
    def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high


#对于仍然在使用tell_area接口的人来说根本无需改动自己的代码,就可以用上新功能

  Animal() 
#父类只是用来树立规范的,不能用来实例化,更无需兑现内部的法子

property属性:

4858.com 414858.com 42

例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)

成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
  体质指数(BMI)=体重(kg)÷身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86

例子1

4858.com 434858.com 44

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

p1=People('egon',75,1.85)
print(p1.bmi)

例子2

4858.com 454858.com 46

import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(10)
print(c.radius)
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上
'''
输出结果:
314.1592653589793
62.83185307179586
'''

例子3

#留神:此时的特点area和perimeter不能够被赋值
c.area=3 #为特性area赋值
”’ 抛出拾叁分: AttributeError: can’t set attribute

 

 

何以要用property

将三个类的函数定义成特色现在,对象再去行使的时候obj.name,根本无法察觉自身的name是履行了八个函数然后计算出来的,那种特征的采纳办法遵守了统壹访问的条件

除此而外,看下

ps:面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开

 

4858.com 47

python并不曾在语法上把它们四个内建到祥和的class机制中,在C++里壹般会将富有的具有的数额都设置为民用的,然后提供set和get方法(接口)去设置和收获,在python中经过property方法能够实现

4858.com 484858.com 49

class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'

View Code

3个静态属性property本质正是完毕了get,set,delete几种方式

4858.com 504858.com 51

class Foo:
    @property
    def AAA(self):
        print('get的时候运行我啊')

    @AAA.setter
    def AAA(self,value):
        print('set的时候运行我啊')

    @AAA.deleter
    def AAA(self):
        print('delete的时候运行我啊')

#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

View Code

4858.com 524858.com 53

class Foo:
    def get_AAA(self):
        print('get的时候运行我啊')

    def set_AAA(self,value):
        print('set的时候运行我啊')

    def delete_AAA(self):
        print('delete的时候运行我啊')
    AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应

f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

View Code

4858.com 544858.com 55

class Goods:

    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price


obj = Goods()
obj.price         # 获取商品价格
obj.price = 200   # 修改商品原价
print(obj.price)
del obj.price     # 删除商品原价

View Code

 

 1 import abc
 2 
 3 
 4 class Animal(metaclass=abc.ABCMeta):
 5     @abc.abstractmethod
 6     def speak(self):
 7         pass
 8 
 9     @abc.abstractmethod
10     def run(self):
11         pass
12 
13 
14 
15 class People(Animal):
16     def speak(self):
17         print('say hello')
18 
19     def run(self):
20         pass
21 
22 
23 class Dog(Animal):
24     def speak(self):
25         print('汪汪汪')
26 
27     def run(self):
28         pass
29 
30 
31 class Pig(Animal):
32     def speak(self):
33         print('哼哼哼')
34 
35     def run(self):
36         pass
37 
38 
39 obj1 = People()
40 obj2 = Dog()
41 obj3 = Pig()

Python推崇的是鸭子类型,只要您叫的声音像鸭子,并且你走路的样板也像鸭子,那您正是鸭子

 1 class Disk:
 2     def read(self):
 3         print('Disk read')
 4 
 5     def write(self):
 6         print('Disk write')
 7 
 8 
 9 class Memory:
10     def read(self):
11         print('Mem read')
12 
13     def write(self):
14         print('Mem write')
15 
16 
17 class Cpu:
18     def read(self):
19         print('Cpu read')
20 
21     def write(self):
22         print('Cpu write')
23 
24 
25 obj1 = Disk()
26 obj2 = Memory()
27 obj3 = Cpu()
28 
29 obj1.read()
30 obj2.read()
31 obj3.read()

 

面向对象-封装

一.怎么着是包装

  装: 往容器/名称空间里存入名字

  封: 代表将存放于名称空间中的名字给藏起来,那种隐形对外不对内

二.为啥要卷入

  封装数据属性:

    将数据属性隐藏起来,类外就无法直接操作属性,供给类内部开辟多少个接口,让外部的选择能够直接地操作属性,能够在接口钦点制任意的操纵逻辑,从而严控使用者对质量的操作

 1 class People:
 2     def __init__(self, name, age):
 3         self.__name = name
 4         self.__age = age
 5 
 6     def tell_info(self):
 7         print('<name:%s age:%s>' % (self.__name, self.__age))
 8 
 9     def set_info(self, name, age):
10         if type(name) is not str:
11             print('名字必须是str类型傻叉')
12             return
13         if type(age) is not int:
14             print('年龄必须是int类型傻叉')
15             return
16         self.__name = name
17         self.__age = age
18 
19 
20 obj = People('egon', 18)
21 obj.set_info('EGON', '18')
22 obj.tell_info()

  封装函数属性: 隔绝复杂度

 1 class ATM:
 2     def __card(self):
 3         print('插卡')
 4 
 5     def __auth(self):
 6         print('用户认证')
 7 
 8     def __input(self):
 9         print('输入取款金额')
10 
11     def __print_bill(self):
12         print('打印账单')
13 
14     def __take_money(self):
15         print('取款')
16 
17     def withdraw(self):
18         self.__card()
19         self.__auth()
20         self.__input()
21         self.__print_bill()
22         self.__take_money()
23 
24 
25 a = ATM()
26 a.withdraw()

三.什么封装

  在类钦赐义的品质前加__开头(没有__结尾)

  总结:

    1.
__开班的本性实现的隐蔽仅仅只是壹种语法意义上的变形,并不会真正限制类外部的走访

    二.
该变形操作只在类定义阶段检查实验语法时爆发贰次,类定义阶段之后新增的__始发的质量并不会变形

    三. 万1父类不想让子类覆盖本身的特性,能够在品质前加__开头

 1 class Foo:
 2     def __f1(self):  # _Foo__f1
 3         print('Foo.f1')
 4 
 5     def f2(self):
 6         print('Foo.f2')
 7         self.__f1()  # obj._Foo__f1()
 8 
 9 
10 class Bar(Foo):
11     def __f1(self):  # _Bar__f1
12         print('Bar.f1')
13 
14 
15 obj = Bar()
16 
17 >>>Foo.f2
18 >>>Foo.f1

 

面向对象-property

property装饰器是用来将类内的函数属性伪装成数据属性

 1 class People:
 2     def __init__(self, name):
 3         self.__name = name
 4 
 5     @property
 6     def name(self):
 7         return '<名字:%s>' % self.__name
 8 
 9     @name.setter
10     def name(self, obj):
11         if type(obj) is not str:
12             print('name必须为str类型')
13             return
14         self.__name = obj
15 
16     @name.deleter
17     def name(self):
18         print('不让删')
19 
20 obj = People('egon')
21 del obj.name
22 print(obj.__dict__)

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有