Python—面向对象的程序设计

一.面向对象和面向过程的区别

1.面向过程

面向过程类似于流水线的一种思维,在面向过程中,每个步骤是一个接着一个的执行,上一步的结果拿给下一步使用,每个步骤环环相扣,如果我们提请提供原材料,我们就可以预知得到的结果是怎样的,同样的,如果我们要修改其中某些功能的话,我们就要把所有的步骤重新设计,扩展性特别的差。

2.面向对象

面向对象的思想类似于一种老板的思维模式,例如,我想开一个公司,我会先找一个人力资源的经理帮我找人,在找一些其他部分的负责人,其他的事情就不用我来操心,让我找的人去完成即可,这些我找的人相当于一个个对象,对象之间的会相互交流,完成相应的事情,这样,如果我需要对公司的业务进行修改的话,也只需要修改一些,且不会影响到其他的人,这样的思想解决了扩展性的相关问题。但是,也存在一些问题,比如说找的人不好,产生的结果也不好,找的人好,产生的结果也是好的,所以,对产生的结果是不可预估的。

 

3.面向过程和面向对象的对比

面向过程注重在过程上面,环环相扣,扩展性差

面向对象注重在对象上面,扩展想好,但是结果不可预估。

 

二.类和对象

1.对象:对象是特征(变量)与技能(函数)的结合体

对象具有数据属性(变量),也具有技能的属性(函数),因此,对象是特征(变量)与技能(函数)的结合体

例如:人具有名字,性别,国籍等数据属性(变量表示),还具有说话,吃饭,跑步等属性等等(函数表示)。

2.类

从一组对象中提取有相似部分的部分组成一个类,类中所有的对象具有相同的属性和方法

例如:在所有的人的对象中,我们可以提取出一个中国人类,在这个类中,中国人都有自己的中文名字(数据属性),还会说汉语(技能属性)

3.类和对象之间的联系

1.在现实生活中,先有的对象,在有了类的概念

2.在程序的世界里,是先有的类,后有了对象的概念。

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

#程序中的类
class Chinese:
    country='China'
    def learn(self):
        print('is learning')
        
    def eat(self):
        print('is eating')
    
    def sleep(self):
        print('is sleeping')
  


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

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


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

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


s1=Chinese('李坦克','',18) #先调用类产生空对象s1,然后调用Chinese.__init__(s1,'李坦克','男',18)
s2=Chinese('王大炮','',38)
s3=Chinese('牛榴弹','',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')
示例

注意:!!! 类在定义的时候就会执行里面的代码,这个和函数是不一样的

class Chinese:
    country='China'
    def learn(self):
        print('is learning')
    print('===')  #===
    print(country)  #China

3.类的特殊属性

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

4.类中__init__的使用方法

class Chinese:
    country='China'

    def learn(self):
        print('is learning')

p1=Chinese()#实例化的过程
p2=Chinese()


#当我们使用上面的写法使用类的时候,我们会发现所有对象的属性都是一样的,但是如果有的对象属性和别人不一样的情况下,
# 我们该怎样解决呢?

# 这个时候就需要使用我们的__init()的方法了
class Chinese:

    def __init__(self,name,age):
        #只干初始化的工作,也可以加一些校验规则
        # if not isinstance(name,str):  #检验名字是否是字符串类型
        #     raise   TypeError
        self.name=name
        self.age=age

    def learn(self):
        print('is learning')

p1=Chinese("大锤",30) #实例化的过程就是调用__init__()方法的过程,由于里面有参数,我们必须要传参数,且要按照位置进行传参
                      #相当于__init__(p1,"大锤",30)

p2=Chinese("叮叮",40) #相当于__init__(p2,"叮叮",40)


"""
总结:
   1. __init()方法的就是用来满足每个对象有不同属性的而诞生出来的,通过这个方法,我们可以为不同的
    对象定制不同属性,使用了这个方法以后,示例化的过程就是调用这个函数,这个函数中有相应参数,我们
    示例化的过程中也要传入响应的参数,且要按照位置进行传参。(第一个参数是self,不需要自己传参,内部自动回把这个对象本身传进去)
    (如果定义类的时候没有定义__init__方法,示例化过程就不需要进行传参)
    
    2.__init__()方法只干初始化的工作,也可以做一些校验的规则,例如:校验参数是否符合格式
    
"""
__init__()的使用方法

5.从代码级别看到面向对象用法的好处(重点)

#1、在没有学习类这个概念时,数据与功能是分离的
def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx


def exc2(host,port,db,charset,proc_name)
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

#每次调用都需要重复传入一堆参数
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')




#2、我们能想到的解决方法是,把这些变量都定义成全局变量
HOST=‘127.0.0.1’
PORT=3306
DB=‘db1’
CHARSET=‘utf8’

def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx


def exc2(host,port,db,charset,proc_name)
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

exc1(HOST,PORT,DB,CHARSET,'select * from tb1;')
exc2(HOST,PORT,DB,CHARSET,'存储过程的名字')


#3、但是2的解决方法也是有问题的,按照2的思路,我们将会定义一大堆全局变量,这些全局变量并没有做任何区分,即能够被所有功能使用,然而事实上只有HOST,PORT,DB,CHARSET是给exc1和exc2这两个功能用的。言外之意:我们必须找出一种能够将数据与操作数据的方法组合到一起的解决方法,这就是我们说的类了

class MySQLHandler:
    def __init__(self,host,port,db,charset='utf8'):
        self.host=host
        self.port=port
        self.db=db
        self.charset=charset
    def exc1(self,sql):
        conn=connect(self.host,self.port,self.db,self.charset)
        res=conn.execute(sql)
        return res


    def exc2(self,sql):
        conn=connect(self.host,self.port,self.db,self.charset)
        res=conn.call_proc(sql)
        return res


obj=MySQLHandler('127.0.0.1',3306,'db1')
obj.exc1('select * from tb1;')
obj.exc2('存储过程的名字')


#改进
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('存储过程的名字')
从代码级别看出面向对象的简便

 4.属性引用

一个类中有两种属性:数据属性(变量的赋值)和函数属性(函数方法)

1.数据属性是所有对象共享使用的

2.函数属性是绑定给对象使用的

class Chinese:

    country='China'

    def __init__(self,name,age):
        self.name=name
        self.age=age
    def learn(self):
        print('is learning')

p1=Chinese("大锤",30)
p2=Chinese("叮叮",40)

# 从下面的结果可以看出对象也是引用类的数据属性
print(id(p1.country))#34841296
print(id(p2.country))#34841296
print(id(Chinese.country))#34841296


# 可以看出每个对象绑定的函数属性的的内存地址都是不一样的
#ps:id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准
print(Chinese.learn)
print(p1.learn)
print(p2.learn)
"""
<function Chinese.learn at 0x000000000299CBF8>
<bound method Chinese.learn of <__main__.Chinese object at 0x00000000029A2588>>
<bound method Chinese.learn of <__main__.Chinese object at 0x00000000029A25C0>>
"""
示例

3.类的数据类型中有可变数据类型一些需要注意的问题

#对于类的数据属性中有可变数据类型中的一些注意事项
class Chinese:
    country='China'
    l=[]
    def __init__(self,name,age):
        self.name=name
        self.age=age
        # self.l.append(123)
        Chinese.l.append(123)
    def learn(self):
        print('is learning')

p1=Chinese("大锤",30)

p2=Chinese("叮叮",40)
print(p1.l)#[123, 123]
print(p2.l)#[123, 123]
print(Chinese.l)#[123, 123]
注意事项

5.绑定方法 

类中的方法是绑定给对象使用的

class Chinese:
    country='China'

    def __init__(self,name,age):
        self.name=name
        self.age=age

    def learn(self):
        print('is learning')

p1=Chinese("大锤",30)
p2=Chinese("叮叮",40)

p1.learn()
p2.learn()
Chinese.learn(p1) #效果等同于p1.learn()
Chinese.learn(p2) #效果等同于p2.learn()


#由上述结果我们可以联想到:
s='qwe'
s1=s.upper()
s2=str.upper(s1)
print(s1) #QWE
print(s2) #QWE


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

2.类使用函数方法的时候,需要先实例好一个对象,在把对象
当做参数传进去,两者产生的结果是一样的,但是使用对象的时候由于可以
不用传参,使用起来更加方便,简单

"""

 

posted @ 2018-01-20 16:56  明-少  阅读(135)  评论(0)    收藏  举报