面向对象编程知识点综合

一、面向对象编程与面向过程编程对比

  1、面向过程编程:核心过程二字,过程指的是解决问题的步骤,既先干什么、再干什么、后干什么,基于该思想的编程就好比在生产一条流水线,是一种机械式的思维方式。

    优点:复杂的问题流程化进而简单化

    缺点:可扩展性差

  2、面向对象编程:核心是对象二字,对象是技能与特征的结合体,基于该思想编写程序就好比在创造一个世界,世界是由一个个对象组成的,在上帝眼里任何存在的事物都是对象,任何不存在的事物也都可以创造出来,是一种上帝式的思维方式

    优点:可扩展性强

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

二、类与对象

  对象:对象是技能与特征的结合体

  类:对象相同特征与技能的结合体

    对象是具体存在的事物,而类则是抽象出来的概念,站在不同角度总结出来的类与对象是不同的

    在现实世界中,现有一个个具体存在的对象,然后随着人类文明的发展才总结出类的概念

#在现实世界中,站在老男孩学校的角度:先有对象,再有类
对象1:李坦克
    特征:
        学校=oldboy
        姓名=李坦克
        性别=男
        年龄=18
    技能:
        学习
        吃饭
        睡觉

对象2:王大炮
    特征:
        学校=oldboy
        姓名=王大炮
        性别=女
        年龄=38
    技能:
        学习
        吃饭
        睡觉

对象3:牛榴弹
    特征:
        学校=oldboy
        姓名=牛榴弹
        性别=男
        年龄=78
    技能:
        学习
        吃饭
        睡觉


现实中的老男孩学生类
    相似的特征:
        学校=oldboy
    相似的技能:
        学习
        吃饭
        睡觉
View Code

 

    在程序中,是先定义出类的概念后调用类来产生对象

#在程序中,务必保证:先定义(类),后使用(产生对象)
PS:
  1. 在程序中特征用变量标识,技能用函数标识
  2. 因而类中最常见的无非是:变量和函数的定义

#程序中的类
class OldboyStudent:
    school='oldboy'
    def learn(self):
        print('is learning')
        
    def eat(self):
        print('is eating')
    
    def sleep(self):
        print('is sleeping')
  


#注意:
  1.类中可以有任意python代码,这些代码在类定义阶段便会执行
  2.因而会产生新的名称空间,用来存放类的变量名与函数名,可以通过OldboyStudent.__dict__查看
  3.对于经典类来说我们可以通过该字典操作类名称空间的名字(新式类有限制),但python为我们提供专门的.语法
  4.点是访问属性的语法,类中定义的名字,都是类的属性

#程序中类的用法
.:专门用来访问属性,本质操作的就是__dict__
OldboyStudent.school #等于经典类的操作OldboyStudent.__dict__['school']
OldboyStudent.school='Oldboy' #等于经典类的操作OldboyStudent.__dict__['school']='Oldboy'
OldboyStudent.x=1 #等于经典类的操作OldboyStudent.__dict__['x']=1
del OldboyStudent.x #等于经典类的操作OldboyStudent.__dict__.pop('x')


#程序中的对象
#调用类,或称为实例化,得到对象
s1=OldboyStudent()
s2=OldboyStudent()
s3=OldboyStudent()

#如此,s1、s2、s3都一样了,而这三者除了相似的属性之外还各种不同的属性,这就用到了__init__
#注意:该方法是在对象产生之后才会执行,只用来为对象进行初始化操作,可以有任意代码,但一定不能有返回值
class OldboyStudent:
    ......
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    ......


s1=OldboyStudent('李坦克','',18) #先调用类产生空对象s1,然后调用OldboyStudent.__init__(s1,'李坦克','男',18)
s2=OldboyStudent('王大炮','',38)
s3=OldboyStudent('牛榴弹','',78)


#程序中对象的用法
#执行__init__,s1.name='牛榴弹',很明显也会产生对象的名称空间
s2.__dict__
{'name': '王大炮', 'age': '', 'sex': 38}

s2.name #s2.__dict__['name']
s2.name='王三炮' #s2.__dict__['name']='王三炮'
s2.course='python' #s2.__dict__['course']='python'
del s2.course #s2.__dict__.pop('course')
View Code

  __init__方法

#方式一、为对象初始化自己独有的特征
class People:
    country='China'
    x=1
    def run(self):
        print('----->', self)

# 实例化出三个空对象
obj1=People()
obj2=People()
obj3=People()

# 为对象定制自己独有的特征
obj1.name='egon'
obj1.age=18
obj1.sex='male'

obj2.name='lxx'
obj2.age=38
obj2.sex='female'

obj3.name='alex'
obj3.age=38
obj3.sex='female'

# print(obj1.__dict__)
# print(obj2.__dict__)
# print(obj3.__dict__)
# print(People.__dict__)





#方式二、为对象初始化自己独有的特征
class People:
    country='China'
    x=1
    def run(self):
        print('----->', self)

# 实例化出三个空对象
obj1=People()
obj2=People()
obj3=People()

# 为对象定制自己独有的特征
def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
    obj.name = x
    obj.age = y
    obj.sex = z

chu_shi_hua(obj1,'egon',18,'male')
chu_shi_hua(obj2,'lxx',38,'female')
chu_shi_hua(obj3,'alex',38,'female')





#方式三、为对象初始化自己独有的特征
class People:
    country='China'
    x=1

    def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
        obj.name = x
        obj.age = y
        obj.sex = z

    def run(self):
        print('----->', self)


obj1=People()
# print(People.chu_shi_hua)
People.chu_shi_hua(obj1,'egon',18,'male')

obj2=People()
People.chu_shi_hua(obj2,'lxx',38,'female')

obj3=People()
People.chu_shi_hua(obj3,'alex',38,'female')




# 方式四、为对象初始化自己独有的特征
class People:
    country='China'
    x=1

    def __init__(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
        obj.name = x
        obj.age = y
        obj.sex = z

    def run(self):
        print('----->', self)

obj1=People('egon',18,'male') #People.__init__(obj1,'egon',18,'male')
obj2=People('lxx',38,'female') #People.__init__(obj2,'lxx',38,'female')
obj3=People('alex',38,'female') #People.__init__(obj3,'alex',38,'female')


# __init__方法
# 强调:
#   1、该方法内可以有任意的python代码
#   2、一定不能有返回值
class People:
    country='China'
    x=1

    def __init__(obj, name, age, sex): #obj=obj1,x='egon',y=18,z='male'
        # if type(name) is not str:
        #     raise TypeError('名字必须是字符串类型')
        obj.name = name
        obj.age = age
        obj.sex = sex


    def run(self):
        print('----->', self)


# obj1=People('egon',18,'male')
obj1=People(3537,18,'male')

# print(obj1.run)
# obj1.run() #People.run(obj1)
# print(People.run)
View Code

类是一系列对象相同特征与技能的结合体,既类体中最常见的就是变量与函数体,但其实类体中是可以存在任意python代码的,

类体中会在定义阶段立即执行,会产生一个类的名称空间,用来将类体代码执行过程中产生的名字都丢进去

总结:①类本质就是一个名称空间,或者说就是一个用来存放变量与函数的容器,

     ②类的用途之一就是当做名称空间,从其内部取出名字来使用

   ③类的用途之二是用来调用类产生对象

调用类产生对象:调用类的过程称之为类的实例化,调用类的返回值称之为类的一个对象

View Code

  调用类发生了:

    1、产生一个空对象

    2、触发类中的__init__方法,将对象连同调用类括号内指定的参数一同传入__init__  

      类中定义的变量是类的数据属性,类可以用,对象也可以用,大家都指向同一个地址,类变量值一旦改变,所有对象都跟着改变

      类中定义的函数是类的函数属性,类可以用,类来调用就是一个普通的函数,但其实类中定义的函数就是给对象用的,而且是绑定给对象用的

      绑定方法:指向类的函数(特殊之处是绑定给谁就应该由谁调用)

      类的函数:该传几个参数就传几个参数

三大特性之继承:

  利用继承能来解决类与类之间的代码冗余问题

  继承是一种新建类的方法,新建的类称之为子类(派生类),被继承的类称之为父类、基类、超类

  继承的特性:子类可以遗传、重用父类的属性

python中继承类的特点:

  1、在python中一个子类可以同时继承多个父类

  2、在继承背景下说,python中类分为两种:新式类和经典类

    新式类:但凡继承了object的类以及该类的子类都是新式类

      python中一个类即便没有显示的继承任何类,默认就会继承object,即在python3中所有的类都是新式类

    经典类:没有继承object的类以及该类的子类都是经典类

   在单继承的基础下属性查找的顺序是:对象——》对象类——》父亲——》父类。。。

子类中重用父类的属性:

  方式一:

      在子类派生出的新方法中指名道姓的引用某一个类中的函数

      与继承无关,访问的是父类中的函数没有自动传值功能

继承解决的是类与类之间代码冗余的问题,一定是一个类是另外一个类的子类

总结对象之间的相似之处得到类,总结类之间的相似之处得到的就是父类

  多继承背景下属性查找的顺序:对象--》对象的类--》按照从左往右的顺序一个个的分支找下去

一旦出现菱形继承问题,新式类与经典类在属性查找上的区别是:

  新式类:广度优先查找,在最后一个分支查找顶级类

  经典类:深度优先查找,在第一个分支就查找顶级类

mro()查找的顺序:

  在子类派生出的新的方法中重用父类功能的方式二

    在子类中用super()方法

      python2中:super(自己的类名,对象自己)

      python3中:super()

  调用super()方法会得到一个特殊的对象,该对象是专门用来引用父类中的属性,完全参照mro()列表 访问是绑定方法,有自动传值的效果

组合:

  组合指的是一个对象拥有一个属性,该属性的值属于另外一个类的对象

  组合通过一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接的将两个类关联、整合,从而减少类之间的代码冗余问题

多态:

  多态指的是同一事物的不同形态

  在多态背景下,可以不用考虑对象具体的类型的前提下直接使用对象多态的精髓:统一

  父类只是用来建立规范的,不能用来实例化的,更无需实现内部方法。

  python崇尚鸭子类型

封装:

  装:往容器、名称空间内存入名字

  封:代表存放于名称空间的名字给藏起来,这种隐藏对外不对内

  在类内定义的属性前加__开头(没有__结尾)

总结:

  1、__开头的属性实现的隐藏仅仅只是一种语法上的变形,并不会真正的限制类外部的访问

  2、该变形操作只在类定义阶段检测语法时发生一次,类定义阶段之后新增的__开头的属性不会变形

  3、如果父类不想让子类覆盖自己的属性,可以在属性前加__开头

  4、peoperty装饰器是用来将类内的函数属性伪装为数据属性

绑定方法与非绑定方法

 

一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):

    1. 绑定到类的方法:用classmethod装饰器装饰的方法。

                为类量身定制

                类.boud_method(),自动将类当作第一个参数传入

              (其实对象也可调用,但仍将类当作第一个参数传入)

    2. 绑定到对象的方法:没有被任何装饰器装饰的方法。

               为对象量身定制

               对象.boud_method(),自动将对象当作第一个参数传入

             (属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)

 

import settings
class MySQL:
    def __init__(self,host,port):
        self.host=host
        self.port=port

    @classmethod
    def from_conf(cls):
        print(cls)
        return cls(settings.HOST,settings.PORT)

print(MySQL.from_conf) #<bound method MySQL.from_conf of <class '__main__.MySQL'>>
conn=MySQL.from_conf()

conn.from_conf() #对象也可以调用,但是默认传的第一个参数仍然是类

 

 

 

二:非绑定方法:用staticmethod装饰器装饰的方法

        1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已

    注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说

 

import hashlib
import time
class MySQL:
    def __init__(self,host,port):
        self.id=self.create_id()
        self.host=host
        self.port=port
    @staticmethod
    def create_id(): #就是一个普通工具
        m=hashlib.md5(str(time.time()).encode('utf-8'))
        return m.hexdigest()


print(MySQL.create_id) #<function MySQL.create_id at 0x0000000001E6B9D8> #查看结果为普通函数
conn=MySQL('127.0.0.1',3306)
print(conn.create_id) #<function MySQL.create_id at 0x00000000026FB9D8> #查看结果为普通函数
View Code

 

classmethod与staticmethod的区别

import settings
class MySQL:
    def __init__(self,host,port):
        self.host=host
        self.port=port

    @staticmethod
    def from_conf():
        return MySQL(settings.HOST,settings.PORT)

    # @classmethod #哪个类来调用,就将哪个类当做第一个参数传入
    # def from_conf(cls):
    #     return cls(settings.HOST,settings.PORT)

    def __str__(self):
        return '就不告诉你'

class Mariadb(MySQL):
    def __str__(self):
        return '<%s:%s>' %(self.host,self.port)


m=Mariadb.from_conf()
print(m) #我们的意图是想触发Mariadb.__str__,但是结果触发了MySQL.__str__的执行,打印就不告诉你:
View Code

三、 元类

  元类源自一句话,在python中一切皆对象,而对象都是由类实例化得到的,既然这样那样类也是对象,也是通过实例化得到的,内置类为type

调用关系是:

  调用元类——》自定义的类

  调用自定义的类——》自定义的对象

自定义类的三个关键组成部分

  1 类名

  2 类的基类们

  3 类的名称空间

class关键字的底层的工作原理

   1、先拿到类名(oldboyteacher)

  2、再拿到类的基类们:(object,)

  3、拿到类的名称空间(执行类体代码,将产生的名字放到类的名称空间也就是一个字典里,补充exec)

  4、调用元类实例化得到自定义的类:、oldboyTeacher=type('oldboyTeacher',(object){})

实现代码

 

class_name="OldboyTeacher"
class_bases=(object,)
class_dic={}
class_body='''
    school=self.shcool
    def  __init__(self,...)
       .............
    def score(......)         
    ...........
exec('x=1',{},class_dic)
 
print(class_dic)
OldboyTeacher_type(class_name,class_bases,class_dic)
View Code

 

自定义元类来控制类的产生:

  但凡继承了type的类才能称之为自定义的元类,否则就是一个普通的类

  对象之所以可以调用是因为对象有一个函数__call__

  实例化发生的三件事:

    1、产生一个空对象

    2、执行__init__方法,完成对象初始化属性的操作

    3、返回初始化好的那个对象

自定义类来控制类的调用

 

posted on 2018-09-04 16:20  一条流浪鱼  阅读(1376)  评论(0编辑  收藏  举报

导航