python 面向对象
面向对象
面向对象的三大特性
封装继承多态
面向对象定义
面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化。
类:就是具有相同属性和功能的一类事物。
对象:就是类的具体表现。
方法:定义在类里的函数,并且还带有self参数
实例变量:self.名字
实例化:对象是从类中出来的,只要是类名加上()
实例化一个对象总共发生了三件事:
1,在内存中开辟了一个对象空间。
2,自动执行类中的__init__方法,并将这个对象空间(内存地址)传给了__init__方法的第一个位置参数self。
3,在__init__ 方法中通过self给对象空间添加属性。
class Human:
mind = '有思想'
language = '使用语言'
def __init__(self,name,sex,age,hobby):
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
self.n = name
self.s = sex
self.a = age
self.h = hobby
obj = Human('barry','男',18,'运动')
五大基本原则:
1.单一职责原则
2.开放封闭原则
3.替换原则
4.依赖原则
5.接口分离原则
类的结构
class Human:
"""
此类主要是构建人类
"""
mind = '有思想' # 第一部分:静态属性 属性 静态变量 静态字段
dic = {}
l1 = []
def work(self): # 第二部分:方法 函数 动态属性
print('人类会工作')
class 是关键字与def用法相同,定义一个类。
Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。
类的结构从大方向来说就分为两部分:
静态变量。
动态方法。
python中一切皆对象,对象的类型就是类
变量名=xx数据类型对象
a = 10
b = 12.5
l = [1,2,3]
d = {'k':'v'}
o = 函数
q = 迭代器
u = 生成器
i = 类名
面向对象格式
class 类名:
def __init__(self,参数):
self.名字=参数 # 对象的属性/实例变量
对象=类名(参数)
#对象=类名()的过程 是通过类获取一个对象的过程 - 实例化
print(对象.__dict__)#属性查看
属性查看
print(alex.name) # print(alex.__dict__['name']) 属性的查看
属性的修改
alex.name = 'alexsb' # 属性的修改
print(alex.name)
属性的增加
alex.money = 1000000 # 属性的增加
print(alex.money)
属性的删除
del alex.money # 属性的删除
print(alex.__dict__)
封装
将一些 数据属性和方法封装起来,还可以取出来,就是封装
将你的数据放到列表里面也是封装,这是数据层面的
常用的代码段放到函数里面,这是语句层面封装
而类是一种更高级的封装,他可以将这两种封装在一起
广义:
把属性和方法装起来,外面不能直接调用了,要通过类的名字来调用
狭义:
把属性和方法藏起来,外面不能调用,只能在类的内部调用
class Human:
mind = '有思想'
language = '实用语言'
def __init__(self,name,sex,age,hobby):
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
self.n = name
self.s = sex
self.a = age
self.h = hobby
obj = Human('barry','男',18,'运动')
obj.job = 'IT' # 增
del obj.n # 删
obj.s = '女' # 改
print(obj.s) # 查
print(obj.__dict__)
c
类中的方法一般都是通过对象执行的(出去类方法,静态方法外),并且对象执行这些方法都会自动将对象空间传给方法中的第一个参数self.
##self 是什么?
self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self。所以咱们把类中的方法的第一个参数约定俗成设置成self, 代表这个就是对象。
## 继承
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
###继承优点
节省代码,增强耦合性,代码规范
###继承缺点
类的耦合性继承要少用
可读性差,拍错难,容易出现意料之外的错误
```python
# 继承语句
# class A:
# pass
# class B(A):
# pass
# B继承A,A是父类,B是子类
# A是父类 基类 超类
# B是子类 派生类
单继承
# 子类可以使用父类中的 : 方法 静态变量
class Animal:
def __init__(self,name):
self.name = name
def eat(self):
print('%s is eating'%self.name)
def drink(self):
print('%s is drinking'%self.name)
def sleep(self):
print('%s is sleeping'%self.name)
class Cat(Animal):
def climb_tree(self):
print('%s is climbing'%self.name)
class Dog(Animal):
def house_keep(self):
print('%s house keeping'%self.name)
小白 = Cat('小白')
# 先开辟空间,空间里有一个类指针-->指向Cat
# 调用init,对象在自己的空间中找init没找到,到Cat类中找init也没找到,
# 找父类Animal中的init
小白.eat()
小白.climb_tree()
小黑 = Dog('小黑')
小黑.eat()
# 当子类和父类的方法重名的时候,我们只使用子类的方法,而不会去调用父类的方法了
class Animal:
def __init__(self,name):
self.name = name
def eat(self):
print('%s is eating'%self.name)
def drink(self):
print('%s is drinking'%self.name)
def sleep(self):
print('%s is sleeping'%self.name)
class Cat(Animal):
def eat(self):
print('%s吃猫粮'%self.name)
def climb_tree(self):
print('%s is climbing'%self.name)
小白 = Cat('小白')
小白.eat()
# 子类想要调用父类的方法的同时还想执行自己的同名方法
# 猫和狗在调用eat的时候既调用自己的也调用父类的,
# 在子类的方法中调用父类的方法 :父类名.方法名(self)
class Animal:
def __init__(self,name,food):
self.name = name
self.food = food
self.blood = 100
self.waise = 100
def eat(self):
print('%s is eating %s'%(self.name,self.food))
def drink(self):
print('%s is drinking'%self.name)
def sleep(self):
print('%s is sleeping'%self.name)
class Cat(Animal):
def eat(self):
self.blood += 100
Animal.eat(self)
def climb_tree(self):
print('%s is climbing'%self.name)
self.drink()
class Dog(Animal):
def eat(self):
self.waise += 100
Animal.eat(self)
def house_keep(self):
print('%s is keeping the house'%self.name)
小白 = Cat('小白','猫粮')
小黑 = Dog('小黑','狗粮')
小白.eat()
小黑.eat()
print(小白.__dict__)
print(小黑.__dict__)
单继承总结
继承语法 class 子类名(父类名):pass
父类和子类方法的选择:
子类的对象,如果去调用方法
永远优先调用自己的
如果自己有 用自己的
自己没有 用父类的
如果自己有 还想用父类的 : 直接在子类方法中调父类的方法 父类名.方法名(self)
调子类的 : 子类自己有的时候
调父类的 : 子类自己没有的时候
调子类和父类的 :子类父类都有,在子类中调用父类的
#单继承
class D:
def func(self):
print('in D')
class C(D):pass
class A(C):
def func(self):
print('in A')
class B(A):pass
B().func()
多继承
多继承 有好几个爹
有一些语言不支持多继承 java
python语言的特点 : 可以在面向对象中支持多继承
1. python2.2之前:都是经典类
2. python2.2至python2.7之间存在两种类型:经典类,新式类
3. python3 只有新式类 默认继承 class A(object)
经典类:基类不继承object
遵循深度优先原则
深入的规则是从左至右,从左边一直找到最底层,在从最底层一层一层往回找
新式类:基类必须继承object
遵循mro算法,mro依赖于c3算法
# 多继承
class B:
def func(self):print('in B')
class A:
def func(self):print('in A')
class C(B,A):pass
C().func()
多继承总结
一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找
多态:
python:默认支持多态
同一个对象,多种形态,A=1 A=“ad”
一个类表现出多种形态,当你定义一个苹果支付类和微信支付类,他们同属于支付类,可以在支付类中定义双下方法属性
鸭子类型:
python中 你看起来像鸭子,你就是鸭子
A,B两个类,没有任何关系,独立两个,但是里面的功能相似,所以python一般会将类似于A,B两个类里面的相似功能让其命名相同
A,B虽然无关系,但是很默契的制定了一个规范,让你使用更方便
组合
组合
一个类的对象是另一个类对象的属性
两个类之间 有 什么有什么的关系 : 班级有学生 学生有班级 班级有课程 图书有作者 学生有成绩
# 组合
# 一个类的对象是另外一个类对象的属性
# 学生类
# 姓名 性别 年龄 学号 班级 手机号
# 班级信息
# 班级名字
# 开班时间
# 当前讲师
# class Student:
# def __init__(self,name,sex,age,number,clas,phone):
# self.name = name
# self.sex = sex
# self.age = age
# self.number = number
# self.clas = clas
# self.phone = phone
# class Clas:
# def __init__(self,cname,begint,teacher):
# self.cname = cname
# self.begint = begint
# self.teacher = teacher
# 查看的是大壮的班级的开班日期是多少
# 查看的是雪飞的班级的开班日期是多少
# py22 = Clas('python全栈22期','2019-4-26','小白')
# py23 = Clas('python全栈23期','2019-5-28','宝元')
# 大壮 = Student('大壮','male',18,27,py23,13812012012)
# 雪飞 = Student('雪飞','male',18,17,py22,13812012013)
# print(大壮.clas,py23)
# print(py23.begint)
# print(大壮.clas.begint)
# 练习 :
# 对象变成了一个属性
# 班级类
# 包含一个属性 - 课程
# 课程
# 课程名称
# 周期
# 价格
# 创建两个班级 linux57
# 创建两个班级 python22
# 查看linux57期的班级所学课程的价格
# 查看python22期的班级所学课程的周期
class Clas:
def __init__(self,course):
self.course=course
class Course:
def __init__(self,coursename,period ,pirce):
self.coursename=coursename
self.period=period
self.pirce=pirce
python=Clas("python22期")
linux=Clas("linux57期")
python22=Course("python","6个月",21800)
linux57=Course("linux","5个月",19800)
python.course=python22
linux.course=linux57
print(python.course.pirce)
类的约束:
类的约束是一个开发规范,约束他的所有子类必须实现和他同名的方法,不同名抛出错误
作用:
在重要的逻辑,与用户数据相关等核心部分,我们要进行约束,避免此类错误
第一种约束(常用):主动抛异常
#在父类中定义个pay方法,主动抛出异常,如果子类中没有定义pay方法,会寻找父类
#即会报错,python推荐的一种约束方式
class Payment: #主动报错
def pay(self,money): #约定俗称,定义一种规范,子类要定义pay方法
raise Exception('子类必须定义此方法')
class Alipay(Payment):
def pay(self,money):
print(f"利用支付宝支付了{money}")
class Wechatpay(Payment):
def fuqian(self,money):
print(f"利用微信支付了{money}")
#支付
def pay(obj,money):
obj.pay(money)
obj1 = Alipay() #调用支付宝支付
pay(obj1,100)
obj2 = Wechatpay() #调用微信支付
pay(obj2,200)
第二种约束:实例化对象时报错,严谨
#利用抽象类的概念:基类如上设置,子类如果没有定义pay方法,在实例化对象时报错
from abc import ABCMeta,abstractclassmethod
class Payment(metaclass=ABCMeta): #约束子类必须要有pay方法
@abstractclassmethod
def pay(self,money):
pass
class Alipay(Payment):
def pay(self,money):
print(f"利用支付宝支付了{money}")
class Wechatpay(Payment):
def fuqian(self,money):
print(f"利用微信支付了{money}")
#支付
def pay(obj,money):
obj.pay(money)
obj1 = Alipay()
obj2 = Wechatpay() #调用微信
pay(obj1,100)
pay(obj2,200)xxxxxxxxxx class Human: mind = '有思想' language = '使用语言' def __init__(self,name,sex,age,hobby): # self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。 self.n = name self.s = sex self.a = age self.h = hobbyobj = Human('barry','男',18,'运动')
反射:
通过字符串形式,反射类中的属性和方法
反射的五个函数:
hasattr(obj,"字符串") #判断字符串是否存在类中
getattr(obj,"字符串") #进行反射调用字符串(属性或者方法)
setattr(obj,"字符串") #添加属性
delattr(obj,"字符串") #删除属性
callable() 函数用于检查一个对象是否是可调用的。如果返回 True,object 仍然可能调用失败;但如果返回 False,调用对象 object 绝对不会成功。
实例角度反射:
class A:
static_field = "静态属性"
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print("in A func")
obj = A("海洋",18)
if hasattr(obj,"static_field"): #判断boj对象是否有static_field
print(getattr(obj,"static_field"))
if hasattr(obj,"func"): #判断hasttr是否有函数
getattr(obj,"func")() #执行对象内的方法
# print(getattr(obj,"name",None)) #没有属性,可以自定义设置返回值
# setattr(obj,"hobby",'台球') #* 添加一个属性
# print(getattr(obj,"hobby"))
#
# delattr(obj,"hobby") #* 删除一个属性
# print(getattr(obj,"hobby"))
类的角度反射:
class A:
static_field = "静态属性"
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print(self)
print(self.name)
print("in A func")
# print(hasattr(A,"static_field"))
# print(getattr(A,"static_field"))
obj = A("海洋",18)
getattr(A,"func")(obj)
脚本角度:
def func1():
print("in func1")
def func2():
print("in func2")
def func3():
print("in func3")
class B:
static = "B类"
import sys
this_moudles = sys.modules[__name__] #将__name__加入modules,获取当前脚本对象
getattr(this_moudles,"func1")() #调用函数
cls = getattr(this_moudles,"B") #获取到B,在进行实例化,调用
obj = cls()
print(obj.static)
类的反射:
import sys
class Auth:
function_list = [("login","请登录"), ("register","请注册"),("exit","退出")]
def login(self):
print("登录函数")
def register(self):
print("注册函数")
def exit(self):
print("退出函数")
while 1:
obj = Auth()
for num,option in enumerate(obj.function_list,1):
print(num,option[1])
func_name = int(input("请输入选择:").strip())
if hasattr(obj,obj.function_list[func_name-1][0]):
getattr(obj,obj.function_list[func_name-1][0])()
文件的例子
class File:
lst = [('读文件','read'), ('写文件','write'),
('删除文件','remove'),( '文件重命名','rename'),
('复制','copy'),('移动文件','move')]
def __init__(self,filepath):
self.filepath = filepath
def write(self):
print('in write func')
def read(self):
print('in read func')
def remove(self):
print('in remove func')
def rename(self):
print('in rename func')
def copy(self):
print('in copy func')
def move(self):
print('in 移动文件 func')
f = File('ashkgkfj')
while True:
for index,opt in enumerate(File.lst,1):
print(index,opt[0])
num = int(input('请输入您要做的操作序号>>'))
if hasattr(f,File.lst[num-1][1]):
getattr(f,File.lst[num-1][1])()
单例模式:
一个类只能实例化一个对象,无论你实例化多少次,内存中都只有一个对象,节省内存
主要是实例化对象,执行类中的方法
#单例模式:(面试必考)
#一个类只能实例化一个对象,无论你实例化多少次,内存中都只有一个对象,节省内存
#这个类的对象不是个性化的,主要是实例化对象之后去执行类中的方法
class A:
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance: #如果为反的话
obj1 = object.__new__(cls) #调用object __new__方法封装类名
cls.__instance = obj1 #object1对象
return obj1
else:
return cls.__instance
obj = A()
obj1 = A()
print(obj,obj1)
#传参示例:
class Baby:
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = object.__new__(cls) #object=super,找父类__new__ object类中的new可以创建空间 Baby = cls
return cls.__instance
def __init__(self,cloth,pants): #self = b1
self.cloth = cloth
self.pants = pants
b1 = Baby('黑衣服','黑裤子')
b2 = Baby('白衣服','白裤子')
print(b1.__dict__)
print(b2.__dict__)
经典类,新式类
只要继承object类就是新式类
不继承object类的都是经典类
python3 所有的类都继承object类,都是新式类
在py2中 不继承object的类都是经典类
继承object类的就是新式类了
在py3中不存在经典类 ,在py2中不主动继承object的类
单继承
在单继承方面(无论是新式类还是经典类都是一样的)
class A:
def func(self):pass
class B(A):
def func(self):pass
class C(B):
def func(self):pass
class D(C):
def func(self):pass
d = D()
寻找某一个方法的顺序:D->C->B->A
越往父类走,是深度
多继承
# 多继承
class A:
def func(self):
print('A')
class B(A):
pass
# def func(self):
# print('B')
class C(A):
pass
# def func(self):
# print('C')
class D(B,C):
pass
# def func(self):
# print('D')
print(D.mro()) # 只在新式类中有,经典类没有的
广度优先,深度优先
在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,再走深度,广度优先
在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了
C3算法
A(O) = [AO]
B(A) = [BAO]
C(A) = [CAO]
D(B) = [DBAO]
E(C) = [ECAO]
F(D,E) = merge(D(B) + E(C))
= [F] + [DBAO] + [ECAO]
F = [DBAO] + [ECAO]
FD = [BAO] + [ECAO]
FDB = [AO] + [ECAO]
FDBE = [AO] + [CAO]
FDBEC= [AO] + [AO]
FDBECA= [O] + [O]
FDBECAO
# 算法的内容
# 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序
# 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,...
# merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序中的一个
# 或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中的一个
# 如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类
总结(经典类,新型类)
经典类 - 深度优先 新式类 - 广度优先
深度优先要会看,自己能搞出顺序来
广度优先遵循C3算法,要会用mro,会查看顺序
经典类没有mro,但新式类有
super
在py3中怎么用?在py2(新式类/经典类)中怎么用?
在单继承中执行父类的同名方法的时候怎么用?
super方法和mro方法的关系是什么?
class A(object):
def func(self):
print('A')
class B(A):
def func(self):
super().func()
print('B')
class C(A):
def func(self):
super().func()
print('C')
class D(B,C):
def func(self):
super().func()
super(D,self).func()
print('D')
D().func()
# A,C,B,A,C,B,D
# super是按照mro顺序来寻找当前类的下一个类
# 在py3中不需要传参数,自动就帮我们寻找当前类的mro顺序的下一个类中的同名方法
# 在py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象).函数名()
# 这样才能够帮我们调用到这个子类的mro顺序的下一个类中的方法
# 在py2的经典类中,并不支持使用super来找下一个类
# 在D类中找super的func,那么可以这样写 super().func()
# 也可以这样写 super(D,self).func() (并且在py2的新式类中必须这样写)
# 在单继承的程序中,super就是找父类
class User:
def __init__(self,name):
self.name = name
class VIPUser(User):
def __init__(self,name,level,strat_date,end_date):
# User.__init__(self,name)
super().__init__(name) # 推荐的
# super(VIPUser,self).__init__(name)
self.level = level
self.strat_date = strat_date
self.end_date = end_date
太白 = VIPUser('太白',6,'2019-01-01','2020-01-01')
print(太白.__dict__)
细分类的组成成员
每个区域详细划分又可以分为:
class A:
company_name = '老男孩教育' # 静态变量(静态字段)
__iphone = '1353333xxxx' # 私有静态变量(私有静态字段)
def __init__(self,name,age): #特殊方法
self.name = name #对象属性(普通字段)
self.__age = age # 私有对象属性(私有普通字段)
def func1(self): # 普通方法
pass
def __func(self): #私有方法
print(666)
@classmethod # 类方法
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法')
@staticmethod #静态方法
def static_func():
""" 定义静态方法 ,无默认参数"""
print('静态方法')
@property # 属性
def prop(self):
pass
类的私有成员
对于每一个类的成员而言都有两种形式:
公有成员,在任何地方都能访问
私有成员,只有在类的内部才能方法
私有成员和公有成员的访问限制不同:
静态字段(静态属性)
公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
私有静态字段:仅类内部可以访问;
class C:
name = "公有静态字段"
def func(self):
print C.name
class D(C):
def show(self):
print C.name
C.name # 类访问
obj = C()
obj.func() # 类内部可以访问
obj_son = D()
obj_son.show() # 派生类中可以访问
公有静态字段
class C:
__name = "私有静态字段"
def func(self):
print C.__name
class D(C):
def show(self):
print C.__name
C.__name # 不可在外部访问
obj = C()
obj.__name # 不可在外部访问
obj.func() # 类内部可以访问
obj_son = D()
obj_son.show() #不可在派生类中可以访问
私有静态字段
普通字段(对象属性)
公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
私有普通字段:仅类内部可以访问;
参考博客
https://www.cnblogs.com/jin-xin/articles/10311392.html
类中的三个装饰器(内置函数)
主要就是类方法:
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
实例方法
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。
类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:实例对象和类对象都可以调用。
静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用。
类方法
使用装饰器@classmethod
原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方法。
class Goods:
__discount = 0.8
def __init__(self):
self.__price = 5
self.price = self.__price * self.__discount
@classmethod # 把一个对象绑定的方法 修改成一个 类方法
def change_discount(cls,new_discount):
cls.__discount = new_discount
@classmethod # 把一个对象绑定的方法 修改成一个 类方法
第一,在方法中仍然可以引用类中的静态变量
第二,可以不用实例化对象,就直接用类名在外部调用这个方法
什么时候用@classmethod?
1.定义了一个方法,默认传self,但这个self没被使用
2.并且你在这个方法里用到了当前的类名,或者你准备使用这个类的内存空间中的名字的时候
Goods.change_discount(0.6) # 类方法可以通过类名调用
apple = Goods()
print(apple.price)
apple.change_discount(0.5) # 类方法可以通过对象名调用
apple2 = Goods()
print(apple2.price)
查看时间
# import time
# class Date:
# def __init__(self,year,month,day):
# self.year = year
# self.month = month
# self.day = day
# @classmethod
# def today(cls):
# struct_t = time.localtime()
# date = cls(struct_t.tm_year,struct_t.tm_mon,struct_t.tm_mday)
# return date
#
# date对象 = Date.today()
# print(date对象.year)
# print(date对象.month)
# print(date对象.day)
静态方法
使用装饰器@staticmethod。
帮助我们把一个普通的函数挪到类中来直接使用,制造静态方法用的
静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护
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
property 是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
@property 把一个方法伪装成属性,使它调用的时候不用加括号
class Goods:
discount = 0.8
def __init__(self,name,origin_price):
self.name = name
self.__price = origin_price
@property
def price(self):
return self.__price * self.discount
@price.setter
def price(self,new_value):
if isinstance(new_value,int):
self.__price = new_value
apple = Goods('apple',5)
print(apple.price) # 调用的是被@property装饰的price
apple.price = 10 # 调用的是被setter装饰的price
print(apple.price)
class Goods:
discount = 0.8
def __init__(self,name,origin_price):
self.name = name
self.__price = origin_price
@property
def price(self):
return self.__price * self.discount
@price.setter
def price(self,new_value):
if isinstance(new_value,int):
self.__price = new_value
@price.deleter
def price(self):
del self.__price
apple = Goods('apple',5)
print(apple.price)
apple.price = 'ashkaksk'
del apple.price # 并不能真的删除什么,只是调用对应的被@price.deleter装饰的方法而已
print(apple.price)
内置的魔术方法
new :单列
# 实例化的时候
# 先创建一块对象的空间,有一个指针能指向类 --> __new__
# 调用init --> __init__
# 设计模式 -- 单例模式
# 一个类 从头到尾 只会创建一次self的空间
# class Baby:
# __instance = None
# def __new__(cls, *args, **kwargs): # 构造方法
# if cls.__instance is None:
# cls.__instance = super().__new__(cls)
# return cls.__instance
# def __init__(self,cloth,pants):
# self.cloth = cloth
# self.pants = pants
# b1 = Baby('红毛衣','绿皮裤')
# print(b1.cloth)
# b2 = Baby('白衬衫','黑豹纹')
# print(b1.cloth)
# print(b2.cloth)
双下方法:
双下方法触发条件:
__new__: 在实例化时候触发,触发优先级比__init__高,单例模式使用
__len__: len(obj) len对象时候触发
__str__: str(obj)或者格式化输入时候触发
__call__: 实例化对象后触发,call优先级比__init__方法低
__new__方法:
#开辟一个空间
class A:
def __init__(self):
print("in init")
def __new__(cls, *args, **kwargs): #cls = A类名
print("in new")
object1 = object.__new__(cls) #2.利用object类的new产生一个空间
return object1 #3.将这个对象空间返回给A()
obj = A() #1.先触发__new__并且将类名自动传给cls
__len__方法:
#一个对象值所以可以使用len函数,是这个对象从属于类中有__len__方法
class A:
def __init__(self,name,age,hobby):
self.name = name
self.age = age
self.hobby = hobby
def __len__(self):
print("执行了__len__方法")
return len(self.__dict__)
obj = A("海洋",18,"台球")
ret = len(obj) #触发A类中的__len__方法,ret返回10
print(ret)
__str__方法:
class Student:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __str__(self):
return f"{self.name}{self.age}{self.sex}" #str优先级高
# def __repr__(self): #跟str双下方法一样
# return f"{self.name}{self.age}{self.sex}"
obj = Student("海洋",18,"男")
obj1 = Student("俊丽",18,"女")
# # print(str(obj)) #会触发
# print(obj) #打印一个实例就会触发__str__
# print(obj1)
print(f"此对象为{obj}") #格式化输出也会触发
__call__方法:
# 对象call ,类加()触发
class A:
def __init__(self):
self.a = 1
print(111)
def __call__(self, *args, **kwargs):
print(222)
obj = A() #实例化触发
obj()
__enter__和__exit__方法:
#对一个对象类似于进行with语句上下文管理,必须要在类当中定义__enter__和__exit__
class A:
def __init__(self,text):
self.text = text
def __enter__(self):
self.text = self.text + "您来了" #1
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.text = self.text + "这就走了" #
with A("大爷") as f1: #2
print(f1.text)
print(f1.text) #4
#__eq__ 对象比较是触发
#__del__ 析构方法,手动垃圾挥手
#__item__ 对一个对象,执行字典的操作,执行item
#__iter__ 将一个对象设置成一个可迭代对象,for循环取值或者list
异常处理:(try)
一旦程序出现异常,异常处理会及时捕捉你的错误,不至于使你的程序崩溃
异常处理不能经常使用:耗费性能,有些错误是需要分流使用的,代码的可读性变差
关键的节点时候使用
单分支:
try:
l1 = [1,2,3,4,5]
print(l1[6])
except IndexError as e: #当索引报错后,后面的就不会再走了
print("索引错误")
print(111)
多分支和分流:
try:
l1 = [1,2,3,4,5]
print(l1[6])
dic = {1:2,'a':'b'}
print(dic[3])
num = input("请输入序号:")
int(num)
except IndexError as e: #当索引报错后,后面的就不会再走了
print("索引错误")
except KeyError as e:
print('没有此键')
except ValueError as e:
print("转化错误")
print(111)
#程序分流
dic = {
1:666,
2:333,
3:555
}
while 1:
try:
num = input("请输入序号:")
int(num)
print(dic[int(num)])
except KeyError as e:
print(f'选项超出范围,请重新输入{e}') #e是将错误打印出来
except ValueError as e:
print(f"请输入数字{e}")
万能异常:
# 万能异常
# 什么时候使用万能异常,什么时候使用多分支?
# 如果你只是想把整个异常全部处理掉,让程序继续执行,就用万能异常
# 如果出现了异常,你是想根据不同的异常执行不同的逻辑流程,你要采取多分支
dic = {
1:666,
2:333,
3:555
}
try:
num = input("请输入序号:")
int(num)
print(dic[int(num)])
except Exception as e: #代表所有错误,全部捕获
print(e)
print(111)
万能异常加分流:
dic = {
1:666,
2:333,
3:555
}
while 1:
try:
num = input("请输入序号:")
int(num)
print(dic[int(num)])
except KeyError as e:
print('选项超出范围,请重新输入')
except ValueError as e:
print("请输入数字")
except Exception: #以上异常没有pass掉
pass
异常处理其他成员:无异常时候执行
dic = {
1:666,
2:333,
3:555
}
try:
num = input("请输入序号:")
int(num)
print(dic[int(num)])
except KeyError as e:
print("选项超出范围,重新输入")
except Exception:
pass
else: #以上无异常执行else语句,否则不执行else语句
print(666)
finally:在出现错误前执行此语句
#使用场景,文件读写,数据库连接
try:
int("a")
finally: #finally: 在出错误前执行此语句
print(777)
def func(): #函数结束前执行finally
try:
a = 1
b = 2
return a + b
finally:
print(666)
print(func())
raise/assert:主动抛出异常
raise Exception("主动抛出异常")
assert #断言:可以添加条件加判断
assert 1 == 2
print(11)
自定义异常(了解)
class Connection(BaseException):
def __init__(self,msg):
self.msg=msg
raise Connection("触发了连接异常")