添加对象或类的属性哪里(类__init__方法中、类方法中、类外)都可以添加。
class A: def __init__(self,name): self.name = name def func(self,sex): self.sex = sex # 类外面可以: obj = A('barry') obj.age = 18 print(obj.__dict__) # {'name': 'barry', 'age': 18} # 类内部也可以: obj = A('barry') # __init__方法可以。 obj.func('男') # func 方法也可以。 对象以及类查询"名字"的顺序对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->…
类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> …
上面的顺序都是单向不可逆,类名不可能找到对象的属性。
类与类之间的关系 依赖关系将一个类的对象或者类名传到另一个类的方法使用. 这种关系比较弱。
组合(关联、聚合)关系关联关系, 其实就是 我需要你. 你也属于我
组合:将一个类的对象封装到另一个类的对象的属性中,就叫组合。
继承继承分为单继承和多继承
python中类的分类这里需要补充一下python中类的种类(继承需要): 在python2x版本中存在两种类.: ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写. ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。 python3x版本中只有一种类: python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object类。
单继承类名.对象执行父类方法执行顺序 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。同时执行类以及父类方法 子类方法中父类.func(对象,其他参数)super().func(参数) 多继承一个类继承多个类
经典类 沿用深度优先算法 从左至右,依次查找。每次都选取节点的最左边,一直找到头,如果没有,返回上一个节点在查询其他路线。如果上一个节点没有其他路线或者都已经查询完毕,再返回上一个节点,直至遍历完所有的节点 新式类 沿用c3算法 MRO super() 示例一class A: def f1(self): print('in A f1') def f2(self): print('in A f2') class Foo(A): def f1(self): super().f2() print('in A Foo') obj = Foo() obj.f1() 示例二 class A: def f1(self): print('in A') class Foo(A): def f1(self): super().f1() print('in Foo') class Bar(A): def f1(self): print('in Bar') class Info(Foo,Bar): def f1(self): super().f1() print('in Info f1') obj = Info() obj.f1() ''' in Bar in Foo in Info f1 ''' print(Info.mro()) # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>] 示例三 class A: def f1(self): print('in A') class Foo(A): def f1(self): super().f1() print('in Foo') class Bar(A): def f1(self): print('in Bar') class Info(Foo,Bar): def f1(self): super(Foo,self).f1() print('in Info f1') obj = Info() obj.f1() 封装将属性写到__init__中
多态同样名称的方法在不同的子类中会有不同的行为。
同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = “太白”, 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态。
对类的约束提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.方式一:class Payment: """ 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。 """ def pay(self,money): raise Exception("你没有实现pay方法") class QQpay(Payment): def pay(self,money): print('使用qq支付%s元' % money) class Alipay(Payment): def pay(self,money): print('使用阿里支付%s元' % money) class Wechatpay(Payment): def fuqian(self,money): print('使用微信支付%s元' % money) def pay(obj,money): obj.pay(money) a = Alipay() b = QQpay() c = Wechatpay() pay(a,100) pay(b,200) pay(c,300)方式二:引入抽象类的概念from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类 @abstractmethod def pay(self):pass # 抽象方法 class Alipay(Payment): def pay(self,money): print('使用支付宝支付了%s元'%money) class QQpay(Payment): def pay(self,money): print('使用qq支付了%s元'%money) class Wechatpay(Payment): # def pay(self,money): # print('使用微信支付了%s元'%money) def recharge(self):pass def pay(a,money): a.pay(money) a = Alipay() a.pay(100) pay(a,100) # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能 q = QQpay() q.pay(100) pay(q,100) w = Wechatpay() pay(w,100) # 到用的时候才会报错抽象类和接口类做的事情 :建立规范,只要子类继承了我写的这个抽象类,实例化对象时就会报错。
类的私有成员对于每一个类的成员而言都有两种形式:
公有成员,在任何地方都能访问私有成员,只有在类的内部才能方法类
类
类内部
派生类
公有类的静态属性
可以访问
可以访问
可以访问
公有方法
可以访问
可以访问
可以访问
私有类的静态属性
不可以访问
可以访问
不可以访问
私有方法
不可以访问
可以访问
不可以访问
对象属性
对象
类内部
派生类
公有对象属性
可以访问
可以访问
可以访问
私有对象属性
不可以访问
可以访问
不可以访问
对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用.
类的其他成员 类方法使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:实例对象和类对象都可以调用。
class Student: __num = 0 def __init__(self,name,age): self.name = name self.age= age Student.addNum() # 写在__new__方法中比较合适,但是现在还没有学,暂且放到这里 @classmethod def addNum(cls): cls.__num += 1 @classmethod def getNum(cls): return cls.__num a = Student('太白金星', 18) b = Student('barry', 18) print(Student.getNum()) 静态方法定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用。
静态方法是类中的函数,不需要实例化。可以理解为,静态方法是个独立的、单纯的函数,仅仅托管于某个类的名称空间中,便于使用和维护。
import time class TimeTest(object): def __init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second @staticmethod def showTime(): return time.strftime("%H:%M:%S", time.localtime()) print(TimeTest.showTime()) t = TimeTest(2, 10, 10) nowTime = t.showTime() print(nowTime) 属性 propertyproperty是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
class Foo: @property def AAA(self): print('get的时候运行我啊') @AAA.setter def AAA(self,value): print('set的时候运行我啊') @AAA.deleter def AAA(self): print('delete的时候运行我啊') #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA #或者: class Foo: def get_AAA(self): print('get的时候运行我啊') def set_AAA(self,value): print('set的时候运行我啊') def delete_AAA(self): print('delete的时候运行我啊') AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA isinstance isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象 class A: pass class B(A): pass obj = B() print(isinstance(obj,B)) print(isinstance(obj,A)) isinstance issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类 class A: pass class B(A): pass class C(B): pass print(issubclass(B,A)) print(issubclass(C,A)) issubclass 反射python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
Python实现自省的函数hasattr、getattr、setattr、delattr
应用于对象的反射class Foo: f = '类的静态变量' def __init__(self,name,age): self.name=name self.age=age def say_hi(self): print('hi,%s'%self.name) obj=Foo('egon',73) #检测是否含有某属性 print(hasattr(obj,'name')) print(hasattr(obj,'say_hi')) #获取属性 n=getattr(obj,'name') print(n) func=getattr(obj,'say_hi') func() print(getattr(obj,'aaaaaaaa','不存在啊')) #报错 #设置属性 setattr(obj,'sb',True) setattr(obj,'show_name',lambda self:self.name+'sb') print(obj.__dict__) print(obj.show_name(obj)) #删除属性 delattr(obj,'age') delattr(obj,'show_name') delattr(obj,'show_name111')#不存在,则报错 print(obj.__dict__) 应用于类的反射与对象基本相同
反射的作用更优雅的写代码?
class User: def login(self): print('欢迎来到登录页面') def register(self): print('欢迎来到注册页面') def save(self): print('欢迎来到存储页面') user = User() while 1: choose = input('>>>').strip() if hasattr(user,choose): #如果user存在choose这个属性 func = getattr(user,choose)#取这个属性并赋值给func变量 func()#执行 else: print('输入错误。。。。') 异常处理AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
基本语法:
try: 被检测的代码块 except 异常类型: try中一旦检测到异常,就执行这个位置的逻辑多分支+万能异常
dic = { 1: login, 2: register, 3: dariy, 4: article, 5: comment, } print(''' 欢迎访问博客园系统: 1,登录 2,注册 3,访问日记页面 4,访问文章页面 5,访问评论页面 ''') try: choice = int(input('请输入:')) dic[choice]() # if choice.isdigit(): # if # # else: # print('请输入数字...') except ValueError: print('请输入数字....') except KeyError: print('您输入的选项超出范围...') except Exception as e: print(e) try…except…else组合 与循环中的else比较类似,try代码中,只要出现了异常,则不会执行else语句,如果不出现异常,则执行else语句。 比如我们完成一个转账功能的代码,需要一个转账给另一个人,然后另一个人确认收到才算是转账成功,我们用伪代码写一下,他就可以用在这个地方: # 伪代码 try: print('扣第一个人钱') ... print('给第二个人加钱') except ValueError: print('必须输入数字。。。') else: print('转账成功') Try…excet…finally组合 finally这个用法比较有意思,他是在捕获异常发生之前,先执行finally的代码,有点未卜先知的意思。 如果出现异常并且成功捕获了,finally会在try中最后执行。 try: dic = {'name': '太白金星'} print(dic[1]) except KeyError: print('出现了keyError错误....') finally: print('正常执行') 如果出现异常但是没有成功捕获,finally会在异常发生之前执行。try: dic = {'name': '太白金星'} print(dic[1]) except NameError: print('出现了NameError错误....') finally: print('异常发生之前,先执行我') finally用在哪里呢? 关闭文件的链接链接,数据等链接时,需要用到finally。f = open('file',encoding='utf-8') try: '''各种操作''' print(f.read()) '''但是发生错误了, 此时没关闭文件句柄,所以''' finally: f.close()函数中,finally也会在return之前先执行。 def func(): try: return 1 finally: print('finally') func()循环中,finally也会在return之前执行。 while 1: try: break finally: print('finally')一般就是收尾工作,在一些重要环节出错之前必须一定要做的比如关闭链接的问题时,最好是用上finally作为最后一道防线,收尾。
主动出发异常 在类的约束中,我们已经用过此方法,主动发出异常raise TypeError('类型错误') 断言 表示一种强硬的态度,只要assert后面的代码不成立,直接报错,下面的代码就不让你执行。# assert 条件 assert 1 == 1 assert 1 == 2 # 应用: assert 条件 代码 代码 ....... 自定义异常 python中给你提供的一些错误类型并不是所有的,只是常见的异常,如果以后你在工作中,出现了某种异常无法用已知的错误类型捕获(万能异常只能捕获python中存在的异常),那么你就可以尝试自定义异常,只要继承BaseException类即可。# assert 条件 assert 1 == 1 assert 1 == 2 # 应用: assert 条件 代码 代码 ....... 异常处理正确的使用方式 有的同学会这么想,学完了异常处理后,好强大,我要为我的每一段程序都加上try…except,干毛线去思考它会不会有逻辑错误啊,这样就很好啊,多省脑细胞===》2B青年欢乐多 try…except应该尽量少用,因为它本身就是你附加给你的程序的一种异常处理的逻辑,与你的主要的工作是没有关系的 这种东西加的多了,会导致你的代码可读性变差,只有在有些异常无法预知的情况下,才应该加上try…except,其他的逻辑错误应该尽量修正 ---来自腾讯云社区的---Dreamy.TZK
微信扫一扫打赏
支付宝扫一扫打赏