Python学习之==>面向对象编程(一)

一、面向对象与面向过程

  面向对象与面向过程是两种不同的编程范式,范式指的是按照什么方式去编程、去实现一个功能。不同的编程范式本质上代表对各种不同类型的任务采取不同的解决问题的思路。

1、面向过程编程

  角色是执行者,把一个项目按照一定的顺序,从头到尾一步步执行下去。这种思想好理解,但只要前面一个步骤变了,后面的步骤也要跟着变,维护起来比较麻烦。

2、面向对象编程

  角色是指挥者,把一个项目分成一个个小的部分,每个部分负责一方面的功能,整个项目由这些部分组合而成一个整体。类似一个机关,分为各个职能部门,只要符合一定的前提就行。面向对象的思想适合多人分工合作。

  面向对象是包含面向过程思路的,比如定义类中的方法,每个小方法、小功能还是面向过程的的思想。

  面向对象与面向过程的主要区别就是:面向对象可以使程序更加容易更改和扩展。

二、面向对象的特性

1、类

  Class,相当于一个种类、一个模型。一个类就是对一类拥有相同属性的对象的抽象、蓝图、原形。在类中定义了这些对象都具备的属性、共同的方法。

2、对象(实例)

  Object,根据模型造出来的具体的东西。一个对象就是一个类实例化后实例。一个类必须经过实例化后才能在程序中调用,一个类可以实例化多个对象,每个对象也可以有不同的属性。(对象就是实例,两者是一个意思)

3、实例化

  初始化一个类,创造一个对象。把一个类变成一个具体的对象的过程,叫做实例化。

4、属性

  属性就是类里面的一个变量,有类属性(类变量)和实例属性(实例变量)两种。类属性是在定义的时候就有的,实例属性是在实例化的时候才产生的变量。举个例子来说明类属性于实例属性:

  类属性(类变量):公共的变量,每个实例都可以用。直接通过“类名.XXX”来进行调用和修改,不需要实例化

  实例属性(实例变量):必须先进行实例化,然后通过“实例名.XXX”来进行调用和修改。

  下面简单定义一个类来说明以上概念,类的定义使用class关键字,类名的首字母大写。

 1 class Person():  # 经典类,新式类为:class Person(object):
 2     hand = 2     # 类属性/静态字段
 3     def __init__(self,name):  # 构造函数,类在实例化的时候自动执行的函数
 4         # self代表的是实例化之后的对象
 5         self.name = name  # 实例属性/普通字段
 6         self.nose = 1     # 实例属性/普通字段
 7         print('开始创造机器人。。。')
 8     def driver(self):  # 实例方法/普通方法
 9         print('%s开车中。。'%self.name)
10         self.eat()     # 调用类里面的方法
11     def fly(self):     # 实例方法/普通方法
12         print('%s,飞吧。。'%self.name)  # 获取类里面的变量
13     def eat(self):     # 实例方法/普通方法
14         print('%s吃吧,管饱'%self.name)
15 
16 # 类在用的时候,首先需要实例化
17 zlj = Person('张流量')   # 实例化:类名+括号
18 print(zlj.name)         # 调用实例属性
19 print(zlj.hand)         # 调用类属性
20 zlj.hand = 5            # 不会改变类变量,只影响实例里面的变量
21 print(zlj.hand)         # 5
22 print(Person.hand)      # 2,上面虽然通过实例修改了变量,但不影响类变量,只是zlj这个实例里面的变量发生了修改
23 zlj.sex = ''          # 为实例增加实例属性
24 print(zlj.sex)          #
25 zlj.driver()            # 调用类方法
26 zlj.fly()               # 调用类方法
27 dcg = Person('董春光')   # 实例化dcg
28 print(dcg.hand)         # 2
29 Person.hand = 10        # 修改类变量
30 print(dcg.hand)         # 10
31 print(zlj.hand)         # 5,修改类变量发生在修改实例变量之后,所以实例变量的值不再发生改变

5、方法

    方法就是类的功能,是定义在类里面的函数

  (1)构造方法:__init__

      实例化后会自动调用的方法,但不是每个类都必须写的,一个类中可以没有构造方法。

  (2)实例方法/普通方法:self

      保存在类中,由对象来调用,实例化后才能使用的方法。

  (3)静态方法():@staticmethod

      a、静态方法就是一个普通的函数,只不过写在类里面而已

      b、它用不了本类中的类属性(变量)、类方法、实例属性(变量)、实例方法

      c、保存在类中,通过类名+静态方法名()直接调用

      d、也可以通过实例化后,通过实例调用

  (4)类方法(cls):@classmethod

      a、不用实例化就可以直接调用

      b、它可以通过cls使用类变量

      c、它不能调用实例变量和实例方法

      d、不想实例化的时候,可以把方法定义成类方法

      e、也可以通过实例化后,通过实例调用

  (5)属性方法:@property

      看起来很像属性的一个方法,将没有入参的函数变为一个变为一个属性方法(类似于变量),结果是函数的返回值

 1 class Baby(object):
 2     nationality = 'China'   # 类变量,公共变量,每个实例都可以用
 3     def __init__(self):     # 构造方法,类在实例化的时候自动执行的函数
 4         self.name = 'niu'   # 实例变量,必须实例化才能调用
 5         print('init构造方法')
 6     def my(self):           # 实例方法,必须实例化才能调用
 7         self.sex = 'male'   # 实例变量,必须实例化才能调用
 8         print('self,实例方法')
 9     @staticmethod           # 静态方法
10     def xh():               # 静态方法括号里面不用写self
11         # self.name         # 报错,不能调用类中其他的实例变量
12         # self.my()         # 报错,不能调用类中其他的实例变量
13         print('staticmethod')
14     @classmethod            # 类方法,不用实例化就可以直接调用
15     def xm(cls):            # cls代表的就是Baby类
16         print('classmethod')
17         print(cls.nationality)  # 可以调用类变量
18         # cls.name          # 报错,不能调用类中其他的实例变量
19         # cls.my()          # 报错,不能调用勒种其他的实例方法
20     @property               # 属性方法,直接返回函数执行结果
21     def AAA(self):
22         return 98
23 
24 # 实例方法
25 Zll = Baby()     # 实例化,实例化后自动执行构造函数
26 Zll.my()         # 实例方法实例化后才能调用
27 
28 # 静态方法:
29 # 1、就是一个普通函数,只不过是写在类里面而已
30 # 2、它用不了类变量、类方法、实例变量、实例方法
31 # 3、可以不用实例化,直接调用类名调用
32 # 4、也可以通过实例化后,通过实例调用
33 Baby.xh()  # 不用实例化直接用类名调用类方法
34 a = Baby() # 也可以通过实例化后,通过实例调用
35 a.xh()
36 # 类方法:不想实例化的时候可以定义成类方法
37 # 1、不用实例化就可以直接调用
38 # 2、它可以通过cls使用类变量
39 # 3、它不能调用这个类里面的其他实例方法和实例变量
40 # 4、也可以通过实例化后,通过实例调用
41 Baby.xm()  # 不用实例化直接用类名调用类方法
42 b = Baby() # 也可以通过实例化后,通过实例调用
43 b.xm()
44 
45 # 属性方法
46 Dcg = Baby()
47 print(Dcg.AAA)  # 调用属性方法不用加括号

属性方法还有另外一种写法,如下:

 1 # 属性方法第二种方式
 2 class Foo():
 3     def f1(self):
 4         return 112
 5     def f2(self,name):  # 必须有参数
 6         print(name)
 7     def f3(self):
 8         print('f3')
 9     per = property(fget=f1,fset=f2,fdel=f3,doc='介绍&说明')
10 
11 obj = Foo()      # 实例化
12 ret = obj.f1()   # 获取f1的返回值
13 print(ret)
14 obj.per = 'niu'  # 传参数给f2并调用f2
15 del obj.per      # 调用f3

6、继承

  一个类可以派生出子类,在父类里面定义的属性和方法自动被子类继承,继承是为了代码重用。并且,子类可以重写父类的方法。Python3中经典类和新式类的多继承都是广度优先。但在Python2中,经典类和新式类的多继承是有区别的:经典类的多继承是深度优先,新式类的多继承是广度优先。

 1 class Father(object):  # 父类
 2     def __init__(self):
 3         self.money = 1000000
 4         self.house = '5环20套'
 5     def sing(self):
 6         print('唱歌')
 7     def dance(self):
 8         print('跳广场舞')
 9     def mf(self):
10         print('找朋友')
11 class Son(Father):    # 继承类:将父类名写在括号里
12     def dance(self):
13         self.house = '2环1套'
14         print('跳霹雳舞')
15 
16 # 通过继承类调用父类中的方法和变量
17 m = Son()       # 实例化
18 print(m.money)  # 调用父类中的实例变量
19 m.sing()        # 调用父类中的实例方法
20 m.dance()       # 子类和父类中都存在的方法则用子类中的方法
21 print(m.house)  # 子类和父类中都存在的变量则用子类中的变量

重写父类的方法:

  (1)父类方法没用,需要重写

  (2)父类方法不够完善,想给这个方法在原有的基础上添加一些功能

 1 class Zll():
 2     pass
 3 
 4 class Dcg():
 5     def smile(self):
 6         print('喔喔喔')
 7 
 8 class Lw():
 9     def smile(self):
10         print('啊啊啊')
11 
12 class Xz(Zll,Dcg,Lw):           # 子类可以继承多个父类
13     def smile(self):            # 重写父类的方法
14         Lw().smile()            # 调用父类,指定哪个父类
15         super(Xz,self).smile()  # 自动找到父类,先找到哪个类用哪个类
16         print('呵呵呵')
17 
18 A = Xz()
19 A.smile()

多继承:

(1)A作为B和C共同的父类

 1 class A(object):  # 新式类
 2     def x(self):
 3         print('A')
 4 class B(A):
 5     pass
 6 class C(A):
 7     def x(self):
 8         print('C')
 9 class D(B,C):
10     pass
11 
12 S = D()
13 S.x()    # C
14 # A作为B和C共同的父类时,是按D→B→C→A的顺序来找,遇到共同的父类时先不到父类中去找,先换到另外一个分支查找,找不到再到父类中去找

(2)A只作为B的父类

 1 class A(object):  # 新式类
 2     def x(self):
 3         print('A')
 4 class B(A):
 5     pass
 6 class C():
 7     def x(self):
 8         print('C')
 9 class D(B,C):
10     pass
11 
12 S = D()
13 S.x()    # A
14 # A只作为B的父类时,是按D→B→A→C的顺序来找,先找完一个分支,再找另外一个分支

(3)多继承中构造函数的调用

 1 class A(object):  # 新式类
 2     def __init__(self):
 3         print('A.init')
 4 class B(A):
 5     def __init__(self):
 6         print('B.init')
 7         A.__init__(self)
 8     def x(self):
 9         print('x')
10         self.y()  # 根据继承关系从头开始找,先从C中找,再从B中找
11     def y(self):
12         print('x--y')
13 class C():
14     def y(self):
15         print('y')
16 class D(C,B):
17     pass
18 
19 S = D() # 实例化时只会调用一次构造函数,本类找不到就到父类中找,但如果本类中找到则不再到父类中找构造函数
20 S.x()   # 调用B中的x时,self.y()不是直接调用B中的y,而是要根据继承关系先从C中找,如果C中没有,再从B中找,所以结果是x和y,不是x和x--y

7、封装

  把一些功能的实现细节隐藏,但类中对数据的赋值、内部调用对外部用户却是透明的,使类变成一个胶囊或容器,里面包含着类的数据和方法(比如说创造一个人,把身体内部的心肝脾肺肾都封装起来了,其他人只能直接找这个人而看不到里面有上面东西)。

8、多态

  对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。

  多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。一种接口,多种实现。

 1 class Animal(object):  # 父类
 2     def __init__(self, name):
 3         self.name = name
 4 class Dog(Animal):     # 狗类,有叫的方法
 5     def cry(self):
 6         print('狗 [%s] 汪汪汪' % self.name)
 7 class Cat(Animal):     # 猫类,有叫的方法
 8     def cry(self):
 9         print('猫 [%s] 喵喵喵' % self.name)
10 def cry(obj):          # 定义一个函数,去调用传进来的实例的cry方法
11     obj.cry()
12 
13 d1 = Dog('大黄')  # 实例化狗
14 d2 = Dog('小黄')  # 实例化狗
15 c1 = Cat('小白')  # 实例化猫
16 c2 = Cat('小黑')  # 实例化猫
17 cry(d1)           # 把对象d1传进来
18 cry(d2)           # 把对象d2传进来
19 objs = [d1, d2, c1, c2]  # 把上面实例化的对象都放到一个list里面
20 for obj in objs:         # 循环统一调用
21     cry(obj)

三、本类对象

  类中的self代表的是本类对象,也就是实例化后的对象。因为函数里面的变量都是局部变量,出了函数就不能使用,用self绑定之后,在类中任何地方都能随便使用(self.XXX)。

 1 class Baby:
 2     def __init__(self,name):
 3         #name = name      # 局部变量,出了函数就失效
 4         self.name = name  # 在类中self.name可以随便用了
 5         print('self的内存地址', id(self))
 6     def cry(self):
 7         print('%s在哭'%self.name)  # self.name在类中其他方法可以使用
 8 Zll = Baby('张流量')         # 实例化时将Amy的地址给self
 9 print('实例的内存地址',id(Zll))    # 与实例化时self的内存地址一致
10 Zll.cry()
11 # 通过运行发现self的内存地址和实例的内存地址是一样的,说明self代表的就是实例化后的对象Zll

四、构造函数与析构函数

1、构造函数

  类在实例化时自动执行的函数,但类中不是必须包含构造函数的。

  实例化时只有构造函数会自动执行,其他函数不会被执行。

1 class Baby(object):
2     def __init__(self):     # 构造函数,类在实例化的时候自动执行的函数
3         self.name = '牛牛'  # 实例变量,必须实例化才能调用
4     def my(self):           # 实例方法,必须实例化才能调用
5         self.sex = ''     # 实例变量,必须实例化才能调用
6 
7 Zll = Baby()
8 print(Zll.name)  # 实例化时构造函数自动执行
9 print(Zll.sex)   # my方法未被执行,所以会报错--'Baby' object has no attribute 'sex'

解决Zll.sex报错有两种方式:

(1)在构造函数中调用一次my函数,如下:

 1 class Baby(object):
 2     def __init__(self):     # 构造函数,类在实例化的时候自动执行的函数
 3         self.name = '牛牛'  # 实例变量,必须实例化才能调用
 4         self.my()           # 在构造函数中调用一次my方法,实例化时会自动执行
 5     def my(self):           # 实例方法,必须实例化才能调用
 6         self.sex = ''     # 实例变量,必须实例化才能调用
 7 
 8 Zll = Baby()
 9 print(Zll.name)  # 实例化时构造函数自动执行
10 print(Zll.sex)   # 实例化时自动调用了一次my函数

(2)实例化后,先调用一次my函数,再使用my函数下的实例变量,如下:

 1 class Baby(object):
 2     def __init__(self):     # 构造函数,类在实例化的时候自动执行的函数
 3         self.name = '牛牛'  # 实例变量,必须实例化才能调用
 4     def my(self):           # 实例方法,必须实例化才能调用
 5         self.sex = ''     # 实例变量,必须实例化才能调用
 6 
 7 Zll = Baby()
 8 print(Zll.name)  # 实例化时构造函数自动执行
 9 Zll.my()         # 调用一次my方法
10 print(Zll.sex)   

2、析构函数

  实例被销毁的时候执行,但不是必须的。

  一般可用于测试用例执行完毕后的关闭连接、关闭数据库、删除测试数据等操作。

例子:操作Mysql数据库

 1 import pymysql
 2 class MyDb(object):
 3     def __init__(self,host,user,db,passwd,
 4                  port=3306,charset='utf8'):  # 构造函数
 5         try:
 6             self.conn = pymysql.connect(
 7                 host=host,user=user,passwd=passwd,port=port,db=db,charset=charset,
 8                 autocommit=True  # 自动提交
 9             )
10         except Exception as e:
11             print('数据库连接失败!:%s'%e)
12         else:
13             self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
14 
15     def __del__(self):  # 析构函数,实例被销毁的时候执行
16         self.cur.close()
17         self.conn.close()
18         print('数据库连接关闭')
19 
20     def ex_sql(self,sql):
21         try:
22             self.cur.execute(sql)
23         except Exception as e:
24             print('sql语句有问题:%s'%sql)
25         else:
26             self.res = self.cur.fetchall()
27             return self.res
28 
29 my = MyDb('118.24.3.40','jxz','jxz','123456')
30 my.ex_sql('select * from stu;')
31 print(my.res)  # 可以用实例属性取值
32 print(my.ex_sql('select * from stu;'))  # 也可以用实例方法的返回值
33 print('我是最后一行代码')   # 执行完最后这行代码后再执行析构函数

五、私有变量&私有方法

出了类以后就不能再使用的变量和方法,被称为私有变量、私有方法。

有些重要的信息不想被调用,可以加两个下划线"__",将变量或者方法变为私有。

 1 # 私有方法 & 私有变量:出了类不能用
 2 class Redis(object):
 3     __table = 'user'               # 私有类变量
 4     def __init__(self):
 5         self.__host = '127.0.0.1'  # 私有变量
 6         self.port = 6379
 7     def __close(self):             # 私有方法
 8         print('私有方法')
 9     def open(self):
10         print('实例方法')
11         print(Redis.__table)       # 类内部可以调用私有类变量
12         self.__close()             # 类内部可以调用私有方法
13         return self.__host         # 类内部可以调用私有变量
14     @staticmethod
15     def stac():
16         return Redis.__table
17 
18 m = Redis()
19 print(m.__host) # 报错,没有__host这个属性,私有变量出类后不能再使用
20 m.__close()     # 报错,没有这个方法,,私有方法出类后不能再使用
21 m.__table       # 报错,没有__table这个属性,私有变量出类后不能再使用
22 print(m.port)   # 打印出:6379
23 m.open()        # 把私有方法放入实例方法中,通过调用实例方法可以拿到私有方法的返回值
24 Redis.stac()    # 通过静态方法还是可以拿到类的私有变量
25 # 和实例方法一样,静态方法和类方法同样也可以是私有的,这里就不再举例
26 # 存在继承关系的类中,子类不能调用父类的私有变量和私有方法,如果想访问需要在父类中定义一个共有的方法,然后把私有变量和方法放进去

例子:操作Redis数据库

 1 # 封装redis操作类
 2 import redis
 3 class My(object):
 4     def __init__(self):
 5         self.__host = '127.0.0.1'  # 私有变量
 6         self.__port = 6379         # 私有变量
 7         self.__passwd = ''         # 私有变量
 8         self.__db = 1              # 私有变量
 9         try:
10             self.r = redis.Redis(host=self.__host,port=self.__port,password=self.__passwd,db=self.__db)
11         except Exception as res:
12             print('redis连接失败..【%s】'%res)
13             # 这时并不会去连redis
14             # 所以捕捉不到数据库连接失败的异常,这里写的捕捉异常没有意义,可以不写
15     def __close(self):             # 私有方法
16         print('close')
17 
18     def str_get(self,name):                  # str类型get
19         res = self.r.get(name)
20         if res:
21             return res.decode()
22         return None
23 
24     def str_set(self,name,value,time=None):  # str类型set
25         self.r.set(name,value,time)
26 
27     def str_delete(self,name):               # str类型的删除key
28         # res = self.r.get(name)
29         res = self.r.exists(name)  # 判断redis数据库是否存在name这个key
30         if res:
31             self.r.delete(name)
32             print('删除成功')
33         else:
34             print('%s不存在'%name)
35 
36     def hash_get(self,name,key):             # hash类型获取单个key
37         res = self.r.hget(name,key)
38         if res:
39             return res.decode()
40         return None
41 
42     def hash_set(self,name,key,value):       # hash类型set
43         self.r.hset(name,key,value)
44 
45     def hash_getall(self,name):              # hash类型获取key里面的所有数据
46         dic = {}
47         res = self.r.hgetall(name)
48         if res:
49             for key,value in res.items():
50                 dic[key.decode()] = value.decode()
51             return dic
52         return None
53 
54     def hash_del(self,name,key):             # 删除某个hash里面小key
55         res = self.r.hget(name,key)
56         if res:
57             self.r.hdel(name,key)
58             print('删除成功')
59         else:
60             print('%s不存在'%name)
61 
62     def clean_redis(self):                   # 清理redis
63         # self.r.flushdb()  # 清空redis数据库
64         res = self.r.keys()
65         for key in res:
66             self.r.delete(key)
67         print('清空redis数据库成功')
68 
69 m = My()
70 m.str_set('Kity','famale')
71 print(m.str_get('Kity'))
72 m.str_delete('Kity')
73 m.hash_set('toy','car','red')
74 m.hash_set('toy','ball','blue')
75 print(m.hash_get('toy','car'))
76 print(m.hash_get('toy','car'))
77 m.hash_del('toy','car')
78 m.clean_redis()

posted on 2018-07-03 20:38  破解孤独  阅读(434)  评论(0编辑  收藏  举报

导航