什么叫做面向对象?
所谓的面向对象其实就是把属性和方法封装起来,以供重复调用。
比如人:
人的属性:姓名,年龄,性别
人的方法:唱,跳,rap
之前我们没有学习面向对象的时候会这样定义:
伪代码:
姓名 = “帅帅”
年龄 = 18
性别 = “superman”
def 唱():
print(“唱的真好听”)
def 跳():
print("跳的真好看")
def rap():
print("rap世界第一")
这样写有一个弊端,就是只有帅帅,淇淇不服啊。为什么她不出来一下?那么下面我们在实现淇淇的伪代码:
姓名 = “淇淇”
年龄 = 18
性别 = “girl”
def 唱():
print(“唱的真好听”)
def 跳():
print("跳的真好看")
def rap():
print("rap世界第一")
这个时候淇淇的伪代码就完成了,但是淇淇在某些方面是不如帅帅的,这个时候我们要把函数给重新架构一下,成下面这样:
伪代码:
姓名 = “淇淇”
年龄 = 18
性别 = “girl”
def 唱():
print(“唱的没帅帅真好听”)
def 跳():
print("跳的没帅帅好看")
def rap():
print("rap世界第二,搁帅帅后面排着")
到此,我们写完了两个人的,那么如果我们要写很多人呢?这个时候是不是可以把他们给抽象出来,变成一张图纸一样,用的时候直接拿过来用就可以?我们尝试着写成以下的伪代码:
伪代码:
人:
属性:
姓名
年龄
性别
方法:
唱
跳
rap
这个时候我们发现,只要是人,就可以拥有着写属性和方法。那么这个时候我们可以造出很多这样的人,比如薛之谦,王一博,周杰伦,他们有个共同的特征就是拥有人的属性和方法。
那么在python里面我们是怎样解决的呢?且看我把上面的伪代码实现
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def sing(self):
print(f"{self.name}唱的真好听")
def dump(self):
print(f"{self.name}跳的真不错")
def rap(self):
print(f"{self.name}世界第一")
这个时候我们肯定很奇怪,这不就是把之前的属性和方法前面套了一个class嘛,有什么神奇的?
下面我带你见证这一神奇的时刻:
shuaishuai = Person("帅帅",18,"superman")
shuaishuai.sing()
shuaishuai.dump()
shuaishuai.rap()
#结果:
帅帅唱的真好听
帅帅跳的真不错
帅帅世界第一
到这是不是还是有些不服,这上面的代码完全可以实现,我这写的都多了,是不是?
那么我们在把淇淇也写出来:
qiqi = Person("淇淇",18,"beautifulgirl")
qiqi.sing()
qiqi.dump()
qiqi.rap()
#结果
淇淇唱的真好听
淇淇跳的真不错
淇淇世界第一
这个时候是不是也没多少感觉,只是减少了一点点代码而已啦,那么接下来就是见证帅帅有多帅的时刻了:
zhoujielun = Person("周杰伦",28,"man")
wangyibo = Person("王一博",21,"man")
xuezhiqian = Person("薛之谦",32,"man")
linjunjie = Person("林俊杰",25,"man")
连续生成四个人,而且他们四个人都可以进行唱,跳,rap
你要用以前的方式写,现在都好几十行了,而我这,短短的四行。
这就是面向对象的魅力
什么叫做对象呢?
这道题就是送分题,你的女朋友或者你的男朋友。这里有个狗粮,帅帅&淇淇。单身狗看我博客是不是特别心酸?
开个玩笑,对象就是实际生活中具体的事物
。比如你的车就是一个对象,你的小狗就是一个对象,我的手机也是一个对象。我手机老破了,太难过。
python中一切皆对象,linux
中一切皆文件
淇淇的进阶课堂:判断下面那个是对象
我的电脑
你的电脑
电脑
鼠标
键盘
手机
我的自行车
Alex的特斯拉
我假装有个特斯拉
什么叫做类?
类是封装对象的属性和行为的载体
类是对象的抽象。刚才我们说了对象就是具体的事物。那么比如我的车,你的车都是对象,这个时候他们有个统一的标准,比如四个轮胎,一个方向盘,四个座椅。而这个时候我们说车的时候,就会知道他会有我们所说的那些属性和方法。
我们住的房子,他就是对象,但是设计房子的图纸,他就是类。他可以设计成各种各样的,然后由我们勤劳的劳动人民去实现。比如天津的网红图书馆,天津的失恋博物馆(好像在这说这个有点尴尬,毕竟俺是有对象的人)。
那么我们刚才说的什么馆,抽象出他们的相同点,他们统一有一个专有名词,叫做馆。这个就是类。
总结:类是对象的抽象,对象是类的具体实例。
面向对象的三大特性:封装,继承,多态
封装:
我们使用电视遥控器,只需要知道按上下就可以进行换台操作,而不知道遥控器是具体怎么实现的,这就是封装。所谓封装,就是把具体实现隐藏起来,别人使用的时候只给固定的结构进行调用。
继承:
继承跟我们现实生活中的继承类似,你爸有好几套房,看你长大了,老在外面租房住,感觉不太好,送了你一套。这就是继承,而面向对象的继承比现实生活中强了不知道无数倍。继承来的东西你的父类还是存在。也就是说,你爸有十套房,你继承之后你也会有十套房,而且你爸还不会少。不像我们现实世界,你爸给你之后,你爸就没了这十套房。
多态:
一种事物的不同表现形态。python中是非常喜欢鸭子模型的,就是有个鸟,它会游泳,它会跑,它会叫,它就是鸭子。关于多态请看后面的多态详细描述。
类表示具有相同属性和方法的集合,使用类就是创建对象。
固定结构:
class 类名: #类名一般使用大驼峰命名
类属性
类方法
写好了类之后并不能直接使用。就跟房子的图纸一样,你写好并不能进行住,需要盖好才可以。
class Person:
def __init__(self,name,age,sex): #self:代表当前对象 剩下的三个属性在类创建对象的时候必须实现
#类属性,可以在__init__中添加,也可以在其他方法里面添加
self.name = name
self.age = age
self.sex = sex
#类方法
def sing(self):
print(f"{self.name}唱的真好听")
def dump(self):
print(f"{self.name}跳的真不错")
def rap(self):
print(f"{self.name}世界第一")
shuaishuai = Person("帅帅",18,"superman")
删除对象属性:del 对象名.属性名
不建议删除
__init__
魔术方法
当类中写了这个方法的时候,第一个参数必须是self,代表当前对象,然后第二个参数开始就随意,但是这些参数在创建对象的时候必须一一实现。
创建对象的时候自动调用__init__
方法
类空间和对象空间
类也遵从自上而上执行,所以如果类里面有同名的方法,前一个方法会被后一个方法覆盖。
然后对象初始化的时候,会调用类覆盖好的方法
# 创建一个类,能够自动统计当前类创建了多少个对象
class Person():
num = 0
def __init__(self):
Person.num += 1
print(Person.num)
Person()
Person()
Person()
Person()
print(Person.num)
python中前后用两个下划线包起来的叫做魔术方法
python3中的魔术方法有:
常用的魔术方法:
__init__:
1.用来构造初始化函数,用来给对象进行初始化属性,所以不需要返回值
2.创建对象的时候自动调用
3.自定义类如果不定义的话,默认调用父类object的,同理继承也是,子类若无,调用父类的,若有,调用自己的
class Animal:
def __init__(self):
print("init初始化方法,没有调用父类object")
Animal()
#结果:
init初始化方法,没有调用父类object
__new__:
1.用所给类创建一个对象,并且返回这个对象
2.因为是给类创建实例,所以至少传一个参数cls,参数cls代表代表要实例化的类,此参数在实例化时用python解释器自动提供
3.在类实例化时内部创建类实例的函数,并且返回这个实例,所以它是实例时最先被调用的方法,一般不要人为定义该方法
4.因为要创建实例返回实例,所以要有返回值。return父类__new__出来的实例,或者直接是object的__new__出来的实例
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
类的成员主要有属性和方法,属性可以随意,方法的第一个参数必须是self
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def sing(self):
print(f"{self.name}唱的真好听")
def dump(self):
print(f"{self.name}跳的真不错")
def rap(self):
print(f"{self.name}世界第一")
shuaishuai = Person("帅帅",18,"superman") #初始化
#访问成员方法
shuaishuai.sing()
shuaishuai.dump()
shuaishuai.rap()
访问类中的属性和方法只需要对象使用成员运算符点
来进行调用
类属性通过类来访问,对象属性通过对象来访问
如果想把某些属性给隐藏起来,不想让外界直接访问,可以在属性名前面加两个下划线。比如帅帅不想直接让别人知道他的年龄或者修改他的年龄:
可以使用单下划线,双下划线,首尾双下划线来限制访问权限
单下划线开头的是protected类型的成员,只允许类本身和子类进行访问,不能使用from xxx import ccc进行导入
双下划线只能由定义了该属性或方法的类调用,而不能由类的对象调用,类的对象如果想调用,必须使用set/get方法
首尾双下划线是系统定义的特殊方法,一般是系统定义的名字
class Person:
def __init__(self, name,sex):
self.name = name
self.__age = None
self.sex = sex
def set(self,age):
self.__age = age
def get(self):
return self.__age
def sing(self):
print(f"{self.name}唱的真好听")
def dump(self):
print(f"{self.name}跳的真不错")
def rap(self):
print(f"{self.name}世界第一")
shuaishuai = Person("帅帅","superman") # 初始化
#这个时候初始化帅帅的年龄就会报错,可以使用set方法来赋值,get方法取值
shuaishuai.set(18)
print(shuaishuai.get())
有的时候我们需要创建对象的时候就进行给属性赋值,但是这样的方法往往是不安全的,会直接修改我们类中的属性,这样的话安全性不高。比如你的年龄是18岁,但是这个时候有用户进行恶作剧,直接将其修改为600岁,你是不是乐坏了?但是你感觉现实吗?
python中使用@property
将一个方法转换为属性,从而实现用于计算的属性,将方法转换为属性后,可以直接通过方法名来访问,而不需要加括号。
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
@property
def func(self):
if self.age < 150 and self.age > 0:
print(self.age)
else:
print("想啥呢?")
shuaishuai = Person("帅帅",18)
shuaishuai.func #func这个属性不能对其赋值,因为他本质也是一个函数
@property
可以将属性设置为只读属性
为此,python中有了私有属性和私有方法供大家使用。私有属性就是在属性前面加两个下划线,然后给这个私有属性给予set和get方法,这样对象调用的时候就只能通过set方法来进行赋值,get方法来获取值
class Person:
def __init__(self, name,sex):
self.name = name
self.__age = None
self.sex = sex
def set(self,age):
self.__age = age
def get(self):
return self.__age
一个一个的类就跟我们现实世界中的模板一样,只有把他们全部关联起来,才会使我们做事更加高效。比如轮胎跟发动机组合成了车,零食跟零食袋组合成了零食一样。类和类的组合,一般分为以下三种关系:
一个动作执行的时候,需要另一个动作来帮忙。比如打开电脑,帅帅去玩电脑或者帅帅去打王者
依赖就是我用你,你需要我。
比如帅帅玩电脑,电脑需要帅帅玩
#依赖
class Person:
def run(self):
print("我没事干")
class Computer:
def play(self,tool):
tool.run()
print("我是电脑,玩我")
class Phone:
def play(self,tool):
tool.run()
print("我有王者荣耀,来玩啊")
shuaishuai = Person()
dnf = Computer()
dnf.play(shuaishuai) #依赖是给一个类的对象的方法给另一个对象
wangzhe = Phone()
wangzhe.play(shuaishuai)
一个类使用某个类中的某个方法
这种情况下,类与类之间的关系是最轻的,可以随时替换。
依赖就是一个类的对象的方法自己完不成一些功能,需要另一个对象来完成,把他加载到此方法中。就是依赖
一个类需要某个类的具体对象去做一些事情,这就是组合。轮胎和发动机组合成了车一样。
组合可以一对一,也可以一对多。
一个类与另一个类没有共同点,但是他们之间有关系,这就是组合
组合就是我需要什么,但是我没有这些东西,我就拿你。
class Car:
def __init__(self,name,power = None):
self.__name = name
self.__power = power
def set_power(self,power):
self.__power = power
def zhuang_Tread(self):
print(f"{self.__name}装好了{self.__power.get_name()}的轮胎")
def saiche_power(self):
print(f"{self.__name}装好了{self.__power.get_name()}的发动机")
class Tread:
def __init__(self,name):
self.__name = name
def set_name(self,name):
self.__name = name
def get_name(self):
return self.__name
class Engine:
def __init__(self,name):
self.__name = name
def set_name(self,name):
self.__name = name
def get_name(self):
return self.__name
tread = Tread("牛逼牌")
engine = Engine("赛车")
car = Car("奔驰",tread)
car.zhuang_Tread()
car.set_power(engine)
car.saiche_power()
#分析:
是不是发现了有很多的重复代码,而且极其麻烦,不如用继承好。刚开始用,还是没有那么的得心应手,我还的努力。
将一个类的对象封装到另一个类的属性中进行一些操作
淇淇的进阶课堂
老师和学生模型(老师对学生是一对多,学生对老师是一对一)
创建教师类和学生类
教师类有姓名和学生列表两个属性
教师类有添加学生的方法(添加的学生是具体对象)
教师类有显示对应学生姓名和学号的方法
学生类有学号/姓名/年龄属性
创建多个学生,并添加到某位教师的学生列表中
打印该教师的所有学生学号
一般我们看到继承
这两个字都有一种一夜暴富的心态。比如我们看的西虹市首富,猛虫过江,都是有了巨额的财富,令继承人过上了幸福的生活。那么在我们的Python中,继承究竟是怎么样的呢?在python中子类会拥有父类的属性和方法,但是不会继承私有属性和私有方法。被继承的类叫父类或基类,继承的类叫做子类或派生类。
#固定结构:
#父类
class Person(object): #括号里面写要继承的类
def __init__(self, name,sex):
self.name = name
self.__age = None
self.sex = sex
def set(self,age):
self.__age = age
def get(self):
return self.__age
def sing(self):
print(f"{self.name}唱的真好听")
def dump(self):
print(f"{self.name}跳的真不错")
def rap(self):
print(f"{self.name}世界第一")
#子类
class Boy(Person):
pass
shuaishuai = Boy("帅帅","superman")
shuaishuai.sing()
#结论:
可以看出,子类Boy什么都没有写,只是继承了一下父类Person,他就拥有了父类的属性和方法,但是私有属性没有被继承。
老师和学生模型(老师对学生是一对多,学生对老师是一对一)
创建教师类和学生类
教师类有姓名和学生列表两个属性
教师类有添加学生的方法(添加的学生是具体对象)
教师类有显示对应学生姓名和学号的方法
学生类有学号/姓名/年龄属性
创建多个学生,并添加到某位教师的学生列表中
打印该教师的所有学生学号
组合是指在新类里面创建原有类的对象,重复利用已有类的功能“has-a”关系
而继承允许设计人员根据其它类的实现来定义一个类的实现“is-a”关系
方法重写就是子类继承父类的方法,然后把方法体进行重写。
比如父类是房子的图纸,因为每个人对美的定义不一样,你感觉你爸弄得这个图纸不适合你,你又不想重新弄。就把比如卧室进行重新设计一下,床啥的就不换了。这就是方法重写
class Person(object):
def __init__(self, name):
self.name = name
def sing(self):
print(f"{self.name}唱的真好听")
#子类
class Boy(Person):
def sing(self):
print(f"{self.name}最帅")
shuaishuai = Boy("帅帅")
shuaishuai.sing()
#结果:帅帅最帅
这个时候我们可以发现,原来我们不重写sing方法的时候,他调用的是父类的sing方法,当我们在子类中进行重写之后,他显示的就是子类的方法。
由此可以得出查找顺序:对象调用某个属性或者方法的时候,会先在当前类中进行查找,如果找不到,就去他的父类对象今进行查找。
深度优先和广度优先
子类如果有自己的初始化属性,也就是有魔术方法__init__
的时候,子类不会自动执行父类的方法,必须使用super来进行调用,获取父类的初始化属性
使用super关键字调用父类的方法
子类如果编写了自己的构造方法,但没有显式调用父类的构造方法,而父类构造函数初始化了一些属性,就会出现问题
解决方式:调用超类构造方法,或者使用super函数 super(当前类名, self).init()
super在Python3和python2中的区别:
Python3可以使用直接使用 super().xxx 代替 super(Class, self).xxx
super钻石继承
super的内核 mro方法:返回的是一个类的方法解析顺序表(顺序结构)
我们定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,这也是super在父类中查找成员的顺序,它是通过一个C3线性化算法来实现的
我们可以使用下面的方式获得某个类的 MRO 列表
类名.mro() 或者 对象名.__class__.mro()
练习:
有一个动物类,猫狗两个类都继承了动物,动物类拥有动物的属性,定制猫狗类的个性属性
动物都有吃的方法,动物在吃东西之后会打印自己的血量值和智力值,但是猫和狗吃的东西不一样
猫狗在吃了食物之后,猫会增加血量值,狗会增加智力
多继承是子类不断的继承父类,依次类推,最后的孙子类拥有父类跟子类的方法
#多继承
class Person(object):
def run(self):
print("人会跑")
class Boy(Person):
def like_girl(self):
print("男孩喜欢女孩子")
class Girl(Boy):
def like_boy(self):
print("女孩子也喜欢男孩子")
class Kid(Girl):
def kids(self):
print("孩子是男孩跟女孩的爱情结晶")
kid = Kid()
kid.run()
kid.like_girl()
kid.like_boy()
kid.kids()
#结果
人会跑
男孩喜欢女孩子
女孩子也喜欢男孩子
孩子是男孩跟女孩的爱情结晶
可以看出,多继承就是最后的一个类拥有上面的类的属性和方法(除了私有属性和私有方法)
多重继承逻辑不行的人就别看了。
isinstance()及issubclass()
isinstance()及issubclass()
isinstance() 用于检查实例类型:isinstance(对象,类型)
issubclass() 用于检查类继承:issubclass(子类,父类)
使用多继承,会涉及到查找顺序(MRO)、钻石继承等问题
钻石继承
单继承时 类名.init()的方式和super().init()方式没啥区别
但是使用 类名.init()的方式在钻石继承时会出现问题
super的内核 mro方法:返回的是一个类的方法解析顺序表(顺序结构)
我们定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,这也是super在父类中查找成员的顺序,它是通过一个C3线性化算法来实现的
我们可以使用下面的方式获得某个类的 MRO 列表
类名.mro() 或者 对象名.class.mro()
栈在内存中保存对象的引用
堆在内存中保存对象
总结:对象在栈中保存,在堆中被引用
实现栈和队列
封装就是把一个个的属性和方法隐藏起来,只留下具体的接口供下一个人使用
我们最常见的封装就是遥控器,你不需要知道遥控器是怎么装的,直接拿来开始换台就行。比如动物世界。
私有属性就是在属性前面加get/set方法,然后再当前类中进行调用和实现,外界只能使用这个属性的set/get方法来操作他。而且不能被子类继承
私有方法跟私有属性一样,在方法前面加两个下划线
破解私有属性和私有方法
_类名__属性
破解私有属性和私有方法:
在名称前加上 _类名,即 _类名__名称(例如a._A__N)
其实加双下划线仅仅是一种变形操作
类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式
一个变量可以有不同的数据类型
一个事物的不同表现形态,具体表现在比如狗,有柯基,二哈,还有淇淇(淇淇那么可爱,哈哈哈)
python天生支持多态
多态基础上,定义统一的接口。不同的类对象作为参数使用时,得到的结果不同
python著名的鸭子模型:
只要你会某一类功能,你就是一只鸭子。
比如会游泳,会飞,会跑,好了,你是鸭子,周黑鸭的鸭子。
对比:
多态强调的是:一类事物 不同的形态
多态性强调的是:同一操作,作用对象不同,表现出不同实现方式(只关心行为结果)
练习:
创建汽车类(Car)含实例属性颜色red,对象方法run,功能是打印XX颜色小汽车在跑。
创建猫类(Cat)含实例属性名字name,对象方法run,功能是打印猫咪XX在跑。
实例化汽车类颜色为红色,实例化猫类,使用公共函数调用对象方法
设计模式就是前人总结的经验,解决某一类问题的具体方法。比如我们肯定都做过算术题,知道首先做括号里面的,然后在做乘除,最后加减。还有我们的城市群落的形成,也是先盖新城,拉动经济,在弄旧改。所以我们学习设计模式之后,以后解决某一类问题,都不需要再重复造轮子。
有时通过单一对象方便集中管理资源
单例模式是保证一个类仅有一个实例的设计模式
保证了在程序的不同位置都可以且仅可以取到同一个对象实例:如果实例不存在,会创建一个实例;如果已存在就会返回这个实例。
总结:某一个类只有一个对象,可以处处调用
学习的文章
使用模块
使用装饰器
使用类
基于魔术方法new(***)
当实例化一个对象时,是先执行了类的__new__
方法(我们没写的时候默认调用object.__new__
)然后再实例化类的__init__
方法
class Singleton(object):
instance= None
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
s1 = Singleton()
s2 = Singleton()
print("s1的地址:{},s2的地址:{}".format(id(s1), id(s2)))
结果:
s1的地址:1085113828968,s2的地址:1085113828968
基于metaclass方式实现
python中不需要创建类,创建子类来实现工厂模式,可以直接使用
class Factory(object):
def get_person(self, name, gender='M'):
if gender == 'M':
return Male(name)
if gender == 'F':
return Female(name)
约束就是一些约定,我们以后早晨八点来上课,晚上十点回家。这就是一种约束。在学校我们听老师的话,在家里听爸爸妈妈的话,在社会上听领导的话。什么时候不听话呢?就是你成了爷爷的时候,哈哈哈。现在既然咋们还没有是爷爷的时候,就按照规定来干。
在父类建立一种约束(通过抛出异常)
class Animal():
def eat(self):
raise Exception("子类必须拥有eat方法")
class Dog(Animal):
def eat(self):
print("dog eat")
class Cat(Animal):
def eat(self):
print("cat eat")
class Bir(Animal):
def bireat(self):
print("bir eat")
def change(tool):
tool.eat()
dog = Dog()
change(dog)
bir = Bir()
change(bir)
引入抽象类的概念
from abc import ABCMeta,abstractmethod
class Airer(metaclass=ABCMeta):
@abstractmethod
def airfly(self):
pass
#结论:
抽象类在父类中抽象完毕之后,必须在子类中重写,不然会报错。
类中定义的普通方法
class Person:
def func(self):
pass
只有实例化之后才可以使用,接收的第一个参数一定为对象本身
指一个类中通过@classmethod
修饰的方法
第一个参数必须是当前类的对象,该参数名一般约定为cls,通过它来传递类的属性和方法。
调用:实例对象和类对象都可以调用
类方法是将类本身作为对象进行操作的方法
通过使用类方法可以在不创建对象的时候直接进行操作。比如有的时候我们不想要实例化对象,而执行一些操作的时候,完全可以使用
应用场景:当一个方法中只涉及到静态属性的时候可以使用类方法(类方法用来修改类属性)
#使用类方法对商品进行统一打折
#分析:商场里面客户购买东西,打几折的时候,用户自己算往往不是很快,而且还很累,这个时候就需要直接计算出打折后的价格。客户只需要调用这个类方法就可以。
class Shop:
def __init__(self,price):
self.__price = price
@property
def func(self):
return self.__price * 0.5
s = Shop(100)
print(s.func)
print(Shop.func)
#进阶版
class Shop:
__discount = 1 #折扣价
def __init__(self,name,price):
self.__name = name
self.__price = price
@property
def discount_money(self):
self.__discount = 0.5
@property
def finally_money(self):
return self.__price * self.__discount
s = Shop("橘子",5)
s.discount_money
print(s.finally_money)
Shop("苹果",10)
Shop.discount_money
print(Shop.finally_money)
#类方法进阶版
class Shop:
__discount = 1 #折扣价
def __init__(self,name,price):
self.__name = name
self.__price = price
@classmethod
def discount_money(cls,num):
cls.__discount = num / 10
@property
def finally_money(self):
return self.__price * self.__discount
s = Shop("橘子",5)
s.discount_money(8)
print(s.finally_money)
类方法说了这么多,具体应用场景还是不太明确,还需要接着研究。
使用@staticmethod
修饰的方法
参数随意,没有self
和cls
参数
方法体中不能使用类或实例的任何属性和方法
实例对象和类对象都可以调用
静态方法是类中的函数,不需要使用实例。也就是说不需要进行实例化就可以调用
静态方法一般定义后就不需要再进行修改,用来写一些固定的操作
应用场景:一般是与类和对象无关的代码
#静态方法
class Person:
@staticmethod
def func():
print("""
1.搞嘛?
2.不知道
3.先记下来吧
4.记下来不知道应用场景
5.我好累
""")
Person.func()
使用property修饰的方法可以直接使用对象.
方法名进行调用,不需要给方法加括号。
应用场景:商场打折,计算周长,面积等
一般具有三种访问方式:获取,修改,删除
只有在属性定义property后才能定义setter,deleter
方法一
class Foo:
@property
def AAA(self):
print('get的时候运行我')
@AAA.setter
def AAA(self,value):
print('set的时候运行我')
@AAA.deleter
def AAA(self):
print('delete的时候运行我')
方法二
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一一对应
只有@property定义只读,加上@setter定义可读可写,加上@deleter定义可读可写可删除
反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!
有四个可以实现自省的函数:hasattr,getattr,setattr,delattr
user = User()
while True:
choose = input('>>>').strip()
if hasattr(user,choose):
func = getattr(user,choose)
func()
else:
print('输入错误。。。。')
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
异常(Exception)是一个事件,该事件可能会在程序执行过程中发生,影响了程序的正常执行
raise语句显式的抛出异常
Python解释器自己检测到异常并引发它
异常的固定结构:
try:
被检测的代码块
except 异常类型:
try中一旦检测到异常,就执行这个位置的逻辑
自定义异常:
python中提供的错误类型可能并不能解决所有错误
如果以后你在工作中,出现了某种异常无法用已知的错误类型捕获(万能异常只能捕获python中存在的异常),那么你就可以尝试自定义异常,只要继承BaseException类即可
自定义异常:
class HelloError(Exception):
def __init__(self,n):
self.n=n
try:
n=input("请输入数字:")
if not n.isdigit():
raise HelloError(n)
except HelloError as hi:
print("HelloError:请输入字符。\n您输入的是:",hi.n)
else:
print("未发生异常")