添加对象或类的属性哪里(类__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中类的种类(继承需要): 在python2x版本中存在两种类.: ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写. ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。 python3x版本中只有一种类: python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object类。
__init__
方法,类中没有,从父类找,父类没有,从object
类中找。父类.func(对象,其他参数)
super().func(参数)
一个类继承多个类
c3
算法
MRO
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)
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
将一个类的函数定义成特性以后,对象再去使用的时候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
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: print('扣第一个人钱') ... print('给第二个人加钱') except ValueError: print('必须输入数字。。。') else: print('转账成功')
try: dic = {'name': '太白金星'} print(dic[1]) except KeyError: print('出现了keyError错误....') finally: print('正常执行')
try: dic = {'name': '太白金星'} print(dic[1]) except NameError: print('出现了NameError错误....') finally: print('异常发生之前,先执行我')
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 1 == 1 assert 1 == 2 # 应用: assert 条件 代码 代码 .......
# assert 条件 assert 1 == 1 assert 1 == 2 # 应用: assert 条件 代码 代码 .......
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句