• 面向对象程序设计


    一、类和对象

      即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,就是一系列对象相似特征和技能的结合体,针对同样的事物,站在不同的角度得到的类是不同的。需要注意的是:

    • 站的角度不同,定义出的类是截然不同的;
    • 现实中的类并不完全等于程序中的类,比如现实中的公司类,在程序中有时需要拆分成部门类,业务类等;
    • 有时为了编程需求,程序中也可能会定义现实中不存在的类,比如策略类,现实中并不存在,但是在程序中却是一个很常见的类。

    1、对象和类的先后关系

      在现实世界中一定是先有对象后有类;但在程序中,却是恰恰相反,一定是先定义类,后调用类来产生对象

    # 先定义类
    class LuffyStudent:
        school = 'luffycity'
    
        def learn(self):
            print('is learning')
    
        def eat(self):
            print('is eating')
    
        def sleep(self):
            print('is sleeping')
    
    
    # 后产生对象
    stu1 = LuffyStudent()  # 不是执行类体,而是实例化
    stu2 = LuffyStudent()
    stu3 = LuffyStudent()
    print(stu1)  # <__main__.LuffyStudent object at 0x10401ae80>

     注意:

    • 类中可以有任意Python代码,这些代码的类定义阶段便会执行,因而会产生新的名称空间,用来存放类的变量名和函数名,可以通过__dict__查看。
    • 类中定义的名字,都是类的属性,点是访问属性的语法。
    • 对于经典类来说我们可以通过该字典操作类名称空间的名字,但新式类有限制。

    2、__dict__方法

       __dict__是一个字典,键为属性名,值为属性值。类的__dict__存储所有实例共享的变量和函数(类属性,方法等),类的__dict__并不包含其父类的属性。

    class LuffyStudent:
        school = 'luffycity'
    
        def learn(self):
            print('is learning')
    
        def eat(self):
            print('is sleeping')
    
    
    print(LuffyStudent.__dict__)
    print(LuffyStudent.__dict__['school'])
    print(LuffyStudent.__dict__['learn'])
    """
    {'__module__': '__main__', 'school': 'luffycity', 'learn': <function LuffyStudent.learn at 0x101eb3620>, 'eat': <function LuffyStudent.eat at 0x101f211e0>, '__dict__': <attribute '__dict__' of 'LuffyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'LuffyStudent' objects>, '__doc__': None}
    luffycity
    <function LuffyStudent.learn at 0x101eb3620>
    """

    需要注意__dict__与dir()函数的区别:  

      1、dir()是Python提供的一个API函数,dir()函数会自动寻找一个对象的所有属性(包括从父类继承的属性),包括__dict__中的属性。

      2、__dict__是dir()的子集,一个实例的__dict__属性仅仅是那个实例的实例属性的集合,并不包含该实例的所有有效属性。

    3、特殊类属性

    __name__:查看类的名字(这里的类名是字符串类型的)

    __dict__:查出一个字典,key为属性名,value为属性值

    __doc__:显示注释

    dir(类名):查看类,以列表的形式显示出来

    __module__:类定义所在的模块

    __class__:

    isinstance(stu1, LuffyStudent):判断对象是否是类的实例

    4、引用类的属性

      在使用类时,可以对类的属性进行增删改查操作。

    class LuffyStudent:
        school = 'luffycity'
    
        def learn(self):
            print('is learning')
    
        def eat(self):
            print('is sleeping')
    
    # 查看
    print(LuffyStudent.school)  # luffystudent.__dict__['school']
    print(LuffyStudent.learn)  # Luffystudent.__dict_ ('learn')
    """
    luffycity
    <function LuffyStudent.learn at 0x101cb3620>
    """
    
    #
    LuffyStudent.country = 'China'
    print(LuffyStudent.__dict__)
    print(LuffyStudent.country)
    """
    {'__module__': '__main__', 'school': 'luffycity', 'learn': <function LuffyStudent.learn at 0x101eb3620>, 'eat': <function LuffyStudent.eat at 0x1040211e0>, '__dict__': <attribute '__dict__' of 'LuffyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'LuffyStudent' objects>, '__doc__': None, 'country': 'China'}
    China
    """
    
    #
    del LuffyStudent.country
    
    #
    LuffyStudent.school = 'whu'
    print(LuffyStudent.school)
    """
    whu
    """

    5、实例化

      调用类(实例化),得到程序中的对象。

    class LuffyStudent:
        school = 'luffycity'
    
        def learn(self):
            print('is learning')
    
        def eat(self):
            print('is eating')
    
        def sleep(self):
            print('is sleeping')
    
    
    # 后产生对象
    stu1 = LuffyStudent()  # 不是执行类体,而是实例化
    stu2 = LuffyStudent()
    stu3 = LuffyStudent()
    print(stu1)
    print(stu2)
    print(stu3)
    """
    <__main__.LuffyStudent object at 0x10401ae80>
    <__main__.LuffyStudent object at 0x10401af28>
    <__main__.LuffyStudent object at 0x10401af60>
    """

      实例化完成后,stu1、stu2、stu3都一样了,这三者除了相似的属性外还有各种不同的属性,就需要用到__init__方法了。

    6、__init__方法:为对象定制自己独有的特征

       __init__方法是在对象产生之后才会执行,只用来为对象进行初始化操作,可以有任意代码,但一定不能有返回值。

      实例化后会产生对象的名称空间,对象的名称空间也可以用stu1.__dict__查看:{'Name': '百合', 'Sex': '女', 'Age': 12}

    class LuffyStudent:
        school = 'luffycity'
    
        def __init__(self, name, sex, age):  # 实例化时自动调用
            self.Name = name
            self.Sex = sex
            self.Age = age
    
        def learn(self):
            print('is learning')
    
        def eat(self):
            print('is sleeping')
    
    
    # 产生对象
    stu1 = LuffyStudent('百合', '', 12)
    print(stu1.Name)
    
    """
    加上__init__方法后,实例化的步骤
        1、先产生一个空对象
        2、LuffyStudent.__init__(stu1, '百合', '女', 12)
    """
    
    #
    print(stu1.__dict__)
    print(stu1.Name)
    print(stu1.Sex)
    print(stu1.Age)
    """
    {'Name': '百合', 'Sex': '女', 'Age': 12}
    百合
    女
    12
    """
    
    #
    stu1.Name = '李二丫'
    print(stu1.__dict__)
    print(stu1.Name)
    """
    {'Name': '李二丫', 'Sex': '女', 'Age': 12}
    李二丫
    """
    
    # 删除
    del stu1.Name
    print(stu1.__dict__)
    """
    {'Sex': '女', 'Age': 12}
    """
    
    #
    stu1.class_name = 'python开发'
    print(stu1.__dict__)
    """
    {'Sex': '女', 'Age': 12, 'class_name': 'python开发'}
    """
    
    stu2 = LuffyStudent('李三炮', '', 22)
    print(stu2.__dict__)
    """
    {'Name': '李三炮', 'Sex': '男', 'Age': 22}
    """

      当类有了__init__方法后,实例化时先调用类产生空对象,再调用__init__()方法。

      上述代码中也包含有对象的使用,对对象的增删改查操作。

    7、关于self

      self,就是实例本身!你实例化时python解释器会自动把这个实例本身通过self参数传进去。

      self是实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给它起个别的名字,但是一般正常人都不会这么做,因为改了别人就不认识了。

    注意:def  __init__(self):   这句话可以写也可以不写,只要有参数参进来的时候就必须得写

       def  方法名(self):这里的self必须得写

    二、属性查找

      类中有两种属性:数据属性和函数属性。

    class LuffyStudent:
        school = 'luffycity'
    
        def __init__(self, name, sex, age):  # 实例化时自动调用
            self.Name = name
            self.Sex = sex
            self.Age = age
    
        def learn(self):
            print('%s is learning' % self.Name)
    
        def eat(self):
            print('%s is sleeping' % self.Name)
    
    
    # 产生对象
    stu1 = LuffyStudent('百合', '', 12)
    stu2 = LuffyStudent('李三炮', '', 38)
    stu3 = LuffyStudent('张铁蛋', '', 48)
    
    # 对象:特征和技能的结合体
    # 类:类是一系列对象相似的特征与相似技能的结合体

    1、类的数据属性是所有对象共享的

    # 类中数据属性:是所有对象共有的(都是一样的)
    print(LuffyStudent.school, id(LuffyStudent.school))
    
    print(stu1.school, id(stu1.school))
    print(stu2.school, id(stu2.school))
    """内存地址一样
    luffycity 4325120112
    luffycity 4325120112
    luffycity 4325120112
    """

    2、类的函数属性是绑定给对象用的,称为绑定到对象的方法。

    # 类中函数属性:是绑定给对象的,绑定到不同的对象是不同的绑定方法,对象调用绑定方法时,会把对象本身当做第一个参数传入,传给self
    print(LuffyStudent.learn)
    LuffyStudent.learn(stu1)
    """
    <function LuffyStudent.learn at 0x1040211e0>
    百合 is learning
    """
    
    print(stu1.learn)
    print(stu2.learn)
    print(stu3.learn)
    """绑定方法,每个人的函数内存地址不同
    <bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x10402cc18>>
    <bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x10402cc50>>
    <bound method LuffyStudent.learn of <__main__.LuffyStudent object at 0x10402cc88>>
    """

    3、属性查找顺序

      优先在对象中查找,对象中没有再在类中查找,类中没有会去父类查找,最后都没有则抛出异常。

    # 属性查找,优先对象中查找,对象中没有在类中查找
    # stu1.x = 'from stu1'
    LuffyStudent.x = 'from Luffycity class'
    
    print(stu1.__dict__)
    print(stu1.x)
    """
    {'Name': '百合', 'Sex': '女', 'Age': 12}
    from Luffycity class
    """

    三、绑定方法

      在属性查找那一小节中,定义了类并实例化出了三个对象stu1、stu2、stu3。

    class LuffyStudent:
        school = 'luffycity'
    
        def __init__(self, name, sex, age):  # 实例化时自动调用
            self.Name = name
            self.Sex = sex
            self.Age = age
    
        def learn(self):
            print('%s is learning' % self.Name)
    
        def eat(self):
            print('%s is sleeping' % self.Name)
    
    
    # 产生对象
    stu1 = LuffyStudent('百合', '', 12)
    stu2 = LuffyStudent('李三炮', '', 38)
    stu3 = LuffyStudent('张铁蛋', '', 48)
    定义类并实例化对象

      类中定义的函数(没有被任何装饰器装饰的)是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数。

    LuffyStudent.learn(stu1)
    LuffyStudent.learn(stu2)
    LuffyStudent.learn(stu3)
    """
    百合 is learning
    李三炮 is learning
    张铁蛋 is learning
    """

      类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法

      强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)

    stu1.learn()
    stu2.learn()
    stu3.learn()
    """
    百合 is learning
    李三炮 is learning
    张铁蛋 is learning
    """

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

    四、类即类型

      python中一切皆为对象,且Python3中类与类型是一个概念,类型就是类。

    class student:
        school = 'whu'
    
    # python当中一切皆对象,在python3中统一了类和类型的概念
    print(list)
    print(dict)∂
    print(student)
    """
    <class 'list'>
    <class 'dict'>
    <class '__main__.student'>
    """

       以list类型举例,类型list就是类list,对类实例化后,对象调用绑定方法append为对象添加元素。

    >>> list
    <class 'list'>
    
    #实例化的到3个对象l1,l2,l3
    >>> l1=list()
    >>> l2=list()
    >>> l3=list()
    
    #三个对象都有绑定方法append,是相同的功能,但内存地址不同
    >>> l1.append
    <built-in method append of list object at 0x10b482b48>
    >>> l2.append
    <built-in method append of list object at 0x10b482b88>
    >>> l3.append
    <built-in method append of list object at 0x10b482bc8>
    
    #操作绑定方法l1.append(3),就是在往l1添加3,绝对不会将3添加到l2或l3
    >>> l1.append(3)
    >>> l1
    [3]
    >>> l2
    []
    >>> l3
    []
    #调用类list.append(l3,111)等同于l3.append(111)
    >>> list.append(l3,111) #l3.append(111)
    >>> l3
    [111]

    五、面向对象小结

    1、定义及调用的固定格式

    class 类名:
        def __init__(self,参数1,参数2):
            self.对象的属性1 = 参数1
            self.对象的属性2 = 参数2
    
        def 方法名(self):pass
    
        def 方法名2(self):pass
    
    对象名 = 类名(1,2)  #对象就是实例,代表一个具体的东西
                      #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
                      #括号里传参数,参数不需要传self,其他与init中的形参一一对应
                      #结果返回一个对象
    对象名.对象的属性1   #查看对象的属性,直接用 对象名.属性名 即可
    对象名.方法名()     #调用类中的方法,直接用 对象名.方法名() 即可

    2、运用面向对象好处

    (1)将数据和专门操作该数据的功能整合到一起

      避免定义一大堆全局变量。

    class MySQLHandler:
        def __init__(self,host,port,db,charset='utf8'):
            self.host=host
            self.port=port
            self.db=db
            self.charset=charset
            self.conn=connect(self.host,self.port,self.db,self.charset)
        def exc1(self,sql):
            return self.conn.execute(sql)
    
        def exc2(self,sql):
            return self.conn.call_proc(sql)
    
    
    obj=MySQLHandler('127.0.0.1',3306,'db1')
    obj.exc1('select * from tb1;')
    obj.exc2('存储过程的名字')

    (2)可扩展性高

      定义类并产生多个对象

    class Chinese:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
    
    p1=Chinese('egon',18,'male')
    p2=Chinese('alex',38,'female')
    p3=Chinese('wpq',48,'female')

      如果新增一个类属性,会立刻反映给所有对象,而对象却无需修改。

    class Chinese:
        country='China'
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
        def tell_info(self):
            info='''
            国籍:%s
            姓名:%s
            年龄:%s
            性别:%s
            ''' %(self.country,self.name,self.age,self.sex)
            print(info)
    
    
    p1=Chinese('egon',18,'male')
    p2=Chinese('alex',38,'female')
    p3=Chinese('wpq',48,'female')
    
    print(p1.country)
    p1.tell_info()

    3、面向对象练习题 

    练习1:编写一个学生类,产生一堆学生对象。

    要求:有一个计数器(属性),统计总共实例了多少个对象

    class Student:   # 类名头字母大写
        school = 'whu'
        count = 0
    
        def __init__(self, name, age, sex):  # 为对象定制对象自己独有的特征
            self.name = name
            self.age = age
            self.sex = sex
            # self.count += 1  # 每个对象都是1,无法实现累加,student类的count一直都是0
            Student.count += 1
    
        def learn(self):
            print('%s is learning' % self.name)
    
        def eat(self):
            print('%s is eating very happy!' % self.name)
    
    
    stu1 = Student('alex', 'male', 38)   # 实例化一次就触发一次__init__
    stu2 = Student('jinxing', 'female', 48)
    stu3 = Student('egon', 'male', 18)
    
    
    print(Student.count)
    print(stu1.count)
    print(stu2.count)
    print(stu3.count)
    print(stu1.__dict__)
    print(stu3.__dict__)
    """
    3
    3
    3
    3
    {'name': 'alex', 'age': 'male', 'sex': 38}
    {'name': 'egon', 'age': 'male', 'sex': 18}
    """
    学生类具备计算器

    练习2:模仿王者荣耀定义两个英雄类, (10分钟)

    要求:1、英雄需要有昵称、攻击力、生命值等属性;

       2、实例化出两个英雄对象;

       3、英雄之间可以互殴,被殴打的一方掉血,血量小于0则判定为死亡。

    class Garen:
        camp = 'Demacia'
    
        def __init__(self, nickname, life_value, aggresivity):
            self.nickname = nickname
            self.life_value = life_value
            self.aggresivity = aggresivity
    
        def attack(self, enemy):
            enemy.life_value -= self.aggresivity
    
    
    class Riven:
        camp = 'Noxus'
    
        def __init__(self, nickname, life_value, aggresivity):
            self.nickname = nickname
            self.life_value = life_value
            self.aggresivity = aggresivity
    
        def attack(self, enemy):
            enemy.life_value -= self.aggresivity
    
    
    g1 = Garen('草丛伦', 100, 30)
    
    r1 = Riven('可爱的瑞雯', 80, 50)
    
    print(r1.life_value)
    g1.attack(r1)  # 攻击了一刀
    r1.attack(g1)
    print(r1.life_value)
    print(g1.life_value)
    英雄角色类互相交互

    4、判断是函数还是方法?

    函数:函数是封装了一些独立的功能,可以直接调用,python内置了许多函数,同时可以自建函数来使用。

    方法:方法和函数类似,同样封装了独立的功能,但是方法是需要通过对象来调用的,表示针对这个对象要做的操作,使用时采用点方法。

  • 相关阅读:
    Git ignore file for Xcode projects
    How can I create a zip archive of a whole directory via terminal without hidden files?
    What is a bare git repository?
    How to tell if UIViewController's view is visible
    Adding A Shadow To UIView
    Properties
    iOS中nil,Nil,NULL之间的区别
    FMDB的简单使用
    iOS 加载图片选择imageNamed 方法还是 imageWithContentsOfFile?
    对retain 和 assign的理解
  • 原文地址:https://www.cnblogs.com/xiugeng/p/8903694.html
Copyright © 2020-2023  润新知