python-封装方法-封装的实现原理-property装饰器-多态-多态之ABC模块-鸭子类型

一、封装方法

  1. 如何封装方法:给方法名字前面加上双下划线
  2. 封装方法的好处:
    1. 提高安全性
    2. 隔离复杂度(将复杂的内容隔离到内部,外部只留下简单的接口,对于使用者而言,降低难度)
class A:

    def __f1(self):
        print("f1 run")

    def run_f1(self):
        self.__f1()

a = A()
a.run_f1()
# ATM的取款功能
#1.插入银行卡  2.输入密码  3.选择取款金额  4.取款
class ATM:
    def __insert_card(self):
        print("插入银行卡...")

    def __input_pwd(self):
        print("输入密码...")
    def __select_money(self):
        print("选择取款金额...")
    def withdraw(self):
        self.__insert_card()
        self.__input_pwd()
        self.__select_money()
        print("取款成功!....")

atm = ATM()
#外部调用这个简单的接口,就能完成一系列复杂的操作
atm.withdraw()

二、封装的实现原理

class Person:

    def __init__(self,name,sex,age,idCard):
        self.name = name
        self.sex = sex
        self.__age = age
        self.__idCard = idCard

    def get_idCard(self):
        return self.__idCard

    def __test(self):
        pass

    print("aaaaaaaaaa")

p = Person("比尔盖茨","男",20,"322323232332332")
p.__idCard = 'xxxxxxx'
print(p.get_idCard())

print(p.__dict__) #{'name': '比尔盖茨', 'sex': '男', '_Person__age': 20, '_Person__idCard': '322323232332332', '__idCard': 'xxxxxxx'}
print(Person.__dict__)

p.__xxxxxxxxxxxx = 1
print(p.__dict__) #{'name': '比尔盖茨', 'sex': '男', '_Person__age': 20, '_Person__idCard': '322323232332332', '__idCard': 'xxxxxxx', '__xxxxxxxxxxxx': 1}

#通过__dict__ 可以发现
#1.私有的属性和方法名称前自动加上了_类名,python就是通过这样的转换方式来实现封装
#2.只有在类的内部的双下划线才会被自动转换,并且这个转换过程只执行一次
#3.父类中私有的方法,子类中无法使用

子类无法覆盖父类的私有方法:

class  A:
    def f(self):
        self.__f1()   #_A__f1

    def __f1(self):
        print("A  __f1")

class B(A):
    def __f1(self):  # _B__f1
        print("B __f1")

    def f2(self):
        self.f()

b = B()
b.f2()
#之所以无法覆盖是因为子类和父类中的私有方法名称不相同,所以无法覆盖,子类的方法一定子类独有的,因为名称不同

三、property装饰器

  1. 当一些属性的值,不是固定的而是通过计算得来的时候,我们必须为这个属性增加方法才能完成计算。但是一旦使用方法后,该属性的访问就变成了方法的调用,很明显与其他的属性访问方式不同,这样给使用者造成迷惑

  2. property可以将方法伪装成属性,利用这个特点我们也可以将其使用到封装中,之前没有这个装饰器我们需要为私有的属性 提供两个方法,但是这样一来方访问私有属性时的方式就发生了变化

    这时候就可以使用property来进行伪装,使得访问私有属性与访问普通属性的方式一致

  3. 另外property还提供了setter(用于修改属性的值)和deleter(删除属性的值)

BIM案例:

class Person:
    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)


p = Person("尔晴",50,1.5)
print(p.bmi)
p.height += 0.2
print(p.bmi)
#22.22222222222222
#17.301038062283737

练习:

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

    def get_idCard(self):
        return self.__idCard

    def set_idCard(self,new_id):
        self.__idCard = new_id

    @property
    def idCard(self):
        return self.__idCard

    @idCard.setter
    def idCard(self,new_id):
        self.__idCard = new_id

    @idCard.deleter
    def idCard(self):
        print('身份证属性被删除了。。。')
        del self.idCard

#使用装饰器前
stu = Student("尔康","男","323254554554")
#普通属性的访问
print(stu.get_idCard())

#使用装饰器后,普通属性的访问
print(stu.idCard)
#使用装饰器后,普通属性的修改操作
stu.idCard = "aaaaaaa"
print(stu.idCard)
#使用装饰器后,普通属性的删除操作
del stu.idCard

print(stu.__dict__) #{'name': '尔康', 'sex': '男', '_Student__idCard': 'aaaaaaa'}
print(Student.__dict__)

四、多态

  1. 什么是多态:生活中具备多种形态的事物 水(水蒸气、冰、液体水)一种事物具备多种形态或状态 就称之为多态。

    官方解释:不同对象,可以使用同一方法,并作出不同的行为,产生不同的结果

  2. 如何实现多态:让几个不同类拥有相同父类,这样一来他们就具备了相同的方法,每个子类要覆盖父类的方法,从而每个类的对象行为都不同

class Animal:
    def eat(self):
        print("动物在吃东西...")
    def sleep(self):
        print("动物在睡觉...")
    def drink(self):
        print("动物需要水.....")


class Person(Animal):
    def eat(self):
        print("人吃粮食...")

class Pig(Animal):
    def eat(self):
        print("猪吃饲料...")

class Dog(Animal):
    def eat(self):
        print("狗吃骨头...")

person = Person()
pig = Pig()
dog = Dog()

person.eat()
pig.eat()
dog.eat()
#人吃粮食...
#猪吃饲料...
#狗吃骨头...
class Phone:
    def call(self):
        print("手机就能打电话..")

    def send_msg(self):
        print("手机能发短信..")


class WindowsPhone(Phone):
    def call(self):
        print("拨号打电话..")

    def send_msg(self):
        print("输入号码发短信..")

class IPhone(Phone):
    def call(self):
        print("拨号打电话..")


    def send_msg(self):
        print("输入号码发短信..")
#可以定义一个方法接受一个手机为参数,无论是是类型的手机都可以被使用
def CALL(phone):
    phone.call()

wp = WindowsPhone()
ipx = IPhone()

CALL(wp)
CALL(ipx)
#拨号打电话..
#拨号打电话..
#系统内置的方法有很多都体现了多态
print(len("abc"))
print(len([1,2,3,4,]))
print(len({"name":"123","sex":"man"}))

print("abc".__len__())
print([1,2,3,4,].__len__())
print({"name":"123","sex":"man"}.__len__())

五、多态之ABC模块

  1. 多态是多个类的对象拥有相同的方法,但是我们没有从严格要求说必须提供这些方法,子类完全可以不提供这些方法。在要做的就是严格要求子类必须实现父类声明的方法
  2. 多态的好处:完全不需要考虑得到的对象时声明类型,只要知道了其基类中的内容就能使用
  3. 使用ABC模块来限制字类的步骤:
    1. 为类中指定元类为abc.ABCMeta
    2. 在相应的方法上加上abc.abstractmethod装饰器
#abstract class 是抽象类的缩写 
import abc

class Animal(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def eat(self):
        pass

    @abc.abstractmethod
    def drink(self):
        pass


class Cat(Animal):
    def eat(self):
        print("猫爱吃鱼肉...")

    def drink(self):
        print("用舌头舔..")

class Dog(Animal):
    def eat(self):
        print("狗爱吃骨头...")
    def drink(self):
        print("用舌头舔..")

cat = Cat()
dog = Dog()

#多态的好处:完全不需要考虑得到的对象时声明类型,只要知道了其基类中的内容就能使用
def feeding(animal):
    animal.eat()
    animal.drink()

feeding(cat)
feeding(dog)
#猫爱吃鱼肉...
#用舌头舔..
#狗爱吃骨头...
#用舌头舔..

练习:

import abc

# 电脑基类
class Computer(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def open(self):
        pass

    @abc.abstractmethod
    def shutdown(self):
        pass

class DesktopComputer(Computer):
    def open(self):
        print("台式机正在启动....")

    def shutdown(self):
        print("台式机正在关机....")

class Worker:
    def working(self,pc):
        # 先开机
        pc.open()
        print("工作中.....")
        pc.shutdown()

w1 = Worker()
dp = DesktopComputer()
w1.working(dp)
#台式机正在启动....
#工作中.....
#台式机正在关机....

#增加了笔记本电脑
class BookComputer(Computer):
    def open(self):
        print("笔记本正在启动....")
    def shutdown(self):
        print("笔记本正在关机....")
bc = BookComputer()
w1.working(bc)

#增加了平板电脑
class PadComputer(Computer):
    def open(self):
        print("平板正在启动....")

    def shutdown(self):
        print("平板正在关机....")
pc = PadComputer()
w1.working(pc)

六、鸭子类型

  1. python推崇简单的编程方式,鸭子类型:如果一个对象叫声像鸭子,走路也像鸭子,那就把它当成鸭子。

    对应到代码中就是:只要你的行为一样,那就把你当成同一个类型来看待

class Duck:

    def bark(self):
        print("鸭子嘎嘎叫...")

    def run(self):
        print("摇摇晃晃走....")

class Chicken:
    def bark(self):
        print("鸡咯咯叫...")

    def run(self):
        print("摇摇晃晃走....")

def test(obj):
    obj.bark()
    obj.run()

duck = Duck()
chicken = Chicken()

test(duck)
test(chicken)
#鸭子嘎嘎叫...
#摇摇晃晃走....
#鸡咯咯叫...
#摇摇晃晃走....

题:

"""
	三个基础的宠物类 -- Cat类,Dog类,Pig类
	    属性:name(名字)、type(品种)
		name、type均为私有属性(对内可见,对外不可见)
		type属性为成员属性(由构造器__init__方法赋初值)
		但type对外又是可读可写(利用property装饰器实现)
		name属性初始化操作由父类完成(子类利用super()来实现)
	    方法:eat(self)
		均拥有eat的方法(父级继承)
		但实现体分别可以体现出 "吃猫粮"、"吃狗粮"、"吃猪粮"不同点(不同的实现)''==


	一个宠物的父类 -- Pet类
	    属性:name(名字)
		name为私有属性(对内可见,对外不可见)
		name属性为成员属性(由构造器__init__方法赋初值)
		但name对外又是可读可写(利用property装饰器实现)
	    方法:eat(self)
		拥有eat的方法(没有方法的实现体,利用abc模块实现)

	一个主人类 -- Master类
	    属性:name(名字)、pet(宠物)
		name、pet均为私有成员属性(具体操作同上面属性的操作)
	    方法:feed(self)
		拥有feed方法(方法只有self一个参数,没有多余的参数)
		feed方法实现要求
			-- "某某"主人准备好宠物粮食
			-- "某某品种"的"某某宠物"来进食
			-- 吃...(调用宠物自身的eat方法)
			注:""括起来的某某都是要被替换为具体的数据的

	创建三个宠物主人,分别养的是不同的三种宠物
	三个主人进行喂食的时候,对应养的宠物就会完成进食
	其他细节自由补充

"""
import abc

class Pet(metaclass=abc.ABCMeta):

    def __init__(self,name):
        self.__name = name
    @property
    def name(self):
        return  self.__name

    @name.setter
    def name(self,new_name):
        self.__name = new_name

    @abc.abstractmethod
    def eat(self):
        pass
class Cat(Pet):
    def __init__(self,name,type):
        # self.name = name
        super().__init__(name) # 这是在调用父类的init方法

        super().name = name # 这是在调用父类的name(new_name)
        self.__type = type

    @property
    def type(self):
        return  self.__type

    @type.setter
    def type(self,new_type):
        self.__type = new_type

    def eat(self):
        print("吃猫粮....")

class Pig(Pet):
    def __init__(self,name,type):
        # self.name = name
        super().__init__(name)
        self.__type = type

    @property
    def type(self):
        return  self.__type

    @type.setter
    def type(self,new_type):
        self.__type = new_type

    def eat(self):
        print("吃猪粮....")

class Master:
    def __init__(self,name,pet):
        self.__name = name
        self.__pet = pet

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

    @name.setter
    def name(self,new_name):
        self.__name = new_name

    @property
    def pet(self):
        return self.__pet

    @pet.setter
    def pet(self, new_pet):
        self.__name = new_pet

    def feed(self):
        print("""
            -- "%s"主人准备好宠物粮食
			-- "%s"的"%s"来进食
        """ % (self.name,self.pet.type,self.pet.name))
        self.__pet.eat()

pet = Pig("猪无能","猪")
m = Master("张三",pet)
m.feed()

猜你喜欢

转载自blog.csdn.net/zdc45625/article/details/85070770
今日推荐