10 Python 基础 面向对象编程
本节内容:
1、介绍
2、 面向对象的三大特性:构造方法、继承多继承、 多态
3、类成员、静态字段 、静态方法、类方法、 属性。
4、成员修饰符、特殊成员
5、异常处理 、反射、单例
一、介绍:
适用场景; 先按函数式编程。如果多个函数式编程中,有一些相同参数时,转换成面向对象编程面向对象编程是最有 效的软件编写方法之一,在面向象编写过程中 你编写表实现的中的事务和情景的类,并基于这些类创建对象。编写类时,你定义一大类对象都有用的通用行为,基于类创建对象时每个对象都自动具备这种通用行为,然后可根据需要赋予每个对象独特的个性。使用面向对象编程可模拟现实场景。
根据类来创建对象被称为实例化,这能够让你使用类的实例。
面向对象编程有助于你像程序员那样看世界,还可以帮助你真正明白自己编写的代码:不仅是各行代码的作用,还有代码背后更宏大的概念。
创建和使用类 class 关键字 叫类 后面跟得是类名 用驼峰体命名
# class 类名: # def 方法名(self,age) # print(age) # # 中间人 = 类名 #中间人 等于对象 对象也成为类,的实例(实例化) 后面还会讲单例 # 中间人.方法名(18) 这就执行了方法里的print(age)
class Wk(): #面向对象 后面跟得是类 def abc(self,age): #名字叫abc的方法 第一个参数必须是self print(age) return 1 mm = wk()#创建中间人 调用方法 因为不可以直接调用里面的方法 ret = mm.abc(18) #执行 print(ret) #也能查看返回值
#self:代指调用的方法 对象 (中间人) class Wk: def mm(self,age): print(self,age) nb = Wk() print(nb) nb.mm(11) nb2 = Wk() print(nb2) nb2.mm(666)
self 代指对象 对象就是中间人 永远是执行方法的调用者 在对象里面传值 就是封装 然后引出 init方法(构造方法)
class Wk: def mm(self,age): print(self,self.name,self.age,age) nb = Wk() nb.name = 'wangkuan' #把值放到nb对象里 就是封装 nb.age = 18 nb.mm(666) #传入最后那个age nb2 = Wk() nb2.name = 'yx' nb2.age = 18 nb2.mm(888)
二、面向对象编程
2.1构造方法
特殊作用:
在 nb = 类名() 内部做了两件事情 :1 创建对象
2 通过对象执行类中的一个特殊方法
__init__ 开头末尾各有两个下划线 这是一种约定,避免Python默认方法,与普通方法发生名称冲突。
class Bar:
def __init__(self): #self 就是 z
print('123')
z = Bar() #只要创建对象 后面加括号 Python就会自动执行 __init__ 方法
print(z)
利用init方法 给里面传值 调用 shou 执行__init__ 里的方法 输出 姓名 年龄 血型
class Jianjie: def __init__(self,name,age,): self.n = name self.a = age self.xue = 'o' def shou(self): print('%s-%s-%s' % (self.n, self.a,self.xue)) wk = Jianjie('王宽',18) wk.shou() wsh = Jianjie('王森浩',22) wsh.shou()
2.2继承:
就和现实中的一样继承父类,父亲有的可以继承,也可以不继承,比如父亲抽烟,儿子就不抽,怎么就不继承了 父亲的了,儿子重写,写成一样的,就用儿子 的,因为,先用自己的,自己的没有才找父亲的
官方 介绍:编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的 特殊版本 ,可以使用继承。 一个类继承另一个类时,它将自动获得另一个类的所有属性和方法:原有的类称为父类,而新类称为子类。子类继承的父类的所有属性和方法 ,同时还可以自己定义自己的属性和方法。
class Gramps: #爷爷 def 喝花酒(self):: pass class Father(Gramps): #父亲继承他爸 孩子他爷 def 抽烟(self): pass def 喝酒(self): pass def 烫头(self): pass class Son(Father): #儿子 继承父亲 def 保健(self): pass s = Son() s.保健() s.喝花酒() #都继承了就可以执行爷爷的了
class F: def w(self): print('w,w1') class Z(F): def k(self): print('k,k1') m = Z() m.w()
class F1: def a(self): print('f.a1') class F2(F1): def a(self): print('f.a2') class F3(F2): def a1(self): print('f.a3') class S1: def b1(self): print('s.b1') class S2(S1): def b2(self): print('s.b2')
继承 不用父级 的
class F: def w(self): print('w,w1') def w2(self): print('ss') class Z(F): def k(self): print('k,k1') def w2(self): #这就用自己的 print('qq') m = Z() m.w2()
介绍
class F: def w(self): print('w,w1') def w2(self): print('ss') class Z(F): def k(self): print('k,k1') def w2(self): print('qq') m = Z() m.k() # k 中的self是形参 代指m m.w() # self 用于指调方法的调用者
又想执行自己的又想执行父亲的
class F: def w(self): print('w,w1') def w2(self): print('ss') class Z(F): def k(self): print('k,k1') def w2(self): super(Z,self).w2() #执行父类中的w2方法 # F.w2(self) #两种方法 推荐用第一种 print('qq') m = Z() m.w2()
默认 多继承先从左开始 一条路走到黑
class F1: def a(self): print(111) class F2: def a(self): print(222) class C(F1,F2): #先从左开始 def w(self): print(3333) obj = C() obj.a()
假设一种现象 S2继承 S1 F3 都有一个共同的根 F 测试什么规律
结果就是 同一个根时 根最后执行
class F: def a(self): print('f.a1') class F2(F): #到了根这就不往上找了 往回找S1 如果S1没有 在找根 def a2(self): print('f.a2') class F3(F2): def a1(self): print('f.a3') class S1(F): def a(self): print('s.b1') class S2(F3,S1): #先从左侧开始找 def b(self): print(123) obj = S2() obj.a()
重点 self 是谁
class AAAAA: pass class BBBBB(AAAAA): def w(self): print(1111) self.m() #重点在这 m 88888 不执行,执行下面本身的 DDDDD 注意self 是本身的EEEEE E 下面本身有m def m(self): #不会先执行这的m 先回自己的EEEEEE找 左侧优先 执行DDDDD下的m print(88888) class CCCCC(BBBBB): def k(self): print(2222) class DDDDD: def m(self): print(666666) class EEEEE(DDDDD,BBBBB): def k(self): print(33333) obj = EEEEE() obj.w()
2.3多态
其他语言创建一个变量时候,要必须指定这个变量是什么类型的(强类型的)
Python >>> 原生多态
三、类成员 :字段、方法、属性
3.1字段 :普通字段、保存在对象中,执行只能通过对象访问。
self.name = name
class Foo(): def __init__(self,name): self.name = name obj = Foo('王宽') r = obj.name print(r)
3.1、静态字段:保存在类中,执行时 可以通过对象访问,也可以通过类访问
不占内存
class Gj: chaini = '中国' #静态字段 保存在类中 由类直接调用 类似全局变量 def __init__(self,name): self.name = name shanxi = Gj('山西') hebei = Gj('河北') print((Gj.chaini),(shanxi.name)) print((Gj.chaini),(hebei.name)) print(shanxi.name)
3.2方法
普通方法:保存在类中,由对象来调用 self =》 对象
class F: def bar(self): print('abc') obj = F() obj.bar()
3.2静态方法:保存在类中,由类直接直接调用 不用self 方法
#静态方法 class AA: @staticmethod #保存在类中 由类直接调用 不用self 方法 self 不用传值 def sat(): print('王宽') AA.sat()
3.2类方法:保存在类中,由类直接调用 cls=》当前类
#类方法 保存在类中 有类直接调用 class MM: @classmethod #保存在类中 由类直接调用 cls==》当前类 def kk(cls): #里面要写 cls cls 是类名 print('wangkuan') MM.kk()
3.3属性
特性:定义像是方法 通过字段的形式访问
class AA: @property #属性 特性 定义像是方法 通过字段的形式访问 def k(self): print(123) return 1 m = AA() r = m.k #如果是方法访问 就得加括号 print(r)
分页 好看 用属性 好看
class Pargination: def __init__(self,current_page): try: p = int(current_page) except Exception as e: p = 1 self.page = p @property # 把括号减了 为了好看 def start(self): val = (self.page-1)*10 return val @property def end(self): val = self.page*10 return val li = [] for i in range(1000): li.append(i) while True: p = input('请输入查看的页码:') obj = Pargination(p) print(li[obj.start:obj.end])
四、成员修饰符
私有成员:__字段名 无法直接访问,只能间接访问。
不能调用例子
class F: def __init__(self,name,age): self.n = name self.__a = age #私有成员 obj = F('王宽',18) print(obj.n) #obj.__a 私有成员外部不能访问
间接
# 内部调用方法 class F: def __init__(self,name,age): self.n = name self.__a = age #私有成员 def shou(self): #只有内部调用 return self.__a obj = F('王宽',18) print(obj.n) ret = obj.shou() print(ret)
静态字段 调用
class F: __v = 88888 #静态字段 def __init__(self): pass def shou(self): return self.__v obj = F() r = obj.shou() print(r)
静态方法 调用不用实例化对象,类 点 方法名 括号就行A.b() 方法前面加个装饰器
# #静态方法 调用 class F: __v = '88888' def __init__(self): pass @staticmethod def shou(): return F.__v F.shou()
普通方法 调用
class Foo: def __f1(self): #外面不能直接访问 return 123 def f2(self): r = self.__f1() return r obj = Foo() s = obj.f2() print(s)
不能访问父级里的私有成员
class F: def __init__(self): self.ge = 123 self.__gene = 123 #私有 外部无法直接访问 class S(F): def __init__(self,name): self.name = name self.__age = 21 #私有 外部无法直接访问 super(S,self).__init__() def show(self): print(self.name) print(self.__age) print(self.ge) # print(self.__gene) #不能访问父级里的 私有成员 obj = S('wangkuan') obj.show()
4.1特殊成员
__init__ 类() 自动执行类里面的__init__方法
__call__ 对象() 创建对象然后 对象.括号自动执行类里面的__call__ 类 ()()两括号 自动执行 init call 都执行
__int__ int(对象)
__str__ str() print时 对象的str()方法 获取返回
__iter__ 如果类中有__iter__方法 对象 >>>可迭代对象
对象、__iter__()的返回值:迭代器
for循环、迭代器 next
for循环,可迭代对象,对象.__iter__(),迭代器 ,next.
1、执行对象的类下 类中的__iner__方法,并获取其返回值
2、循环上一步返回的对象
class Foo: def __init__(self,name,age): self.name = name self.age = age def __getitem__(self, item): #特殊的方法支持索引 切片(slice类型)或者索引 return item + 10 def __setitem__(self, key, value): #赋值 key 是100 value 是'qweasd' print(key,value) def __delitem__(self, key): print(key) li = Foo('wangkuan',21) r = li[8]#自动执行li对象的类中的方法 __getitem__方法,8当作参数传递给item print(r) li[100] = 'qweasd' del li[999]
五、异常处理
Python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让Python不知所措的错误时,她都会创建一个异常对象。如果你编写了处理处理该异常的代码,程序将自动运行,如果你未对异常进行处理,程序将停止,并显示一个
traceback,其中包含有关异常的报告。
异常格式:
try:
#代码块 逻辑
except Exception as e:
#上述代码块如果出错 ,自动执行当前块内容
例子 让用户输入 数字 如果不是 自动执行 数字1 。
while True:
try:
inp = input('请输入序列:')
i = int(inp) #输入的不是整形 就异常处理
except Exception as e: #e是Exception 对象,对象中封装了错误信息;
#输入的不是数字就执行数字 1
# 执行当前块内容
print(e)
i = 1
print(i)
测试其他异常方法:
还有finally方法
#主要是为了测试 IndexError ValueError 这两个处理异常的方法
try:
li = [11,22,33]
li[999] #索引不了这个位置 下面IndexError 执行
# int('dfawfw') #转换不了出这个错误 下面 ValueError执行
except IndexError as e:
#如果是这种错误 执行这句 小弟搞 搞不了 老二搞
print('IndexError',e)
except ValueError as e:
#如果是这种错误 执行这句 老二搞不了 老大搞
print('ValueError',e)
except Exception as e:
所有错误都能用 老大搞定
print('Exception',e)
else:
#上面没出错才执行下面代码 如果出错了 执行上面异常处理 然后执行finally
print('else')
finally: #
#最后不管对不对 都执行
print('.....')
主动抛出异常
raise
try:
raise Exception ('不过了!!!') #主动触发异常
#Exception ('不过了!!!') Exception 加括号 相当于创建一个对象
就会把找这个对象赋值给 e e 就是这个错误的对象
except Exception as e:
print(e)
自定义异常
#自定义异常
class Abcd(Exception):
def __init__(self,msg):
self.message = msg
def __str__(self):
return self.message
try:
raise Abcd('我错了。。。')
except Abcd as e:
print(e) #e对象的__str__()方法,获取返回
断言 assert
#断言 #assert 后面跟条件 条件、成立通过,不成立、报错。简单的一个判断,可捕获,一般不捕获。 #用于用户强制服从,不服从就报错。 print(123) assert 1==1 #assert 1==2 不成立就报错 print(456)
六、反射:
通过字符串的形式操作对象中的成员
getattr 去什么里面获取什么内容
hasattr 是否有,去什么里面去检测有什么没有
setattr 主动设置一个值
delattr 删除
getattr 例子
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj = Foo('wangkuan',18)
#getattr() 去什么东西里面获取什么内容
#已经创建的对象 去obj获取name name是字符串形式
k = getattr(obj,'age')
print(k)
#可以直接输入 因为input 接受的就是字符串
inp = input(">>>")
r = getattr(obj,inp)
print(r)
也可以获取方法
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def shou(self):
return "%s-%s" %(self.name,self.age)
obj = Foo('wangkuan',18)
abc = getattr(obj,'shou') #abc 等于 shou了
print(abc)
r = abc()
print(r)
hasattr 例子
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj = Foo('wangkuan',18)
r = hasattr(obj,'name') 检测 obj 里是否有name 检测 是否有
print(r)
setattr 例子
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj = Foo('wangkuan',18)
#obj.k1 报错了就 得在下面创建了
setattr(obj,"k1","v1") # 主动设置一个值 k1 = v1
r = obj.k1
print(r)
delattr 例子
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
obj = Foo('wangkuan',18)
delattr(obj,'name') #把name删除
obj.name #执行报错
小的应用 模拟一个打开软件的功能 创建一个 s1 s2 让他们关联起来
s2
def f1():
return '微信'
def f2():
return '快手'
def f3():
return '抖音'
s1
import s2
inp = input('相看啥??f1 f2 f3')
if hasattr(s2,inp):
func = getattr(s2,inp)
result = func()
print(result)
else:
print('输的啥呀 别看了 真是')
七、单例 :就是单个实例,永远使用同一份实例(对象)
好处 内存里面对象只创建一次 永远用这一个 省内存
就打个比方 同一个网站有很多人访问 不能所有都去创建一个实例化 通过一个来实现
以后数据库 连接池的时候会用到 连接池只有一个 只创建一份 以后不管谁来 都用这一份
class Foo:
__v = None #单例 有值就还是一个储存地址
@classmethod
def get_instance(cls):
if cls.__v:
return cls.__v
else:
cls.__v = Foo()
return cls.__v
obj1 = Foo.get_instance()
#第一次执行 v等于空 执行slse 然后创建了一个对象 赋值给v 然后return回来了
# obj1 就等于你创建的那个对象
print(obj1)
obj2 = Foo.get_instance()#第二次执行 v以经有值了 执行if 还是之前那个对象 返回了
print(obj2)
obj3 = Foo.get_instance() #第三次也是一样的
print(obj3)
#他们三个实例是一模一样的 通过类方法和静态字段伪造出 我以后想要这个对象时候 我只创建一次 以后拿着它在来就行了
浙公网安备 33010602011771号