• 面向对象编程(基础)


    面向对象编程

    面向对象编程的核心是对象二字,对象是特征与技能的结合体。

    基于面向对象编程的思想编写程序,就好比是在创造一个世界,你就是这个世界的上帝,是一种上帝式的思维方式。

    优点:可扩展型强

    缺点:编程的复杂度要高于面向过程

    类与对象

    对象是特征与技能的结合体,类就是一系列对象相似的特征与技能的结合体。

    现实世界中,先有一个个具体存在的对象,随着发展才有了分类的概念,Python程序中也有类这个概念,但是Python程序中必须先定义类,然后调用类来产生对象。

    现实世界中定义类和对象

    定义对象

    • 学生类:

      相似的特征:

      学校 = '北京大学'
      

      相似的技能:

      选课
      

    程序中定义类和对象

    定义类

    # 注意类中定义变量使用驼峰体
    
    
    class BeijingStudent():
        school = 'peking'
    
        def choose_course(self):
            print('is choosing course')
    

    定义函数时,函数只检测语法,不执行代码。但是定义类的时候,类体代码会在类定义阶段就立刻执行,并且会产生一个类的名称空间,也就是说类的本身其实就是一个容器/名称空间,是用来存放名字的,这是类的用途之一。

    print(BeijingStudent.__dict__)
    
    {'__module__': '__main__', 'school': 'peking', 'choose_course': <function BeijingStudent.choose_course at 0x000002A4E1AB5D08>, '__dict__': <attribute '__dict__' of 'BeijingStudent' objects>, '__weakref__': <attribute '__weakref__' of 'BeijingStudent' objects>, '__doc__': None}
    
    print(BeijingStudent.__dict__['school'])
    
    peking
    
    print(BeijingStudent.__dict__['choose_course'])
    
    <function BeijingStudent.choose_course at 0x000002A4E1AB5D08>
    
    try:
        BeijingStudent.__dict__['choose_course']()
    
    except Exception as e:
        print('error:', e)
    
    error: choose_course() missing 1 required positional argument: 'self'
    
    print(BeijingStudent.school)
    
    peking
    
    BeijingStudent.choose_course(111)
    
    is choosing course
    
    print(BeijingStudent.choose_course)
    
    <function BeijingStudent.choose_course at 0x000002A4E1AB5E18>
    
    BeijingStudent.__dict__['choose_course']
    
    <function __main__.BeijingStudent.choose_course(self)>
    
    BeijingStudent.country = 'China'
    
    BeijingStudent.__dict__['country']
    
    'China'
    
    BeijingStudent.country = 'CHINA'
    
    BeijingStudent.__dict__['country']
    
    'CHINA'
    
    del BeijingStudent.school
    
    print(BeijingStudent.__dict__)
    
    {'__module__': '__main__', 'choose_course': <function BeijingStudent.choose_course at 0x000002A4E1AB5E18>, '__dict__': <attribute '__dict__' of 'BeijingStudent' objects>, '__weakref__': <attribute '__weakref__' of 'BeijingStudent' objects>, '__doc__': None, 'country': 'CHINA'}
    

    定义对象

    调用类即可产生对象,调用类的过程,又称为类的实例化,实例化的结果称为类的对象/实例。

    stu1 = BeijingStudent()  # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例
    print(stu1.country)
    
    CHINA
    
    stu2 = BeijingStudent()  # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例
    print(stu2.country)
    
    CHINA
    
    stu3 = BeijingStudent()  # 调用类会得到一个返回值,该返回值就是类的一个具体存在的对象/实例
    stu3.choose_course()
    
    is choosing course
    

    定制对象独有特征

    类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个。

    引入

    class BeijingStudent:
        school = 'peking'
    
        def choose_course(self):
            print('is choosing course')
    
    
    stu1 = BeijingStudent()
    stu2 = BeijingStudent()
    stu3 = BeijingStudent()
    

    对于上述的学生类,如果类的属性改了,则其他对象的属性也会随之改变。

    print(stu1.school)
    BeijingStudent.school = 'PEKING'
    
    peking
    
    print(stu1.school)
    
    PEKING
    

    定制对象独有特征

    print(stu1.__dict__)
    
    {}
    
    print(stu2.__dict__)
    
    {}
    

    对象本质类似于类,也是一个名称空间,但是对象的名称空间存放对象独有的名字,而类中存放的是对象们共有的名字。因此我们可以直接为对象单独定制名字。

    stu1.name = 'tom'
    stu1.age = 18
    stu1.gender = 'male'
    
    print(stu1.name, stu1.age, stu1.gender)
    
    tom 18 male
    
    try:
        print(stu2.name, stu2.age, stu2.gender)
    except Exception as e:
        print(e)
    
    'BeijingStudent' object has no attribute 'name'
    
    stu2.name = 'jerry'
    stu2.age = 18
    stu2.gender = 'female'
    
    print(stu2.name, stu2.age, stu2.gender)
    
    jerry 18 female
    

    类定义阶段定制属性

    def init(obj, x, y, z):
        obj.name = x
        obj.age = y
        obj.gender = z
    
    
    init(stu1, 'tom1', 19, 'male1')
    print(stu1.name, stu1.age, stu1.gender)
    
    tom1 19 male1
    
    init(stu2, 'jerry1', 29, 'female1')
    print(stu2.name, stu2.age, stu2.gender)
    
    jerry1 29 female1
    

    使用上述方法虽然让我们定制属性更简单,但还是太麻烦了,如果可以在实例化对象的时候自动触发定时属性,那就更方便了,因此可以使用类的__init__方法。

    class BeijingStudent:
        school = 'peking'
    
        def __init__(self, name, age, gender):
            '''调用类时自动触发'''
            self.name = name
            self.age = age
            self.gender = gender
            print('*'*20)
    
        def choose_course(self):
            print('is choosing course')
    
    
    try:
        stu1 = BeijingStudent()
    except Exception as e:
        print(e)
    
    __init__() missing 3 required positional arguments: 'name', 'age', and 'gender'
    
    stu1 = BeijingStudent('tom', 18, 'male')
    
    ********************
    
    • 通过上述现象可以发现,调用类时发生两件事:
      • 创造一个空对象
      • 自动触发类中__init__功能的执行,将stu1以及调用类括号内的参数一同传入
    print(stu1.__dict__)
    
    {'name': 'tom', 'age': 18, 'gender': 'male'}
    

    对象的属性查找顺序

    属性查找

    • 先从对象自己的名称空间找,没有则去类中找,如果类中也没有则报错
    class BeijingStudent:
        school = 'peking'
        count = 0
        aa = 10
    
        def __init__(self, x, y, z):  # 会在调用类时自动触发
            self.name = x
            self.age = y
            self.gender = z
            BeijingStudent.count += 1
    
            self.aa = 1
    
        def choose_course(self):
            print('is choosing course')
    
    print(BeijingStudent.count)
    
    0
    
    stu1 = BeijingStudent('tom', 18, 'male')
    print(stu1.count)
    
    1
    
    stu2 = BeijingStudent('jerry', 19, 'male')
    print(stu2.count)
    
    2
    
    stu3 = BeijingStudent('shane', 25, 'male')
    print(stu3.count)
    
    3
    
    print(BeijingStudent.count)
    
    3
    
    • 由于上述修改的是类属性,类属性的count已经被修改为3,所以其他实例的count都为3
    print(stu1.count)
    print(stu2.count)
    print(stu3.count)
    
    3
    3
    3
    
    • 由于aa是私有属性,因此stu们都会用私有的aa,不会用类的aa
    print(stu1.__dict__)
    print(stu2.__dict__)
    print(stu3.__dict__)
    
    {'name': 'tom', 'age': 18, 'gender': 'male', 'aa': 1}
    {'name': 'jerry', 'age': 19, 'gender': 'male', 'aa': 1}
    {'name': 'shane', 'age': 25, 'gender': 'male', 'aa': 1}
    

    类与对象的绑定方法

    类与对象的绑定方法

    class BeijingStudent:
        school = 'peking'
    
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def choose_course(self):
            print(f'{self.name} is choosing course')
    
        def func(self):
            print('from func')
    
    • 类名称空间中定义的数据属性和函数属性都是共享给所有对象用的

    • 对象名称空间中定义的只有数据属性,而且是对象所独有的数据属性

    类的绑定对象

    stu1 = BeijingStudent('tom', 18, 'male')
    stu2 = BeijingStudent('jerry', 19, 'male')
    stu3 = BeijingStudent('shane', 25, 'male')
    
    
    print(stu1.name)
    print(stu1.school)
    
    tom
    peking
    
    
    • 类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵循函数的参数规则,该传几个值就传几个值。
    print(BeijingStudent.choose_course)
    
    <function BeijingStudent.choose_course at 0x000002A4E1C01268>
    
    try:
        BeijingStudent.choose_course(123)
    except Exception as e:
        print(e)
    
    'int' object has no attribute 'name'
    

    对象的绑定方法

    • 类中定义的函数是共享给所有对象的,对象也可以使用,而且是绑定给对象用的
    • 绑定的效果:绑定给谁,就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入
    print(id(stu1.choose_course))
    print(id(stu2.choose_course))
    print(id(stu3.choose_course))
    print(id(BeijingStudent.choose_course))
    
    2907183244104
    2907183244104
    2907183244104
    2907185353320
    
    print(id(stu1.school))
    print(id(stu2.school))
    print(id(stu3.school))
    
    2907185318128
    2907185318128
    2907185318128
    
    print(id(stu1.name), id(stu2.name), id(stu3.name))
    
    2907185317792 2907185319192 2907185317568
    
    stu1.choose_course()
    stu2.choose_course()
    stu3.choose_course()
    
    tom is choosing course
    jerry is choosing course
    shane is choosing course
    
    • 补充:类中定义的函数,类确实可以使用,但其实类定义的函数大多情况下都是绑定给对象用的,所以在类中定义的函数都应该自带一个参数self
    stu1.func()
    
    from func
    
    BeijingStudent.func(1)
    
    from func
    

    类与数据类型

    类与数据类型

    • Python3中统一了类与类型的概念,类就是类型
    class Foo:
        pass
    
    
    obj = Foo()
    print(type(obj))
    
    <class '__main__.Foo'>
    
    lis = [1, 2, 3]
    lis2 = [4, 5, 6]
    print(type(lis))
    
    <class 'list'>
    
    • lis和lis2都是实例化的对象,因此lis使用append方法和lis2无关
    lis.append(7)
    print(lis)
    
    [1, 2, 3, 7]
    
    print(lis2)
    
    [4, 5, 6]
    

    list.append()方法原理

    class BeijingStudent:
        school = 'peking'
    
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def choose_course(self, name):
            print(f'{name} is choosing course')
    
    
    stu1 = BeijingStudent('tom', 18, 'male')
    
    stu1.choose_course(1)  # BeijingStudent.choose_course(stu1,1)
    
    1 is choosing course
    
    BeijingStudent.choose_course(stu1, 1)
    
    1 is choosing course
    
    lis = [1, 2, 3]
    print(type(lis))
    
    <class 'list'>
    
    lis.append(4)
    print(lis)
    
    [1, 2, 3, 4]
    
    list.append(lis, 5)
    print(lis)
    
    [1, 2, 3, 4, 5]
    

    对象的高度整合

    没有对象

    • 以连接数据库举例,如果没有面对对象的思想,我们只要想要使用一个方法,就必须得这样做
    import pymysql  # 连接mysql的三方库,可以pip3 install pymysql安装
    
    
    def exc1(host, port, db, charset, sql):
        conn = pymysql.connect(host, port, db, charset)
        conn.execute(sql)
        return xxx
    
    
    def exc2(proc_name):
        conn = pymysql.connect(host, port, db, charsett)
        conn.call_proc(sql)
        return xxx
    
    
    exc1('1.1.1.1', 3306, 'db1', 'utf-8', 'select * from t1')
    exc1('1.1.1.1', 3306, 'db1', 'utf-8', 'select * from t2')
    exc1('1.1.1.1', 3306, 'db1', 'utf-8', 'select * from t3')
    exc1('1.1.1.1', 3306, 'db1', 'utf-8', 'select * from t4')
    
    • 由于host、port、db、charset可能是固定不变的,sql一直在变化,因此我们通过上述的方法实现不同的sql语句,非常麻烦,因此我们可以改用默认形参
    def exc1(sql, host='1.1.1.1', port=3306, db='db1', charset='utf-8'):
        conn = pymysql.connect(host, port, db, charset)
        conn.execute(sql)
        return xxx
    
    
    exc1('select * from t1')
    exc1('select * from t2')
    exc1('select * from t3')
    exc1('select * from t4')
    
    • 虽然是用默认参数简化了操作,但是对于不同引用的对象,参数并不是一成不变的,或者我们需要对exc2方法进行修改,这是非常麻烦的,因此可以考虑使用面向对象

    有对象

    • 有了面对对象之后,对于上述的例子,我们可以这样做
    import pymysql
    
    
    class Foo:
        def __init__(self, host, port, db, charset):
            self.host = host
            self.port = port
            self.db = db
            self.chartset = chartset
    
        def exc1(self, sql):
            conn = pymysql.connect(self.host, self.port, self.db, self.charset)
            conn.execute(sql)
            return xxx
    
        def exc2(self, proc_name):
            conn = pymysql.connect(self.host, self.port, self.db, self.charsett)
            conn.call_proc(sql)
            return xxx
    
    
    obj1 = Foo('1.1.1.1', 3306, 'db1', 'utf-8')
    obj1.exc1('select * from t1')
    obj1.exc1('select * from t2')
    obj1.exc1('select * from t3')
    obj1.exc1('select * from t4')
    
    obj2 = Foo('1.1.1.2', 3306, 'db1', 'utf-8')
    obj2.exc1('select * from t4')
    
    • 对于上述发生的现象,我们可以总结对象其实就是一个高度整合的产物,整合数据与专门操作该数据的方法(绑定方法)
  • 相关阅读:
    引用类型Array进行数值对比(应用jquery版)
    在网站前端中,你可能会用到的这些…
    javascript获得鼠标的坐标值
    增加PV方法
    wordpress后台修改“WordPress 地址(URL)”后无法打开的解决方法
    css给网页添加 黑白滤镜
    配置Android开发环境(fedora)
    成功的从fedora 7升级到了fedora 8
    听说这些是公司高管必读的笑话
    debian英文环境中中文输入
  • 原文地址:https://www.cnblogs.com/WilliamKong94/p/11123172.html
Copyright © 2020-2023  润新知