200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > Python学习之==面向对象编程(一)

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

时间:2020-02-27 06:25:24

相关推荐

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

一、面向对象与面向过程

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

1、面向过程编程

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

2、面向对象编程

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

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

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

二、面向对象的特性

1、类

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

2、对象(实例)

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

3、实例化

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

4、属性

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

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

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

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

1 class Person(): # 经典类,新式类为:class Person(object): 2hand = 2# 类属性/静态字段 3def __init__(self,name): # 构造函数,类在实例化的时候自动执行的函数 4 # self代表的是实例化之后的对象 5 self.name = name # 实例属性/普通字段 6 self.nose = 1# 实例属性/普通字段 7 print('开始创造机器人。。。') 8def driver(self): # 实例方法/普通方法 9 print('%s开车中。。'%self.name)10 self.eat()# 调用类里面的方法11def fly(self):# 实例方法/普通方法12 print('%s,飞吧。。'%self.name) # 获取类里面的变量13def 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) # 522 print(Person.hand)# 2,上面虽然通过实例修改了变量,但不影响类变量,只是zlj这个实例里面的变量发生了修改23 zlj.sex = '男'# 为实例增加实例属性24 print(zlj.sex)# 男25 zlj.driver() # 调用类方法26 zlj.fly()# 调用类方法27 dcg = Person('董春光') # 实例化dcg28 print(dcg.hand) # 229 Person.hand = 10 # 修改类变量30 print(dcg.hand) # 1031 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): 2nationality = 'China' # 类变量,公共变量,每个实例都可以用 3def __init__(self):# 构造方法,类在实例化的时候自动执行的函数 4 self.name = 'niu' # 实例变量,必须实例化才能调用 5 print('init构造方法') 6def my(self): # 实例方法,必须实例化才能调用 7 self.sex = 'male' # 实例变量,必须实例化才能调用 8 print('self,实例方法') 9@staticmethod # 静态方法10def xh():# 静态方法括号里面不用写self11 # self.name # 报错,不能调用类中其他的实例变量12 # self.my() # 报错,不能调用类中其他的实例变量13 print('staticmethod')14@classmethod # 类方法,不用实例化就可以直接调用15def xm(cls): # cls代表的就是Baby类16 print('classmethod')17 print(cls.nationality) # 可以调用类变量18 # cls.name# 报错,不能调用类中其他的实例变量19 # cls.my()# 报错,不能调用勒种其他的实例方法20@property# 属性方法,直接返回函数执行结果21def AAA(self):22 return 9823 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(): 3def f1(self): 4 return 112 5def f2(self,name): # 必须有参数 6 print(name) 7def f3(self): 8 print('f3') 9per = 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并调用f215 del obj.per# 调用f3

6、继承

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

1 class Father(object): # 父类 2def __init__(self): 3 self.money = 1000000 4 self.house = '5环20套' 5def sing(self): 6 print('唱歌') 7def dance(self): 8 print('跳广场舞') 9def mf(self):10 print('找朋友')11 class Son(Father): # 继承类:将父类名写在括号里12def 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(): 2pass 3 4 class Dcg(): 5def smile(self): 6 print('喔喔喔') 7 8 class Lw(): 9def smile(self):10 print('啊啊啊')11 12 class Xz(Zll,Dcg,Lw): # 子类可以继承多个父类13def 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): # 新式类 2def x(self): 3 print('A') 4 class B(A): 5pass 6 class C(A): 7def x(self): 8 print('C') 9 class D(B,C):10pass11 12 S = D()13 S.x() # C14 # A作为B和C共同的父类时,是按D→B→C→A的顺序来找,遇到共同的父类时先不到父类中去找,先换到另外一个分支查找,找不到再到父类中去找

(2)A只作为B的父类

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

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

1 class A(object): # 新式类 2def __init__(self): 3 print('A.init') 4 class B(A): 5def __init__(self): 6 print('B.init') 7 A.__init__(self) 8def x(self): 9 print('x')10 self.y() # 根据继承关系从头开始找,先从C中找,再从B中找11def y(self):12 print('x--y')13 class C():14def y(self):15 print('y')16 class D(C,B):17pass18 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): # 父类 2def __init__(self, name): 3 self.name = name 4 class Dog(Animal):# 狗类,有叫的方法 5def cry(self): 6 print('狗 [%s] 汪汪汪' % self.name) 7 class Cat(Animal):# 猫类,有叫的方法 8def cry(self): 9 print('猫 [%s] 喵喵喵' % self.name)10 def cry(obj):# 定义一个函数,去调用传进来的实例的cry方法11obj.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: # 循环统一调用21cry(obj)

三、本类对象

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

1 class Baby: 2def __init__(self,name): 3 #name = name# 局部变量,出了函数就失效 4 self.name = name # 在类中self.name可以随便用了 5 print('self的内存地址', id(self)) 6def 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):2def __init__(self):# 构造函数,类在实例化的时候自动执行的函数3 self.name = '牛牛' # 实例变量,必须实例化才能调用4def 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): 2def __init__(self):# 构造函数,类在实例化的时候自动执行的函数 3 self.name = '牛牛' # 实例变量,必须实例化才能调用 4 self.my() # 在构造函数中调用一次my方法,实例化时会自动执行 5def 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): 2def __init__(self):# 构造函数,类在实例化的时候自动执行的函数 3 self.name = '牛牛' # 实例变量,必须实例化才能调用 4def 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): 3def __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 15def __del__(self): # 析构函数,实例被销毁的时候执行16 self.cur.close()17 self.conn.close()18 print('数据库连接关闭')19 20def 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.res28 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'# 私有类变量 4def __init__(self): 5 self.__host = '127.0.0.1' # 私有变量 6 self.port = 6379 7def __close(self): # 私有方法 8 print('私有方法') 9def open(self):10 print('实例方法')11 print(Redis.__table) # 类内部可以调用私有类变量12 self.__close() # 类内部可以调用私有方法13 return self.__host # 类内部可以调用私有变量14@staticmethod15def stac():16 return Redis.__table17 18 m = Redis()19 print(m.__host) # 报错,没有__host这个属性,私有变量出类后不能再使用20 m.__close()# 报错,没有这个方法,,私有方法出类后不能再使用21 m.__table # 报错,没有__table这个属性,私有变量出类后不能再使用22 print(m.port) # 打印出:637923 m.open() # 把私有方法放入实例方法中,通过调用实例方法可以拿到私有方法的返回值24 Redis.stac() # 通过静态方法还是可以拿到类的私有变量25 # 和实例方法一样,静态方法和类方法同样也可以是私有的,这里就不再举例26 # 存在继承关系的类中,子类不能调用父类的私有变量和私有方法,如果想访问需要在父类中定义一个共有的方法,然后把私有变量和方法放进去

例子:操作Redis数据库

1 # 封装redis操作类 2 import redis 3 class My(object): 4def __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 # 这时并不会去连redis14 # 所以捕捉不到数据库连接失败的异常,这里写的捕捉异常没有意义,可以不写15def __close(self): # 私有方法16 print('close')17 18def str_get(self,name): # str类型get19 res = self.r.get(name)20 if res:21 return res.decode()22 return None23 24def str_set(self,name,value,time=None): # str类型set25 self.r.set(name,value,time)26 27def str_delete(self,name):# str类型的删除key28 # res = self.r.get(name)29 res = self.r.exists(name) # 判断redis数据库是否存在name这个key30 if res:31 self.r.delete(name)32 print('删除成功')33 else:34 print('%s不存在'%name)35 36def hash_get(self,name,key): # hash类型获取单个key37 res = self.r.hget(name,key)38 if res:39 return res.decode()40 return None41 42def hash_set(self,name,key,value): # hash类型set43 self.r.hset(name,key,value)44 45def 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 dic52 return None53 54def hash_del(self,name,key): # 删除某个hash里面小key55 res = self.r.hget(name,key)56 if res:57 self.r.hdel(name,key)58 print('删除成功')59 else:60 print('%s不存在'%name)61 62def clean_redis(self): # 清理redis63 # 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()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。