美文网首页
lesson 040 —— 面向对象简介

lesson 040 —— 面向对象简介

作者: 爱喵喵的鱼 | 来源:发表于2019-02-11 12:43 被阅读0次

    lesson 040 —— 面向对象简介

    关于面向对象的简单介绍。

    三大编程范式

    1. 面向过程编程
    2. 函数式编程
    3. 面向对象编程

    面向对象概念

    • 类: 把一类事物相同的特征和动作整合到一起就是类。类是一个抽象的概念。类是一种数据结构。
    • 对象:就是基于类而创建的一个具体的事物(具体存在的),也是特征和动作整合到一起;对象就是类的实例化,具体化。对象是一个具体的事物。
    • 类与对象的关系: 对象是由类产生的,对象是类的实例化,具体化。
    • 实例化: 由类产生对象的过程叫实例化,类实例化的结果就是一个对象,或者叫一个实例(实例=对象)。
    1. 声明类
    class 类名:
        """类的文档字符串"""
        类体
        
    # 声明一个类,类名一般首字母大写,使用驼峰命名法
    # 代表的是:class Data(object):
    class Data:
        """这是一个时间的类。"""
        pass
    
    # 实例化这个类
    d1 = Data()
    

    在 Python3 中使用新式类,所有的类都继承自一个父类:object。

    2. 属性

    类是用来描述一类事物的,类的对象指的是一类事物中的一个个体。事物的属性分为:

    1. 数据属性: 就是变量
    2. 函数(方法)属性: 就是函数,在面向对象里称为方法。

    注意:类和对象都使用点 . 来访问自己的属性。

    3. 类的属性
    1. 类的数据属性: 类的数据属性是所有对象共享的

    2. 类的方法属性: 类的函数属性是绑定给对象用的

    3. 一些内置的类的特殊属性

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

      使用 dir(类名) 可以查看类的属性!!!

    class Data:
        """关于时间的类"""
        
        # 类的数据属性
        year = 2018
        month = 7
        day = 35
        week = '星期三'
        
        # 类的方法属性
        def print_year():
            print('2018 年')
        # 需要传入参数和这个类绑定,不传也没问题,可是不会绑定
        # 可是要使用参数的时候,就需要传入 self
        def print_data(self):
            print('%4d 年 %2d 月 %2d 日' % (self.year, self.month, self.day))
    
    if __name__ == '__main__':
        d1 = Data()
        d2 = Data()
    
        print("类的属性")
        print("Data.year: %d" % Data.year)
        print("Data.print_year: ")
        Data.print_year()
        # 这里类调用的话,就需要传入一个参数
        print("Data.print_data: ")
        Data.print_data(Data)
        print()
        
        print("类的属性是所有对象公有的")
        print("id Data.year: %d" % id(Data.year))
        print("id d1.year: %d" % id(d1.year))
        print("id d2.year: %d" % id(d2.year))
        print()
        
        print("函数属性是对于不同对象的")
        print("addr Data.print_data: ", Data.print_data)
        print("addr d1.print_data: ", d1.print_data)
        print("addr d2.print_data: ", d2.print_data)
        print("id Data.print_data: %d" % id(Data.print_data))
        print("id d1.print_data: %d" % id(d1.print_data))
        print("id d2.print_data: %d" % id(d2.print_data))
        print()
    
        print("d1 对象与类属性关系")
        print("d1.year: %d" % d1.year)
        # 这里不能调用,因为类里面是没有参数的,对象调用的话就会传入对象,即 self 参数
        #print("d1.print_year: ")
        #d1.print_year()
        print("d1.print_data: ")
        d1.print_data()
        print()
    
        print("类改变数据属性:")
        print("Data.year: %d" % Data.year)
        print("d1.year: %d" % d1.year)
        print("d2.year: %d" % d2.year)
        print("执行 Data.year = Data.year + 1")
        Data.year = Data.year + 1
        print("Data.year: %d" % Data.year)
        print("d1.year: %d" % d1.year)
        print("d2.year: %d" % d2.year)
        print()
    
        print("对象改变数据属性:")
        print("Data.year: %d" % Data.year)
        print("d1.year: %d" % d1.year)
        print("d2.year: %d" % d2.year)
        print("执行 d1.year = d1.year + 1")
        d1.year = d1.year + 1
        print("Data.year: %d" % Data.year)
        print("d1.year: %d" % d1.year)
        print("d2.year: %d" % d2.year)
        print("执行 d2.year = d2.year + 1")
        d2.year = d2.year + 1
        print("Data.year: %d" % Data.year)
        print("d1.year: %d" % d1.year)
        print("d2.year: %d" % d2.year)
        print()
    
        print("改变之后的地址")
        print("id Data.year: %d" % id(Data.year))
        print("id d1.year: %d" % id(d1.year))
        print("id d2.year: %d" % id(d2.year))
        print()
    

    结果:

    类的属性
    Data.year: 2018
    Data.print_year: 
    2018 年
    Data.print_data: 
    2018 年  7 月 35 日
    
    类的属性是所有对象公有的
    id Data.year: 139849464558928
    id d1.year: 139849464558928
    id d2.year: 139849464558928
    
    函数属性是对于不同对象的
    addr Data.print_data:  <function Data.print_data at 0x7f313da13d90>
    addr d1.print_data:  <bound method Data.print_data of <__main__.Data object at 0x7f313da440f0>>
    addr d2.print_data:  <bound method Data.print_data of <__main__.Data object at 0x7f313da44128>>
    id Data.print_data: 139849464102288
    id d1.print_data: 139849465338376
    id d2.print_data: 139849465338376
        
    d1 对象与类属性关系
    d1.year: 2018
    d1.print_data: 
    2018 年  7 月 35 日
    
    类改变数据属性:
    Data.year: 2018
    d1.year: 2018
    d2.year: 2018
    执行 Data.year = Data.year + 1
    Data.year: 2019
    d1.year: 2019
    d2.year: 2019
    
    对象改变数据属性:
    Data.year: 2019
    d1.year: 2019
    d2.year: 2019
    执行 d1.year = d1.year + 1
    Data.year: 2019
    d1.year: 2020
    d2.year: 2019
    执行 d2.year = d2.year + 1
    Data.year: 2019
    d1.year: 2020
    d2.year: 2020
    
    改变之后的地址
    id Data.year: 139849465104656
    id d1.year: 139849464558832
    id d2.year: 139849464558896
    

    从以上实例中我们可以验证得到这几个结论:

    1. 类的数据属性是所有对象共享的,我们称为类的数据

      id Data.year: 139849464558928
      id d1.year: 139849464558928
      id d2.year: 139849464558928
      
    2. 当使用改变类的数据之后,我们发现,所有的对象数据都改变了,即他们的地址都是一样的。

      类改变数据属性:
      Data.year: 2018
      d1.year: 2018
      d2.year: 2018
      执行 Data.year = Data.year + 1
      Data.year: 2019
      d1.year: 2019
      d2.year: 2019
      
    3. 但是,我们使用对象改变类的属性之后,仅仅是这个对象的数据变了,而其它对象和类的都不会改变。我们可以得知:Python 中,直接改变对象中类的数据,其实是创建了新的对象数据,而不是改变了类的数据,即将指向类的数据的变量指向了一个新的数据地址!!!

      对象改变数据属性:
      Data.year: 2019
      d1.year: 2019
      d2.year: 2019
      执行 d1.year = d1.year + 1
      Data.year: 2019
      d1.year: 2020
      d2.year: 2019
      执行 d2.year = d2.year + 1
      Data.year: 2019
      d1.year: 2020
      d2.year: 2020
          
      id Data.year: 139849465104656
      id d1.year: 139849464558832
      id d2.year: 139849464558896
      

      注意:Python 中几乎所有变量的赋值,都是将新的数据地址赋值给这个变量,即这个变量指向了一个新的内存地址,而不是改变变量指向的对应内存地址的数据!!!

    4. obj.name 会先从 obj 自己的名称空间里找 name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常.

    5. 类中的函数属性需要一个 self 形参来和这个类的对象绑定。在 Python 中,self 代表的就是对象,定义的函数属性本质上是定义一个函数。(虽然不加 self 程序不会报错,但是不会和对象绑定)。虽然绑定了,但是当类调用的时候可以随便传入参数,只要传入的参数使函数可以运行。

      def print_data(self):
          print('%4d 年 %2d 月 %2d 日' % (self.year, self.month, self.day))
      
      Data.print_data(Data)
      
    6. 类的函数属性没有 self 参数的时候,只有类可以调用,对象是无法调用的,它是类的方法

      # 这里不能调用,因为类里面是没有参数的,对象调用的话就会传入对象,即 self 参数
      #print("d1.print_year: ")
      #d1.print_year()
      
    7. 通过类来创建对象的时候,对于绑定的类的函数,即有 self 形参的函数,实际上是将那个函数复制到了对象的空间中,有了自己的内存,与类中的地址不一样。所以,通过类创建对象,虽然是同一个类,同一个类的函数,但是,每个对象都会复制函数,每个对象有他们自己的存储这个函数的内存,即变成了对象自己的函数,而不是类的函数。虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法!!!

      addr Data.print_data:  <function Data.print_data at 0x7f313da13d90>
      addr d1.print_data:  <bound method Data.print_data of <__main__.Data object at 0x7f313da440f0>>
      addr d2.print_data:  <bound method Data.print_data of <__main__.Data object at 0x7f313da44128>>
      id Data.print_data: 139849464102288
      id d1.print_data: 139849465338376
      id d2.print_data: 139849465338376
      
    8. 强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将本身当做第一个参数传给方法,即自动传值(方法 __init__ 也是一样的道理)

      注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数 selfself 可以是任意名字,但是约定俗成地写出self。

      # 类调用
      Data.print_data(Data)
      
      # 对象调用
      d1.print_data()
      
    4. 对象

    对象是类的实例化,类实例化的一个结果称为一个实例或者一个对象。

    class Student:
        school='xxoo'
        def __init__(self, name, sex, age):
            print('开始创建')
            self.name = name
            self.age = age
            self.sex = sex
            print('创建结束')
        def learn(self):
            print('%s is learning' % self.name) #新增self.name
    
        def eat(self):
            print('%s is eating' % self.name)
    
        def sleep(self):
            print('%s is sleeping' % self.name)
    
    # 创建对象
    s1=Student('李坦克','男',18)
    s2=Student('王大炮','女',38)
    s3=Student('牛榴弹','男',78)
    

    对象不仅有函数属性,还有类的数据属性,另外,还有它自己的数据属性。它们都可以通过 . 来访问

    对象的 __dict__ 属性只有函数属性,说明了对象只有数据属性

    要使用 __init__ 来设置初始化一个对象的方法,它没有返回值。

    对于每一个类里定义的参数,都必须要有 self 形参,且必须要有,还要放在第一个位置。

    5. 类属性增删改查

    类属性的操作使用 .del 进行操作,当使用类进行类属性的更改,它的所有的实例对象,不管是改变之前创建的,或者是改变之后创建的,都会跟着改变;当使用对象对类属性重新赋值之后,类属性实际不会改变,而这个对象的类属性转变为对象属性。数据属性与函数属性都一样,同样的方式。

    注意: 要调用类的属性,只能通过类名加点或者对象加点的方式调用,如果直接使用变量名,则调用的是全局的变量。调用不到类的属性。

    country = '中国'
    class N:
        country = '日本'
        num = ['a', 'b',]
        
        def __init__(self):
            print(country)   # 输出的是中国
        
    n1 = N()
    print(N.num)
    print(n1.num)
    n1.num.append(1)   # 没有给类属性赋新值,只是改变了类属性,所以结果是类属性改变了
    print(N.num)
    print(n1.num)
    

    结果:

    中国
    ['a', 'b']
    ['a', 'b']
    ['a', 'b', 1]
    ['a', 'b', 1]
    

    相关文章

      网友评论

          本文标题:lesson 040 —— 面向对象简介

          本文链接:https://www.haomeiwen.com/subject/aocqeqtx.html