面向对象初识二

面向对象三大特性之继承

一、什么是继承:

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类

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

class ParentClass1: #定义父类
    pass

class ParentClass2: #定义父类
    pass

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

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

查看继承

在python3中 所有的类都继承自object

class ParentClass1: pass
print(ParentClass1.__bases__)
>>>
(<class 'object'>,)
class ParentClass1: pass
class ParentClass2: pass

class ChildClass1(ParentClass1):  # 单继承
    pass
class ChildClass2(ParentClass1,ParentClass2):  # 多继承
    pass
print(ChildClass1.__base__)  # 会显示该类的一个父类
print(ChildClass2.__base__)  # 会显示该类的第一个父类
print(ChildClass2.__bases__)  # 会显示该类的所有父类
>>>
<class '__main__.ParentClass1'>
<class '__main__.ParentClass1'>
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

二、继承与抽象(先抽象再继承)

抽象即抽取类似或者说比较像的部分。

抽象分成两个层次: 

1.将奥巴马和梅西这俩对象比较像的部分抽取成类; 

2.将人,猪,狗这三个类比较像的部分抽取成父类。

抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

 

抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

 

 

三、继承与重用性

# 猫类 : 吃eat 喝drink 睡sleep 爬树climb
# 狗类 : 吃eat 喝drink 睡sleep 看家watch
class Pet:
    def __init__(self,name,kind,food):
        self.name = name      #  派生属性
        self.kind = kind
        self.food = food

    def eat(self):
        print('%s吃%s'%(self.name,self.food))

    def drink(self):
        print('%s在喝水'%self.name)

    def sleep(self):
        print('%s在睡觉' % self.name)

class Cat(Pet):
    def climb(self):      # 派生方法
        print('%s在爬树' % self.name)

class Dog(Pet):
    def watch(self):     # 派生方法
        print('%s在看家' % self.name)

tom = Cat('Tom','暹罗猫','猫粮')  # 子类使用名字(方法和静态变量),如果在子类中没有,就使用父类的\
# Cat('Tom','暹罗猫','猫粮') 实例化

hei = Dog('小黑','2哈','狗粮')
tom.eat()
hei.eat()
tom.climb()
hei.watch()

实例化一个类进行了两步:

      1、 创建一个空对象

    2、执行__init__方法:子类没有用父类的

    子类使用名字(方法和静态变量),如果在子类中没有,就使用父类的

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时

我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

class Animal: # 动物
    def __init__(self,name,aggr,hp):  #方法 动态属性  内置的双下方法
        self.name = name    # 对象属性 实例属性
        self.aggr = aggr
        self.hp = hp

class Person(Animal):    # 类名 Person
    def __init__(self,name,sex,aggr,hp):
        self.sex = sex   # 派生属性
        Animal.__init__(self,name,aggr,hp)
        super().__init__(name,aggr,hp)
    def attack(self,dog):  # 自定义方法
        print('%s打了%s'%(self.name,dog.name))
        dog.hp -= self.aggr

class Dog(Animal):
    def __init__(self,name,kind,aggr,hp):
        self.kind = kind   # 派生属性
        Animal.__init__(self,name,aggr,hp)
    def bite(self,person):
        print('%s咬了%s'%(self.name,person.name))
        person.hp -= self.aggr

alex = Person('alex','不详',1,250)
hei = Dog('小黑','teddy',260,10000)
alex.attack(hei)
hei.bite(alex)
再看人狗大战

四、组合与继承

软件重用的重要方式 有两种一种是组合,另一种是继承

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

  组合和继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同

1、继承的方式

  通过继承建立了派生类(子类)与基类(父类)之间的关系,它是一种“”的关系,比如白马是马,人是动物。

  当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师

2、组合的方式

  用组合的方式建立了类与组合的类之间的关系,它是一种“”的关系,比如教授有生日,教授教Python课程

  当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

 

五、派生

子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

class Animal:
    '''
    人和狗都是动物,所以创造一个Animal基类
    '''
    def __init__(self, name, aggressivity, life_value):
        self.name = name  # 人和狗都有自己的昵称;
        self.aggressivity = aggressivity  # 人和狗都有自己的攻击力;
        self.life_value = life_value  # 人和狗都有自己的生命值;

    def eat(self):
        print('%s is eating'%self.name)

class Dog(Animal):
    '''
    狗类,继承Animal类
    '''
    def bite(self, people):
        '''
        派生:狗有咬人的技能
        :param people:  
        '''
        people.life_value -= self.aggressivity

class Person(Animal):
    '''
    人类,继承Animal
    '''
    def attack(self, dog):
        '''
        派生:人有攻击的技能
        :param dog: 
        '''
        dog.life_value -= self.aggressivity

egg = Person('egon',10,1000)
ha2 = Dog('二愣子',50,1000)
print(ha2.life_value)
print(egg.attack(ha2))

注意:像ha2.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。

super用法:

  在python3中,子类执行父类的方法也可以直接用super方法.

  super是用于派生类当中的,就是我们在子类中需要调用父类的函数,并在其基础上进行修改

  使用范围仅限于新式类中,在Python2中,super()中需要两个参数,Python3中不需要

 

class A:
    def hahaha(self):
        print('A')

class B(A):
    def hahaha(self):
        super().hahaha()
        #super(B,self).hahaha()
        #A.hahaha(self)
        print('B')

a = A()
b = B()
b.hahaha()
super(B,b).hahaha()
View Code
# super
class Animal: # 动物
    def __init__(self,name,aggr,hp):  #方法 动态属性  内置的双下方法
        self.name = name    # 对象属性 实例属性
        self.aggr = aggr
        self.hp = hp
    def eat(self):
        print('in Animal eat')

class Person(Animal):    # 类名 Person
    def __init__(self,name,sex,aggr,hp):
        self.sex = sex   # 派生属性
        # Animal.__init__(self,name,aggr,hp)
        super().__init__(name,aggr,hp)
        # 单继承中 super会寻找父类
        # 且在使用super调用父类方法的时候不需要再传self参数
    def eat(self):
        print('in Person eat')
        # Animal.eat(self)
        # super().eat()
alex = Person('alex','不详',1,250)
print(alex.__dict__)
Animal.eat(alex)
super(Person,alex).eat()
super用法一

 

# #coding:utf-8
# #super在Python2中的用法:
#     #1.super(自己的类,self).父类的函数名字
#     #2.super只能用于新式类
# class People(object):
#     def __init__(self,name,sex,age):
#         self.name = name
#         self.age = age
#         self.sex = sex
#     def walk(self):
#         print("%s is walking"%self.name)
# class Chinese(People):
#     country = "China"
#     def __init__(self,name,sex,age,language="Chinese"):
#         # self.name = name
#         # self.sex = sex
#         # self.age = age
#         #People.__init__(self,name,sex,age)
#         super(Chinese,self).__init__(name,sex,age)
#         self.language = language
# c = Chinese("egon","male",18)
# print (c.name,c.age,c.language)
 
# #在Python3中
# class People:
#     def __init__(self,name,sex,age):
#         self.name = name
#         self.sex = sex
#         self.age = age
#     def walk(self):
#         print("%s is walking"%self.name)
# class Chinese(People):
#     country = "China"
#     def __init__(self,name,sex,age,language="Chinese"):
#         super().__init__(name,sex,age)
#         self.language = language
#     def walk(self,x):
#         super().walk()#walk后面不需要加参数
#         print("子类的x",x)
# c = Chinese("egon","male",18)
# # print(c.name,c.age,c.sex)
# c.walk(1)

  当我们使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)

class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        super().__init__()
class C(A):
    def __init__(self):
        print('C的构造方法')
        super().__init__()
class D(B, C):
    def __init__(self):
        print('D的构造方法')
        super().__init__()
f1 = D()
print(D.__mro__)
super用法二

面向对象特性之多态

一、抽象类与接口类

接口类:

继承有两种用途:

一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)  

二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

      >>>>  在Python里面 没有接口类的概念

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 

接口类 : 接口类就是一个规范 接口类一般是项目设计人员写好的

1.多继承问题

在继承抽象类的过程中,我们应该尽量避免多继承;
而在继承接口的时候,我们反而鼓励你来多继承接口

 

接口隔离原则:
使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。

2.方法的实现

在抽象类中,我们可以对一些抽象方法做出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现

 java里
from abc import ABCMeta,abstractmethod
# 接口类 : 接口类就是一个规范 接口类一般是项目设计人员写好的
class Payment(metaclass=ABCMeta):   #规范
    @abstractmethod
    def pay(self,money):
        '''
        :param money:
        :return:
        '''
        raise NotImplementedError

# 微信支付
class WeChatPay(Payment):
    def pay(self,money):
        print('通过微信支付了%s元钱'%(money))

# 支付宝支付
class AliPay(Payment):
    def pay(self,money):
        print('通过支付宝支付了%s元钱'%(money))

# apple pay
class ApplePay(Payment): pass
    def pay(self,money):
        print('通过支付宝支付了%s元钱' % (money))

wp = WeChatPay()
alp = AliPay()
app = ApplePay()
def pay(pay_obj,money): # 程序的归一化设计
    pay_obj.pay(money)

pay(alp,100)
pay(wp,100)
pay(app,100)
接口类

接口类是一个规范
多种支付方式,每一种支付方式都是一个类,
每一个类中定义一个支付方法完成支付功能
由于每一种支付方式在程序中表现出来的就是支付类的对象
拿到每一个支付对象都需要调用支付方法
为了方便支付方法的调用
需要统一一个入口 pay函数

在Java里有Interface语法:
在python里没有接口类这种数据类型,没有接口类专门的语法
但是可以通过继承abc模块实现接口的功能

 ###   接口类不能被实例化

from abc import ABCMeta,abstractmethod
class FlyAnimal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):
        print(11111)

class SwimAnimal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self): pass

class WalkAnimal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self): pass

class Swan(SwimAnimal,WalkAnimal,FlyAnimal):
    #
    def fly(self):pass
    # 游泳
    def swim(self):pass
    #
    def walk(self):pass

class Qq(SwimAnimal,WalkAnimal):
    def swim(self):pass
    #
    def walk(self):pass

class Bird(FlyAnimal,WalkAnimal):
    #
    def fly(self):pass
    #
    def walk(self):pass
    
Swan()
开放原则

 

二、抽象类

抽象类 规范一个类的类

什么是抽象类

    与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

为什么要有抽象类

    如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性。

  比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。你永远无法吃到一个叫做水果的东西。

    从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

  从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

from abc import ABCMeta , abstractmethod
class File(metaclass=ABCMeta):
    @abstractmethod
    def read(self):
        f = open('file','r')
        self.f = f
    @abstractmethod
    def write(self):
        f = open('file','w')

class Word(File):
    def read(self):
        # 打开一个文件
        # 读文件
        # 关闭一个文件
        super().read()
        self.f.read()
        self.f.close()

class Excle(File):
    def read(self):
        # 打开一个文件
        # 读某一列  读某一列
        # 关闭一个文件
        super().read()
        self.f.readline()
        self.f.close()

class PPT(File):
    def read(self):
        # 打开一个文件
        # 读文字 读表格 读图片
        # 关闭一个文件
        super().read()
        self.f.readpicture()
        self.f.close()
抽象类

在python里 抽象类和接口类 没区别

在java里 有区别

java的接口规定里面的方法一定不能实现(一句代码也不能写)

抽象类 单继承

无论接口类 还是抽象类 其实都是一种面向对象编程的开发规范,只是在接口类或者抽象类中 去约束继承它的子类必须实现某些方法

对于java代码来说:

   如果发生多继承 那么一定是接口类 且里面的方法都不能实现,如果在方法里有了实现 那么一定是单继承 的抽象类

但是对于python来说:

   就没有这些约束因为python没有接口的概念对于类的继承 没有多继承的限制

实际上abc模块是帮我实现抽象类的方法,只是我们用它来模仿接口类的效果了

在python中,只要metaclass = ABCMeta 定义了抽象方法(@abctractmethod)

这个类就不能被实例化,
你可以说他是一个抽象类。

  多态

多态指的是一类事物有多种形态,如动物有多种形态:人,狗,猪

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')
View Code
1+'1'  强类型
def func(name,age):pass   # 弱类型

func('alex',18)
func(18,'alex')
class WeChatPay:
    def pay(self,money):
        print('通过微信支付了%s元钱'%(money))
class AliPay:
    def pay(self,money):
        print('通过支付宝支付了%s元钱'%(money))
def pay(pay_obj,money): # 程序的归一化设计
    pay_obj.pay(money)
w = WeChatPay()
a = AliPay()
pay(w,100)
View Code
python当中对相似的类的实现方式
class List:
    def index(self):
        pass
    def slice(self):
        pass
    def len(self):
        pass
    def append(self):
        pass
class Tuple:
    def index(self):
        pass
    def slice(self):
        pass
    def len(self):
        pass
class Str:
    def index(self):
        pass
    def slice(self):
        pass
    def len(self):
        pass
    def split(self):
        pass

l = List()
t = Tuple()
s = Str()
l.len()  # 方法
def len(obj):
    return obj.len()
多态性
如果建立规范 那么必须通过继承抽象类的形式强制约束

鸭子类型:

Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象

也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

例2:序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系

 

# 多态
class List(序列):
    def index(self):
        pass
    def slice(self):
        pass
    def length(self):
        pass
    def append(self):
        pass
class Tuple(序列):
    def index(self):
        pass
    def slice(self):
        pass
    def len(self):
        pass
class Str(序列):
    def index(self):
        pass
    def slice(self):
        pass
    def len(self):
        pass
    def split(self):
        pass

l = List()
t = Tuple()
l.len()  # 方法
# def len(序列 obj):
#     return obj.len()
鸭子类型

 

六、钻石继承

继承顺序

 

class A:
    def wahaha(self):print('in A')

class B(A):
    def wahaha(self):print('in B')

class C(B):
    def wahaha(self):print('in C')

class D(C):pass
    # def wahaha(self):print('in D')

d = D()
d.wahaha()
继承顺序1

 不要发生循环继承
 依赖倒置原则 :
 高层模块不应该依赖低层模块

python3中统一都是新式类
pyhon2中才分新式类与经典类

class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B):
    def test(self):
        print('from D')

class E(C):
    def test(self):
        print('from E')

class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类
继承顺序2

继承原理

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

>>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, 
<class '__main__.A'>, <class 'object'>]

 

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

 

继承总结

1、继承的作用

继承的作用

减少代码的重用
提高代码可读性
规范编程模式

几个名词

抽象:抽象即抽取类似或者说比较像的部分。是一个从具题到抽象的过程。
继承:子类继承了父类的方法和属性
派生:子类在父类方法和属性的基础上产生了新的方法和属性

抽象类与接口类

复制代码
1.多继承问题
在继承抽象类的过程中,我们应该尽量避免多继承;
而在继承接口的时候,我们反而鼓励你来多继承接口

2.方法的实现
在抽象类中,我们可以对一些抽象方法做出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
复制代码

钻石继承

新式类:广度优先
经典类:深度优先

 

面向对象三大特性封装

【封装】

        隐藏对象的属性和实现细节,仅对外提供公共访问方式。

【好处】 

1. 将变化隔离; 

2. 便于使用;

3. 提高复用性; 

4. 提高安全性;

【封装原则】

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

      2. 把属性都隐藏,提供公共方法对其访问。

 

广义上的封装 : 属于一个类的静态和动态属性 总是出现在一个类中,使用时永远用类名或者对象名调用
狭义上的封装 : 就是把变量 \ 方法私有化,在类的外部以及子类中不能直接使用了

class A:
    STATIC = 'aaa'  # 静态变量
    __S = 'bbb'     # 私有的静态变量
    def wahaha(self):
        print(A.__S) # _A__S
print(A.STATIC)
print(A.__dict__)
print(A._A__S)      # 在类的外面调用私有的变量
a = A()
a.wahaha()
A.__B = 'ccc'   # 在类的外部添加了一个静态变量
print(A.__dict__)  # 我们不能在一个类的外部创建一个"私有的"变量
print(A.__B) 
私有静态属性

 

class B:
    def __init__(self,name,pwd):
        self.name = name
        self.__pwd = pwd   # 也可以创建对象的私有属性

    def qqxing(self):
        self.__a = 'A'     # _B__a

    def get_pwd(self):
        print(self.__pwd)
b = B('alex','alex3714')
b.qqxing()

print(b.name)
print(b._B__pwd)  # 当在类外部的时候,我们也不能直接使用对象的私有属性
b.get_pwd()
私有化对象的属性

 

class C:
    def __ppt(self):    # 私有的方法
        print('ppt')
        self.age = 83
    def open(self):
        self.__ppt()
        print('打开文件')
c = C()
c._C__ppt()   # 不能直接调用
c.open()
c.name = 'alex'

>>>>
ppt
ppt
打开文件
私有化方法

私有的静态变量、 对象属性 方法
私有的 只能在类的内部定义和使用,__私有名字
在类外部使用私有静态变量 _类名__私有的名字
私有的名字 不能被子类继承

 

class Room:
    def __init__(self,owner,price,length,width,height):
        self.owner = owner
        self.__price_single = price  #单价
        self.__length = length
        self.__width = width
        self.height = height

    def get_area(self):
        return self.__length * self.__width

    def get_price(self):
        return self.__price_single * self.get_area()

alex = Room('alex',1000000,2,1,0.8)
print(alex.get_area())
print(alex.get_price())
继承里的私有化

 

内置函数:property、classmethod、staticmethod

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)

wang = Person('王子',1.77,69)
print(wang.bmi)
property1
圆形类  : r   面积area 周长perimeter
from math import pi
class Circle:
    def __init__(self,r):
        self.r = r
    @property
    def area(self):
        return self.r*self.r*pi
    @property
    def perimeter(self):
        return 2*pi*self.r

c = Circle(10)
print(c.area)
print(c.perimeter)
property2
class Foo:
    def __init__(self,name):
        self.__name = name
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self,new_name):
        if type(new_name) == str:
            self.__name = new_name

alex = Foo('alex')
print(alex.name)
alex.name = 123  # 为了迎合属性的设置方式
print(alex.name)
property3
class Foo:
    def __init__(self,name):
        self.__name = name
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self,new_name):
        if type(new_name) == str:
            self.__name = new_name
    @name.deleter
    def name(self):
        del self.__name

alex = Foo('alex')
del alex.name
print(alex.name)
property4
 商品  价格 原价 打折 = 折后价
class Goods:
    def __init__(self,name,price,discount):
        self.name = name
        self.__price = price
        self.discount = discount

    @property
    def price(self):
        return self.__price * self.discount

apple = Goods('apple',5,0.8)
print(apple.price)

为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,

这种特性的使用方式遵循了统一访问的原则

ps:面向对象的封装有三种方式:
public :
这种其实就是不封装,是对外公开的
protected:
这种封装方式对外不公开,但对朋友(friend)或者子类公开
private :
这种封装对谁都不公开
python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,
然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现

  

    一个静态属性property本质就是实现了get,set,delete三种方法

classmethod:

class Goods:
    __discount = 0.8
    def  __init__(self,name,price):
        self.name = name
        self.__price = price

    @property
    def price(self):
        return self.__price*Goods.__discount

    @classmethod  #讲一个普通方法装饰为一个类方法
    def change_discount(cls,new_dis):  # 类方法
        cls.__discount = new_dis
Goods.change_discount(1)
cig = Goods('cigrette',20)
print(cig.price)
cig.change_discount(0.2)
print(cig.price)
cig.change_discount(1)
print(cig.price)

>>20
>>4
>>20
classmethod

 

类方法是被@classmethod装饰的特殊方法,被装饰之后,方法默认接收一个 类 作为参数
  之后所有的操作都只能和 类中的静态变量相关 而不应该和对象相关
类名 和 对象名 都可以直接调用类方法

staticmethod:

class Student:
    def __init__(self,name):
        self.name = name

    @staticmethod    #装饰一个不需要self参数 也不需要cls参数的函数
    def login(a,b,c):    # 普通的函数
        usr = input('username>>>')
        pwd = input('password>>>')
        if usr == 'alex' and pwd == '123':
            obj = Student(usr)
            return obj
# 学生 login
# 用户名  密码  属性
ret = Student.login(1,2,3)
print(ret)

>>>
username>>>alex
password>>>123
<__main__.Student object at 0x000000000287FD30>
staticmethod

 

class Foo:
    def func(self):
        print('in father')


class Son(Foo):
    def func(self):
        print('in son')

s = Son()
s.func()
# 请说出上面一段代码的输出并解释原因?
练习一

 

class A:
    __role = 'CHINA'
    @classmethod
    def show_role(cls):
        print(cls.__role)

    @staticmethod
    def get_role():
        return A.__role

    @property
    def role(self):
        return self.__role

a = A()
print(a.role)
print(a.get_role())
a.show_role()
# __role在类中有哪些身份?
# 以上代码分别输出哪些内容?
# 这三个装饰器分别起了什么作用?有哪些区别?


>>>
CHINA
CHINA
CHINA
练习二

 

posted @ 2018-03-07 19:08  GuoXY  阅读(136)  评论(0编辑  收藏  举报