面向对象三大特性:封装,继承,绑定方法和非绑定方法

封装:

  为什么要隐藏属性:

----------------------------------------------------------------------------------------

目的的是为了隔离复杂度,例如ATM程序的取款功能,该功能有很多其他功能组成,

比如插卡、身份认证、输入金额、打印小票、取钱等,

而对使用者来说,只需要开发取款这个功能接口即可,其余功能我们都可以隐藏起来

----------------------------------------------------------------------------------------

>>> 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()
...
>>> obj=ATM()
>>> obj.withdraw()

 

 property:

property是一个装饰器,是用来绑定给对象的方法伪造成一个数据属性(调用对象不用加括号调用)

案例一:

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

   #定义函数的原因1:
   #1.从bmi公式上看,bmi听该是触发功能计算得到的
   #2.bmi是随着身高体质变化而动态变化的,不是一个固定的值,每次需要临时计算
   @property  #把功能转化为数据属性
   def bmi(self):
      return self.weight/(self.height**2)

obj1 = People('whx',70,170)
print(obj1.bmi)  #0.002422145328719723

案例二(老操作):

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

   def get_name(self):
      return self.__name

   def set_name(self,val):
      if type(val) is not str:
         print('必须传入str类型')
         return
      self.__name = val

   def dle_name(self):
      print('不让删除')

   name = property(get_name,set_name,dle_name)

obj1 = People('whx')

print(obj1.name)  #get_name  查看
obj1.name = 'hello'  #set_name  修改
del obj1.name  #del_name  删除

案例三(常用操作***):

class People():
   def __init__(self,name):
      self.__name = name
   @property #就相当于进行了name = propert(name)操作
   def name(self):  #get_name
      return self.__name
   @name.setter
   def name(self,val):    #set_name
      if type(val) is not str:
         print('必须传入str类型')
         return
      self.__name = val
   @property.deleter
   def name(self):  #del_name
      print('不让删除')


obj1 = People('whx')

print(obj1.name)  #get_name  查看
obj1.name = 'hello'  #set_name  修改
del obj1.name  #del_name  删除

继承:

1.子类会遗传父类的属性

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

2.如果多个类有共同的功能或者属性,

那么可以放在同一个父类中存放,可以解决类与类代码冗余的问题 

(类是解决对象之间代码冗余的问题)


3.如果没有继承任何类,那么会默认继承object类,所以python3所有类都是新式类


多继承还有可能有可能会引发菱形问题

继承的示范:

如果父类有score对象   那么子类想要添加新的参数的话 

OldboyPeople.score(self,name)


单继承:

有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找

多继承:

棱形问题的属性查找关系:

 

 

#1.子类会先于父类被检查
#2.多个父类会根据它们在列表中的顺序被检查
#3.如果对下一个类存在两个合法的选择,选择第一个父类

ps:

1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,

 

深度优先和广度优先:

在python2中有经典类和派生类的说法,2种类会有不同的MRO机制,分别对应深度优先和广度优先


深度优先见名知意,如果有多个父类能直指最终的父类的话,那么则直接找到第一个直指父类的结束进程


广度优先,如果查找属性不存在时,会进行到最终父类前终止,直到最后一个父类指向最终父类再遍历最终父类的方法或者对象


 Minxins机制:

class Vehicle:  # 交通工具
    pass


class FlyableMixin:
    def fly(self):
        '''
        飞行功能相应的代码        
        '''
        print("I am flying")


class CivilAircraft(FlyableMixin, Vehicle):  # 民航飞机
    pass


class Helicopter(FlyableMixin, Vehicle):  # 直升飞机
    pass


class Car(Vehicle):  # 汽车
    pass

# ps: 采用某种规范(如命名规范)来解决具体的问题是python惯用的套路

 

1.首先它必须表示某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀

2.一个Mixin类只能写一个功能**如果有多个功能,那就写多个Mixin类,一个类可以继承多个Mixin,为了保证遵循继承的“is-a”原则,只能继承一个标识其归属含义的父类

3.然后,它不依赖于子类的实现

4.最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了)


绑定方法和非绑定方法:

classnethod:可以用类来调用

@classmethod的作用实际是可以在class内实例化class,

一般使用在有工厂模式要求时。作用就是比如输入的数据需要清洗一遍再实例化,

可以把清洗函数定义在class内部并加上@classmethod装饰器已达到减少代码的目的

总结起来就是:@class method可以用来为一个类创建一些预处理的实例。

绑定到类的方法就是专门给类用的,但其实对象也可以调用,只不过自动传入的第一个参数仍然是类


staticmethod:非绑定方法

1.该方法不与类或对象绑定,类与对象都可以来调用它,但它就是一个普通函数而已,因而没有自动传值那么一说

# 不绑定给对象,也不绑定给类
class Student():
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.id = self.get_id()

    @staticmethod  # 不绑定给对象,也不绑定给类,普通方法了
    def get_id():
        import uuid   #创建一个随机数模块
        return uuid.uuid4()
    
print(stu.id)  #e0ede872-db7c-462c-b6d5-5240d217f966
print(stu.get_id())  #c2c835f5-3c38-4574-8006-606e56bd507d
print(Student.get_id())  #d651ac87-5ad7-415d-bc50-627048dedb9a
'''如果方法里面用到了对象,又用到了类,最好绑定给对象'''

 2.总结:

绑定方法与非绑定方法的使用:若类中需要一个功能,该功能的实现代码中需要引用对象则将其定义成对象方法、

需要引用类则将其定义成类方法、无需引用类或对象则将其定义成静态方法。

 

posted @ 2023-03-19 23:22  无敌大帅逼  阅读(56)  评论(0)    收藏  举报