面向对象
一:面向对象初级
1.思考:首先在python中,以前我们以前用到的几乎都是函数式编程,但是有时候函数式编程其中代码重复利用率太高,我们往往会把这些重复代码写进一个函数日后去调用,所以呢,今天所将的面向对象将使我们学习到面向对象编程,面向对象对函数进行封装和分类,让开发变得更快更好,什么是面向对象?
Python中通过使用类(class)和对象(object)来实现面向对象(object-oriented programming,简称OOP
)的编程。 面向对象编程的最主要目的是提高程序的重复使用性,这和函数的目的相类似。
假设我养了一只小鸡,叫summer。它是个对象,属于鸟类。
2.举个简单的例子小明来说:
1 比如说我们要实现这个简单的功能 2 小明,10岁,男,喝酒 3 小明,10岁,男,吸烟 4 小明,10岁,男,游戏 5 6 老王,50岁,男,喝酒 7 老王,50岁,男,吸烟 8 老王,50岁,男,游戏 9 我们往往在使用函数式编程的时候回这样写 10 def foo(name,age,sex,content): 11 print(name,age,sex,cntent) 12 foo()这里面赋值就行
但是如果用面向对象去做该怎样,因此下面就来具体介绍一下面向对象
1 class bar: 2 def foo(self,name,age,sex,content): 3 print(name,age,sex,content) 4 obj = bar() 5 obj.foo(小明,10岁,男,喝酒) 6 obj.foo(小明,10岁,男,吸烟) 7 obj.foo(小明,10岁,男,游戏) 8 obj.foo(老王,10岁,男,喝酒) 9 obj.foo(老王,10岁,男,吸烟) 10 obj.foo(老王,10岁,男,游戏)
怎样就通过面向对象来实现了,但是你有可能觉得下面的代码还是很多,但是我们得从多个方面去考虑
3.
3.1 定义(以上面的例子为参考)
函数:
def *函数名(参数):
面向对象:
class * 名字是*(bar)的类 ,这里面第一个参数是self。必须有,是系统帮我们生成的
def =》名字叫foo的方法
3.2 执行 obj(object对象)
函数:
函数名(参数)
面向对象:
obj = bar() # 创建一个中间人 也就是对象
obj.foo()
来一个小程序感受一下,其实面向对象就是一个类和对象的结合
1 class s: #类名 2 def add(self,a,b,c): #函数 3 print(a+b+c) 4 return a 5 obj = s() #中间人,对象 6 obj.add(1,2,3) 7 ret = (obj.add(1,2,3)) 8 print(ret) 结果为: # 注意这里面最后又return 最后返回的就是return的值
6
6
1
还有也许有人对self不是太理解,其实他就是中间人也就是对象,来一个例子看一下
1 class bar: 2 def foo(self,arg): 3 print(self,arg) 4 obj = bar() 5 print(obj) 6 obj.foo(11111111111)
结果显示为:
<__main__.bar object at 0x00000015C1FEB8D0> <__main__.bar object at 0x00000015C1FEB8D0> 11111111111
你会发现self 和obj是一样的,self是调用方法的对象(中间人)
但是能不能再中间人里面存东西也就是self.name = "sang"这样行不行,其实 是可以的,上面的例子我们是通过中间人也就是对象先去访问类,我们也可以在对象中存东西,再去执行方法再看一个例子
1 class foo: 2 def aaa(self,arg): 3 print(self,self.name,self.age,self.sex,self.hobby,arg) 4 mid1 = foo() 5 mid1.name = "sang" 6 mid1.age = 20 7 mid1.sex = "male" 8 mid1.hobby = "book" 9 print(mid1.name) 10 mid1.aaa("you are good")
结果为:
sang <__main__.foo object at 0x0000008FE2BF24E0> sang 20 male book you are good
这里呢,再看上面小明的例子我们就可以这样写,就不会感觉代码很多了
1 class bar: 2 def foo(self,content): 3 print(self.name,self.age,self.sex,content) 4 obj = bar() 5 obj.name = "小明" 6 obj.age = 10 7 obj.sex = "男"
3.3 创建方法
构造方法,__init__(self,arg)(内部的)
obj = 类(“all”)
普通方法
obj = 类(“”)
obj.普通方法名()
来一个程序来看一下
class bar: def __init__(self): print("helo world") def foo(self): print("123") z = bar() print(z) z.foo()
结果为:
helo world <__main__.bar object at 0x0000002536D22358> 123
可以看出他先去进行内部的构造方法,再去执行z.foo(),它的特性就是只要类后面加上括号就自动执行,还可以在内部构造方法中加上参数
1 class Bar: 2 def __init__(self,n1,n2,n3,n4,n5,n6): 3 self.nam1=n1 4 self.nam2=n2 5 self.nam3=n3 6 self.nam4=n4 7 self.nam5=n5 8 self.nam6=n6 9 def foo(self): 10 print(self.nam1,self.nam2,self.nam3,self.nam4,self.nam5,self.nam6) 11 z = Bar(1,2,3,4,5,6) 12 print(z.nam1) 13 z.foo()
结果为:
1 1 2 3 4 5 6
此时在改进上面小明的例子
class bar: def __init__(self,n,a,s): self.name = n self.age = a self.sex = s def foo(self,content): print(self.name,self.age,self.sex,content) obj = bar("小明",10,"男")
这样是不是就更加简便了,这就是面向对象的特点
上面的可以看出我们通过person就把值封装到对象里面了,这就是构造封装因此下面引出面向对象的三大特性
3.4 面向对象的三大特性 : 封装,继承,多态
3.41 封装 :
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。所以,在使用面向对象的封装特性时,需要注意:
将内容封装到某处
从某处调用被封装的内容
来看例子来理解
1 class person: 2 def __init__(self,name,age): 3 self.n = name 4 self.a = age 5 def show(self): 6 print("%s-%s" %(self.n,self.a)) 7 zhangsan = person("张三",22) 8 zhangsan.show() 9 wangwu = person("王五",55) 10 wangwu.show()
结果为:
张三-22
王五-55
那么此时我们再来看一下到底什么时候用函数式编程啥时候用面向对象
适用场景:如果多个函数中有一些相同参数时,转换成面向对象
1 class DataBaseHelper: 2 def __init__(self, ip, port, username, pwd): 3 self.ip = ip 4 self.port = port 5 self.username = username 6 self.pwd = pwd 7 def add(self,content): 8 # 利用self中封装的用户名、密码等 链接数据 9 print('content') 10 # 关闭数据链接 11 def delete(self,content): 12 # 利用self中封装的用户名、密码等 链接数据 13 print('content') 14 # 关闭数据链接 15 def update(self,content): 16 # 利用self中封装的用户名、密码等 链接数据 17 print('content') 18 # 关闭数据链接 19 def get(self,content): 20 # 利用self中封装的用户名、密码等 链接数据 21 print('content') 22 # 关闭数据链接 23 s1 = DataBaseHelper('1.1.1.1',3306, 'alex', 'sb')
3.42 继承 :
继承,面向对象中的继承和现实生活中的继承相同,即:儿子可以继承父亲的内容。
来看一个例子
1 class father: #父类,基类 2 def f1(self): #fi()中的self时形参,代指obj,self是用于调用方法的调用者 3 print("f1.aaa") 4 def f2(self): 5 print("f2.vvv") 6 class son(father): #子类,派生类,他们的关系是一一对应的, 7 def f3(self): 8 print("f3.ccc") 9 def f2(self): #重写,防止继承父类中的方法 10 print("son.f2") #son中的f2表示不继承父类中f2,但是如果没有son中的f2,则表示全部继承父类中的,
不想继承就在son自己中定义一个
11 obj = son()
obj.f3()
obj.f1()
obj.f2()
结果为:
f3.ccc
f1.aaa
son.f2
同时呢,父亲还可以有一个父类,这时候son还可以继承父亲的父类,
但是如果我们既想执行自己得f2又想执行父类的f2该怎么办?
class father: def f1(self): print("f1.aaa") def f2(self): print("f2.vvv") class son(father): def f3(self): print("f3.ccc") def f2(self): print("son.f2") super(son,self).f2() #执行父类(基类)中的f2方法
father.f2(self) #父类名.父类中的方法(self) obj = son() obj.f3() obj.f1() obj.f2()
结果为:
f3.ccc
f1.aaa
son.f2
f2.vvv
f2.vvv
3.421 多继承 通俗来说就是说 有多个父类,
class F1(): def a1(self): print('F1.a') class F2(): def a1(self): print('F2.a') class S(F1,F2): pass obj = S() obj.a()
结果为:F1.a #哪个父类在前面就执行哪一个父类中的
但是如果F1没有戴氏有父类或者F2也有父类,该怎么找,来看例子
1 class Base: 2 def a(self): 3 print('Base.a') 4 class F0(Base): 5 def a1(self): 6 print('F0.a') 7 class F1(F0): 8 def a1(self): 9 print('F1.a') 10 class F2(Base): 11 def a1(self): 12 print('F2.a') 13 class S(F1,F2): 14 pass 15 obj = S() 16 obj.a()
结果为: Base.a 你会发现现在左边找,一直往上找,再找右边,但是如果F1和F2的共同的根中有,
F2中也有,它会先找F2,最后才去找根,
总结:
Python中支持多继承
a. 左侧优先
b. 一条道走到黑
c. 同一个根时,根最后执行
1 # class BaseHandler(): 2 # pass 3 # class RequestHandler(BaseHandler): 4 # def serve_forever(self): 5 # print("RequestHandler.serve_forever") 6 # self.process_request()#self 就是obj 7 # def process_request(self): 8 # print("RequestHandler.process_request") 9 # 10 # class Minx: 11 # def process_request(self): 12 #
print("RequestHandler.serve_forever")
13 # class son(Minx,RequestHandler): 14 # pass 15 # obj = son() 16 # obj.serve_forever()
结果为:
print("RequestHandler.serve_forever")
print("RequestHandler.serve_forever") 此时 ,obj是son的对象,它会返回到原点再从左开始找。
查看源码进行分析
1 import socketserver 2 obj = socketserver.ThreadingTCPServer(1,2)#创建对象,init 3 obj.serve_forever()
按住Ctrl ,点击单词就可以查看源码,还有一个快速定位,但是在使用快速定位前要先选中show members这一项
Ctrl r 可以修改一个程序中所有你想改的同一个单词
3.43 多态 ==》原生多态
打个比方来说python和Java
1 # Java 2 string v = 'alex' 3 def func(string arg): 4 print(arg) #在Java中是需要声明类型的 5 func('alex') 6 func(123) 7 8 # Python 9 v = 'alex' 10 def func(arg): 11 print(arg) 12 func(1) 13 func('alex')
二:面向对象中高级
类成员: # 字段 - 普通字段,保存在对象中,执行只能通过对象访问 - 静态字段,保存在类中, 执行 可以通过对象访问 也可以通过类访问 # 方法 - 普通方法,保存在类中,由对象来调用,self=》对象 - 静态方法,保存在类中,由类直接调用 - 类方法,保存在类中,由类直接调用,cls=》当前类 ######## 应用场景: 如果对象中需要保存一些值,执行某功能时,需要使用对象中的值 -> 普通方法 不需要任何对象中的值,静态方法 # 属性,特性 - 不伦不类
1.普通字段
1 class Foo: 2 def __init__(self, name): 3 # 普通字段 4 self.name = name 5 # 普通方法 6 def show(self): 7 print(self.name) 8 obj = Foo('alex') 9 obj.name #字段直接去调用 10 obj.show() #方法加上()才行
1.1静态字段
1 class province: 2 #静态字段属于类 3 country = "中国" 4 def __init__(self,name): 5 #普通字段,属于对象 6 self.name = name 7 # henan = province("河南") 8 # hebei = province("河北") 9 print(province.country) 10 henan = province("河南") 11 print(henan.name)
结果为:
alex
中国
河南
2.方法
1 class foo: 2 def bar(self): 3 print("you are good")#普通方法 4 @staticmethod#静态方法保存在类中,由类直接调用 5 def sta(): 6 print("123") 7 @staticmethod #静态装饰器 8 def stat(a1,a2): 9 print(a1,a2) 10 @classmethod 11 def classmd(cls): 12 #cls 是类名 13 print(cls) 14 print("classmd") 15 16 obj = foo() 17 obj.bar() 18 foo.sta() 19 foo.stat(2,3) 20 foo.classmd()
结果是:
you are good 123 2 3 <class '__main__.foo'> classmd
3.既能用方法又像用字段
1 class foo: 2 def __init__(self): 3 self.name = "a" 4 def bar(self): 5 print("bar") 6 @property 7 def perr(self0): 8 print("123") 9 return 1 10 11 #obj.per = 123 12 @perr.setter 13 def perr(self,val): 14 print(val) 15 @perr.deleter 16 def perr(self): 17 print(666) 18 obj = foo() 19 r = obj.perr 20 #print(r) 21 obj.perr = 123 22 del obj.perr
结果为: 其实他们就是一一对应的关系
123
123
666
3.1
1 class foo: 2 def f1(self): 3 return 123 4 per = property(fget=f1) 第一种 5 6 @property 7 def per(self): 8 return 123 第二种 其实这2种方法功能是一样的 9 obj = foo() 10 re = obj.per 11 obj.per 12 print(re)
所以呢,定义属性有2种方法,分别是装饰器和静态字段
per = property(fget = f1,fset = f2,fdel = f3,doc = "ajakjhs")
最多有三个参数,最后一个参数是介绍这个是干嘛的
3.3 我们在网上看新闻的时候 有时候有很多页,我们可以分页去查看,那么现在就做一个简单的小查看页码的程序