面向对象

目录

面向对象

1 三大特性

  1. 面向对象基本格式

    # 定义
    class 类名:# 类名首字母大写
     def 方法名(self,name):# self相当于形参但不用传参,name必须传参
            print(name)
            return 123
        def 方法名(self,name):
            print(name)
            return 456
    
    # 调用类的方法
    1.创建类的对象 # 实例化
    obj = 类名()
    2.通过对象调用方法
    result = obj.方法名('dpsy') # 使用对象调用类的方法
    print(result) # 返回值 
  2. 对象的作用

    • 存储一些值,以后方便自己使用

    • 将数据封装到对象,方便使用

      class File:
          def read(self):
              with open(self.wenjian,mode="r",encoding='utf-8') as f:
                  data = f.read()
             return data
         def write(self,content):
              with open(self.wenjian,mode='a',encoding='utf-8') as f:
                  f.write(content)
      # 实例化一个File的对象
      obj2 = File()
      # 在对象中写一个wenjian = "test.txt"
      obj2.wenjian = "info.txt"
      # 通过对象调用类中的read方法,read方法中的self就是obj.read()
      obj2.write("dpsy")
  3. 组合:一个类的对象作为另一个类对象的实例变量

 类与类之间的关系  

       1. 依赖关系

    2. 关联关系

    3. 组合关系

    4. 聚合关系

    5. 继承关系

    6. 实现关系

  一.类与类之间的依赖关系

    由于python是一门弱类型编程语言,并且所有的对象之间其实都是多态的关系,也就是说,所有的东西都可以当做对象来使用, 所以我们在写代码的时候很容易形成以上关系.首先,我们先看第一种, 也是这些关系中紧密程度最低的一个, 依赖关系.

    首先, 我们设计一个场景,还是最初的那个例子,要把大象装冰箱,注意,在这个场景中, 其实是存在了两种事物的, 一个是大象, 大象负责整个事件的掌控者, 还有一个是冰箱, 冰箱负责被大象操纵.

    class Elphant:

    def __init__(self, name):
        self.name = name
    def open(self, ref):
        print("大象要开门了. 默念三声. 开!")
        # 由外界传递进来一个冰箱, 让冰箱开门, 这时大象不用背着冰箱到处跑.
        # 类与类之间的关系也就不那么的紧密了, 换句话说, 只要是有open_door()方法的对象.  都可以接收运行
        ref.open_door()
  
    def close(self, ref):
        print("大象要关门了. 默念三声. 关!")
        pass
    def take(self):
        print("钻进去")
 
class Refrigerator:
    def open_door(self):
        print("冰箱门被打开了")
    def close_door(self):
        print("冰箱门被关上了")
# 造冰箱
= Refrigerator()
# 造大象
el = Elphant("神奇的大象")
el.open(r) # 注意,此时是把一个冰箱作为参数传递进去了,也就是说,大象可以指定任何一个冰箱.
el.take()
el.close(r)

此时我们说, 大象和冰箱之间就是依赖关系,我用着你,但是你不属于我, 这种关系是最弱的.比如,公司和雇员之间,对于正式员工, 肯定要签订劳动合同, 还得小心伺候着,但是如果是兼职,那无所谓,需要了你就来,不需要你就可以拜拜了. 这里的兼职(临时工) 就属于依赖关系,我用你但是你不属于我.

  二.关联关系.组合关系.聚合关系

其实这三个在代码上写法是一样的. 但是, 从含义上是不一样的. 

  1. 关联关系: 两种事物必须是互相关联的,但是在某些特殊情况下是可以更改和更换的

  2. 聚合关系: 属于关联关系中的一种特例,侧重点是xxx和xxx聚合成xxx. 各自有各自的声明周期, 比如电脑,电脑里有CPU, 硬 

   盘, 内存等等,电脑挂了, CPU还是好的,还是完整的个体

  3. 组合关系: 属于关联关系中的一种特例, 写法上差不多,组合关系比聚合还要紧密,比如人的大脑, 心脏, 各个器官. 这些器官组

   合成一个人. 这时人如果挂了,其他的东西也跟着挂了. 

  (1)首先我们看关联关系: 这个最简单,也是最常用的一种关系. 比如,大家都有男女朋友,男人关联着女朋友,女人关联着男朋友. 这种关系可以是互相的, 也可以是单方面的. 

   class Boy:

    def __init__(self, name, girlFriend=None):
        self.name = name
        self.girlFriend = girlFriend
 
    def have_a_dinner(self):
        if self.girlFriend:
            print("%s 和 %s⼀起去吃晚餐" % (self.name, self.girlFriend.name))
        else:
            print("单身狗. 吃什么饭")
 
class Girl:
    def __init__(self, name):
        self.name = name
 
= Boy("alex")
b.have_a_dinner()
 
# 突然牛B了. 找到女朋友了
= Girl("如花")
b.girlFriend = # 有女朋友了. 6666
b.have_a_dinner()
 
gg = Girl("李小花")
bb = Boy("wusir", gg) # 娃娃亲. 出生就有女朋友. 服不服
 
bb.have_a_dinner() # 多么幸福的一家
 
# 突然.bb失恋了. 娃娃亲不跟他好了
bb.girlFriend = None
 
bb.have_a_dinner() # 又单身

注意,此时Boy和Girl两个类之间就是关联关系,两个类的对象紧密联系着, 其中一个没有了,另一个就孤单的不得了, 关联关系, 其实就是我需要你, 你也属于我,这就是关联关系. 像这样的关系有很多很多,比如,学校和老师之间的关系.

  School --- 学校

  Teacher--- 老师

  老师必然属于一个学校,换句话说,每个老师肯定有一个指定的工作机构, 就是学校. 那老师的属性中必然关联着学校

class School:

    def __init__(self, name, address):
        self.name = name
        self.address = address
 
class Teacher:
    def __init__(self, name, school=None):
        self.name = name
        self.school = school
 
s1 = School("老男孩北京校区""美丽的沙河")
s2 = School("老男孩上海校区""迪士尼旁边")
s3 = School("老男孩深圳校区""南山区法院欢迎你")
t1 = Teacher("金王", s1)
t2 = Teacher("银王", s1)
t3 = Teacher("海峰", s2)
t4 = Teacher("高鑫", s3)
 
# 找到高鑫所在的校区地址
print(t4.school.address)

  三.继承关系

   在面向对象的世界中存在着继承关系,我们现实中也存在着这样的关系, 我们说过,x是一种y, 那x就可以继承y. 这时理解层面上的,如果上升到代码层面,我们可以这样认为, 子类在不影响父类的程序运行的基础上对父类进行的扩充和扩展. 这里我们可以把父类称为超类或者基类,子类被称为派生类.  

 

  ,我们来继续研究继承上的相关内容. 在本节中主要研究一下self,记住,不管方法之间如何进行调用, 类与类之间是何关系, 默认的self都是访问这个方法的对象.

class Base:

  def __init__(self, num):

    self.num = num
 
  def func1(self):
    print(self.num)
 
class Foo(Base):
    pass
 
obj = Foo(123)
obj.func1() # 123 运行的是Base中的func1
 
继续
 
class Base:
    def __init__(self, num):
        self.num = num
 
    def func1(self):
        print(self.num)
 
class Foo(Base):
    def func1(self):
        print("Foo. func1"self.num)
 
obj = Foo(123)
obj.func1() # Foo. func1 123 运行的是Foo中的func1
 
再来
class Base:
    def __init__(self, num):
        self.num = num
 
    def func1(self):
        print(self.num)
        self.func2()
 
    def func2(self):
        print("Base.func2")
 
class Foo(Base):
    def func2(self):
        print("Foo.func2")
 
obj = Foo(123)
obj.func1() # 123 Foo.func2 func1是Base中的 func2是子类中的

总结:self在访问方法的顺序: 永远先找自己的,自己的找不到再找父类的

接下来. 来难得: 

class Base:
    def __init__(self, num):
        self.num = num
 
    def func1(self):
        print(self.num)
        self.func2()
 
    def func2(self):
        print(111self.num)
 
class Foo(Base):
    def func2(self):
        print(222self.num)
 
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
 obj.func1() # 拿笔来吧. 好好算

结论: self就是你访问方法的那个对象,先找自己, 然后在找父类的

    1. 面向对象的三大特性:封装/继承/多态1.封装:

    2. 类的封装:

      1.   属性
        方法
        隐藏:
        私有化:
        类的内部可以访问,不允许外部访问
        属性私有化:
        self.__属性名 = 16

        方法私有化:
        def __方法名(self):
        pass

        python的私有化,不是真正的私有化,名字重整
        _类名__属性名/方法名

        对于私有属性,一般提供对应的接口
        1.获取值的接口
        def get属性名(self):
        return self.属性
        2.设置值的接口
        def set属性名(self,形参):
        self.属性 = 形参
        封装:
        将应该隐藏起来的东西,不能随意访问
    3. class Student():
      def __init__(self,name,age,gender):
      self.name = name
      #私有属性__age
      self.__age = age
      self.gender = gender

      #提供访问私有属性的方法(只提供读取值的接口的属性,可以称为只读属性)
      def getAge(self):
      return self.__age
      def setAge(self,age):
      if 1 <= age <= 120:
      self.__age = age
      else:
      print('年龄有误')
      def showInfo(self):
      print(self.name,self.__age,self.gender)

      def __test(self):
      print('__test方法')

      stu1 = Student('王昭君','18','女')
    4. # 之前的私有属性已经被改名为_Stuent__age,所以,stu1.__age 等于是加了一个新属性__age
      # stu1.__age = 1000
      print(dir(stu1))
      #通过修改私有属性的接口来完成值的修改
      stu1.setAge(2000)
      stu1.showInfo()
      #在类外,访问不到私有属性__age
      # print(stu1.name,stu1.__age,stu1.gender)
      #可以通过访问私有属性的接口来进行访问
      # print(stu1.name,stu1.getAge(),stu1.gender)
      # print(dir(stu1))
      # 私有属性的名字重整
      # print(stu1._Student__age)
      #在类外,无法访问私有方法
      # stu1.__test()
      • 继承

        • 什么时候用继承? 多个类中如果有公共的方法,可以放到基类中避免重复编写

        • self 到底是谁?

        • self 是哪个类创建的,就从此类开始找,自己(子类、派生类)没有就找父类(基类,超类)。

        • 多继承就从左往右找,左面找到跟,在找右面

          • 深度优先
          • 广度优先
        • 新式类和经典类

          • py2继承object就是新式类;默认经典类

          • py3都是新式类,默认继承object

          • 新式类

            • 继承object
            • 支持super
            • 多继承 广度优先C3算法
            • mro方法
          • 经典类

            • py2中不继承object
            • 没有super语法
            • 多继承 深度优先
            • 没有mro方法
            class A:
                pass
                # def func(self):
                #     print('a')
            class B(A):
                pass
                # def func(self):
                #     print('b')
            class C(A):
                def func(self):
                    print('c')
            class D(B,C):
                pass
                # def func(self):
                #     print('d')
            d = D()
            d.func()
            print(D.mro())
            # DBCA
            # DBAC


      • 多态

        •   多种形态:
          概念
          多态(polymorphism)是指同一个方法调用由于对象不同可能会产生不同的行为。
          在现实生活中,我们有很多例子。比如:同样是调用人的休息方法,张三的休息是睡觉,
          李四的休息是玩游戏,我的休息是写代码。同样是吃饭的方法,中国人用筷子吃饭,英国人用刀叉吃饭,印度人用手吃饭。
          注意点:
          1.多态是方法的多态,属性没有多态。
          多态的存在有2个必要条件:继承、方法重写。
          案例: 不同国家的人吃饭的问题
          """
          class Person():
          def eat(self):
          print('人都需要吃饭')
          class Chinese(Person):
          def eat(self):
          print('中国人使用筷子吃饭')
          class English(Person):
          def eat(self):
          print('英国人使用刀叉吃饭')
          class Indian(Person):
          def eat(self):
          print('印度人使用左手吃饭')

          # person = Person()
          # person.eat()
          # person = Chinese()
          # person.eat()
          # person = English()
          person = Indian()
          person.eat()
    1. 格式和关键词

      class 类:
          def __init__(self,x):
              self.x = x 
      
          def 方法(self,name):
              print(self.x, name)
      
      # 实例化一个类的对象
      v1 = 类(666)
      v2.方法('alex')

      关键词

      • 对象
      • 方法
    2. 什么时候用面向对象?

      • 函数(业务功能)比较多,可以使用面向对象来进行归类。
      • 想要做数据封装(创建字典存储数据时,面向对象)。
      • 游戏示例:创建一些角色并且根据角色需要再创建人物。

2 类成员

    • 类变量
    • 绑定方法
    • 类方法
    • 静态方法
    • 属性
  • 实例(对象)
    • 实例变量
  1. 实例变量

  2. 类变量

    • 定义:写在类的下一级和方法同一级

    • 所有方法都能共享且唯一

    • 使用

      • 类.类变量名称
      • 对象.类变量名称
    • 总结:找变量优先找自己,自己没有找类或基类,修改或赋值只能在自己的内部设置

  3. 方法(绑定方法或普通方法)

    • 定义:至少有一个self参数

    • 执行:先创建对象,有对象.方法()

      class Foo:
          def func(self,a,b):
              print(a,b)
      
      obj = Foo()
      obj.func(1,2)
      
      class Foo:
          def __init__(self):
              self.name = 123
      
         def func(self,a,b)
             print(self.name,a,b)
      
      obj = Foo()
      obj.func(1,2)
  4. 静态方法

    • 定义:

      • @staticmethod装饰器
      • 参数无限制
    • 执行:

      • 类.静态方法名()
      • 对象.静态方法名()(不推荐)
  5. 类方法

    • 定义:

      • @classmethod装饰器
      • 至少有cls参数,当前类
    • 执行:

      • 类.类方法()
      • 对象.类方法() (不推荐)
  6. 属性

    • 定义:
      • @property装饰器
      • 只有一个self参数
    • 执行:
      • 对象.方法 不需要加括号
    class    Foo:
        @property
        def func(self):
            print(123)
            return 33
    
    obj = Foo()
    result = obj.func
    print(result)

3 成员修饰符

  1. 公有,所有地方都能访问到

  2. 私有,只有自己可以访问到

  3. 补充 类的嵌套

    class Foo:
        pass
    
    class Foo(object):
        pass
    
    # 在python3中这俩的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。
    
    
    # 如果在python2中这样定义,则称其为:经典类
    class Foo:
        pass 
    # 如果在python2中这样定义,则称其为:新式类
    class Foo(object):
        pass 
    
    class Base(object):
        pass
    class Bar(Base):
        pass
  4. 强制访问私有实例变量

    class Foo:
        def __init__(self,name):
            self.__x = name
    
    obj = Foo('alex')
    
    print(obj._Foo__x) # 强制访问私有实例变量

4 特殊成员

作用: 就是能够快速实现执行某些方法而生

  1. __init__ 初始化方法

    class Foo:
        """
        类是干啥的
        """
        def __init__(self,a1)
         """
         初始化方法
         """
            self.a1 = a1
    
    obj = Foo('alex')
  2. __new__ 用于创建空的对象,构造方法

    class Foo(object):
        def __init__(self):
            """
            用于给对象中赋值,初始化方法
            """
            seif.a = 123
     def __new__(cls,*args,**kwargs):
         """
         用于创建空的对象,构造方法
         """
            return object.__new__(cls)
    
    obj = Foo()
  3. __call__ 对象加括号可以直接执行

    class Foo(object):
     def __call__(self,*args,**kwargs);
         print('执行call方法')
    # 执行方式一        
    obj = Foo
    obj()*
    # 执行方式二
    Foo()()
  4. __getitem__ 用于索引操作,如字典。表示 获取 数据

    __setitme__ 用于索引操作,如字典。表示 设置 数据

    __delitem__ 用于索引操作,如字典。表示 删除 数据

    class Foo(object):
    
        def __setitem__(self, key, value):
            pass
    
        def __getitem__(self, item):
            return item + 'uuu'
    
        def __delitem__(self, key):
            pass
    
    
    obj1 = Foo()
    obj1['k1'] = 123  # 内部会自动调用 __setitem__方法
    val = obj1['xxx']  # 内部会自动调用 __getitem__方法
    print(val)
    del obj1['ttt']  # 内部会自动调用 __delitem__ 方法
  5. __str__ 只有在print对象时,会自动化调用此方法

    class Foo(object):
        def __str__(self):
            """
            只有在打印对象时,会自动化调用此方法,并将其返回值在页面显示出来
            :return: 
            """
            return 'asdfasudfasdfsad'
    
    obj = Foo()
    print(obj)   # asdfasudfasdfsad
  6. __dict__ 去对象中找到所有变量并将其转换为字典

    class Foo(object):
        def __init__(self,name,age,email)
         self.name = name
            self.age = age
            self.email = email
    
    obj = Foo('dpsy',23,921921921@qq.com) 
    val = obj.__dict__
    print(val)
    # {'name': 'dpsy', 'age': 23, 'email': '921921921@qq.com'}
  7. 上下文管理

    class Foo(object):
        def do_something(self):
            print('内部执行')
    
    class Context:
        def __enter__(self):
            print('进入')
            return Foo()
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('推出')
    
    with Context() as ctx:
        print('内部执行')
        ctx.do_something()
    
    # 读写文件
      class Foo(object):
        def __enter__(self):
            self.x = open('a.txt',mode='a',encoding='utf-8')
            return self.x
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.x.close()
    
    with Foo() as ff:
        ff.write('dpsy')
    
  8. 两个对象相加

    val = 5 + 8
    print(val)
    
    val = "大王八" + "一万年"
    print(val)
    
    class Foo(object):
        def __add__(self, other):
            return 123
    
    obj1 = Foo()
    obj2 = Foo()
    val  = obj1 + obj2
    print(val)

5 栈

  1. 代码从上到下执行

    类可以做类的方法

  2. 栈:后进先出

    队列:先进后出

    # class Queue(object):  # 队列
    class Stack(object): # 栈
        """
        后进先出
        """
        def __init__(self):
            self.data_list = []
    
        def push(self,val):
            """
            入栈:向栈中压入一个数据
            :param val: 
            :return: 
            """
            self.data_list.append(val)
    
        def pop(self):
            """
            出栈:从栈中拿走一个数据
            :return: 
            """
            return self.data_list.pop()

6 约束(抽象类/接口类)

  • 约束子类中必须写父类中指定的方法,如果不写,则调用时候就报NotImplementedError

    class Interface(object):
        def send(self):
            raise NotImplementedError("子类中没有send")
    
    class Message(Interface):
        def send(self):
            print("发送短信")
    
    class Email(Interface):
        print(123)
    
    obj = Message()
    obj1 = Email()    # 123
    
    obj.send()    # 发送短信
    obj1.send()   # NotImplementedError: 子类中没有send

7 反射

​ 根据字符串的形式去某个对象中操作他的成员

​ 通过 对象 来获取 实例变量、绑定方法

​ 通过 类 来获取 类变量、类方法、静态方法

​ 通过 模块名 来获取 模块中的任意变量(普通变量 函数 类)

​ 通过 本文件 来获取 本文件中的任意变量

​ # getattr(sys.modules[name],'变量名')

  1. getatter(对象,"字符串") 根据字符串的形式去某个对象中获取对象的成员

    class Foo(object):
        def __init__(self,name):
            self.name = name
        def login(self):
            print(123)
    
    obj = Foo('sd')
    # 获取变量
    v1 = getattr(obj,'name')
    print(v1)
    # 获取方法
    method_name = getattr(obj,'login')
    method_name()
  2. hasattr(对象,"字符串") 根据字符串的形式去某个对象中判断是否有该成员,如果对象有该属性返回 True,否则返回 False。

    class Foo:
        a = 1
        b = 2
    
    obj = Foo()
    print(hasattr(obj,'a'))
    print(hasattr(obj,'b'))
  3. satattr(对象,'变量','值') 根据字符串的形式去某个对象中设置成员

    class Foo:
        k1 = 1
    
    obj = Foo()
    setattr(obj,'k1',123)    # 相当于obj.k1 = 123
    print(obj.k1)
  4. delattr(对象,'变量') 根据字符串的形式去某个对象中删除成员

    class Foo:
        k1 = 1
    
    obj = Foo()
    delattr(obj,'k1')
    print(obj.k1)
  5. python一切皆对象,所以以后想要通过字符串的形式操作其内部成员都可以通过反射的机制实现。

    • py文件
    • 对象

8 单例模式

  1. 无论实例化多少次,永远用的都是第一次实例化出的对象

    class Foo:
        pass
    
    # 多例,每实例化一次就创建一个新的对象。
    obj1 = Foo() # 实例,对象
    obj2 = Foo() # 实例,对象
    # 单例,无论实例化多少次,都用第一次创建的那个对象。
    obj1 = Foo()
    obj2 = Foo()
  2. 单例的标准

    class Singleton(object):
        instance = None
        def __new__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = object.__new__(cls)
            return cls.instance
    
    obj1 = Singleton()
    obj2 = Singleton()
    
    # 不是最终,加锁。
  3. 文件的连接池

    class FileHelper(object):
        instance = None
        def __init__(self, path):
            self.file_object = open(path,mode='r',encoding='utf-8')
    
        def __new__(cls, *args, **kwargs):
            if not cls.instance:
                cls.instance = object.__new__(cls)
            return cls.instance
    
    obj1 = FileHelper('x')
    obj2 = FileHelper('x')
  4. 通过模块导入的特性也可以实现单列模式

    # jd.py   自定义模块
    class Foo(object):
        pass
    
    obj = Foo()
    # app.py 导入模块
    import jd # 加载jd.py,加载最后会实例化一个Foo对象并赋值给obj
    print(jd.obj)

 

class Base:
    def __init__(self, num):
        self.num = num
 
    def func1(self):
        print(self.num)
        self.func2()
 
    def func2(self):
        print(111self.num)
 
class Foo(Base):
    def func2(self):
        print(222self.num)
 
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
    obj.func2() # 111 1 | 111 2 | 222 3

  再来,还不够绕. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Base:
    def __init__(self, num):
        self.num = num
 
    def func1(self):
        print(self.num)
        self.func2()
 
    def func2(self):
        print(111self.num)
 
class Foo(Base):
    def func2(self):
        print(222self.num)
 
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
 obj.func1() # 拿笔来吧. 好好算
posted @ 2019-05-31 18:36  爱学习的小猫咪  阅读(237)  评论(0编辑  收藏  举报