章节号 | 内容 |
---|---|
1图片格式(png) | 宽度大于620px,保持高宽比减低为620px |
1-1 | 应用 |
1-1-1 | 方法 |
VScode操作:同时选中多个相同字符,同时修改
快捷键:Ctrl+Shift+L
VScode操作:多行同时等量删除缩进
快捷键:Shift+Tab
第1章节 新式类及保护对象的属性
新式类的样式(括号中有object):
class person(object):
def __init__(self):
pass
方法就是
: 1、属性前加__
(私有属性
)。不带__
为公有属性。
2、定义一个方法来修改属性。
3、定义一个方法来return属性。
↓之前的编写中,对象的属性是可以直接进行赋值操作的,比如:
class person(object):
def __init__(self, name, age):
self.name = name
self.age = age
ren=person("xiaom",14)
ren.age=19
↓如果不想在外部直接访问属性,则可以在属性前加两个下划线:__name
,__age
。
class person(object):
def __init__(self, name, age):
self.__name = name
self.__age = age
ren=person("xiaom",14)
print(ren.__age)
ren.__age=19
print(ren.__age)
↓此时如果再继续编译,则:
Exception has occurred: AttributeError
'person' object has no attribute '__age'
File "/home/li/py/2.py", line 7, in <module>
print(ren.__age)
↓此时如果想要修改属性,则只能在类中定义一个方法,通过调用方法来修改:
class person(object):
def __init__(self, name, age):
self.__name = name
self.__age = age
def chaname(self, name):
self.__name = name
def chaage(self, age):
self.__age = age
def priname(self):
print(self.__name)
def priage(self):
print(self.__age)
ren = person("xiaom", 14)
ren.priname()
ren.priage()
ren.chaname("aaa")
ren.chaage(19)
ren.priname()
ren.priage()
xiaom
14
aaa
19
↑可以看到程序已经按我们的预想正确执行了。
↓因为我们修改属性是通过类内部的方法,则我们可以在方法中加入对修改的属性值的一定的合法性
判断。
def chaage(self, age):
if age <=100:
self.__age = age
else:
print("输入的年纪非法")
↓如果需要在外部程序中获得对象的属性的值,则可以定义一个方法,来return
这个属性。
def getname(self):
return self.__name
第2章节 __del__()方法
↑相当于析构函数。
-
2-1 __del__()方法—
class person(object):
def __init__(self, name):
self.__name = name
def __del__(self):
print("a....................")
ren = person("wang")
↓运行结果如下。因为程序结束后python解释器自动删除了ren对象,系统自动调用了__del__
方法。
a....................
↓下面考虑如下情况,我们把ren
继续赋给ren1
和ren2
,这实际上代表什么呢?我们来看一看:
class person(object):
def __init__(self, name):
self.__name = name
def __del__(self):
print("a....................")
ren = person("wang")
print("==============1===============")
ren1=ren
ren2=ren1
del ren
print("==============2===============")
==============1===============
==============2===============
a....................
↑为什么这里删除了ren
这个对象实例,而__del__()
方法却没有在==2==
之前调用呢,这是因为ren
和ren1
和ren2
全部都指向同一片内存区域,删掉了ren
,还有ren1
和ren2
指向这片内存,只有到程序结束之后,python解释器才会释放掉这片内存而自动调用__del__()
方法。
↓对程序稍加改动,再看:
print("==============1===============")
ren1=ren
ren2=ren1
del ren
del ren1
del ren2
print("==============2===============")
==============1===============
a....................
==============2===============
↑经过手动的全部删除掉ren
和ren1
和ren2
,这片内存已经没有任何的引用了,因此在程序退出之前被提前释放了。
第3章节 类的继承
-
3-1 类的继承—私有属性在继承中的工作原理
↓下列代码中的两个类dongwu
和gou
定义的方法和属性其实完全一样,实现的同样功能,这就造成了源代码的冗余。
class dongwu(object):
def __init__(self, name="dongwu",yanse="heise"):
self.__name = name
self.__yanse= yanse
def __del__(self):
print("a..............")
dog = dongwu()
class gou(object):
def __init__(self, name="gou",yanse="heise"):
self.__name = name
self.__yanse= yanse
def __del__(self):
print("a..............")
dog1=gou("gou gou")
a..............
a..............
如何有效的实现代码的重用呢?那就是类的继承
。下面我们将代码进行改动↓
class dongwu(object):
def __init__(self, name="dongwu", yanse="heise"):
self.__name = name
self.__yanse = yanse
def __del__(self):
print(self.__name)
print("a..............")
dog = dongwu()
class gou(dongwu):
pass
#pass语句用作占位,避免编译错误
dog1 = gou("gou gou")
dongwu
a..............
gou gou
a..............
↑可以看到,在gou
类类体中没有编写任何代码的情况下,我们成功的用gou("gou gou")
创建了dog1
对象,而且成功的在程序退出的时候调用了__del__()
。
关键点就在于:
我们定义class gou
的时候,在gou
的括号中,把dongwu
类当做了参数。这是实现继承的关键所在即class gou(dongwu):
。
↓下面我们给gou
类添加一个方法并调用:
class gou(dongwu):
def priinfo(self):
print(self.__name)
print(self.__yanse)
dog1 = gou("gou gou")
dog1.priinfo()
Exception has occurred: AttributeError
'gou' object has no attribute '_gou__name'
File "/home/li/Desktop/py/jichen2.py", line 15, in priinfo
print(self.__name)
File "/home/li/Desktop/py/jichen2.py", line 21, in <module>
dog1.priinfo()
↑提示出错了,具体内容就是gou
没有__name
的属性。
↓下面我们把代码中所有属性的名称的__
去掉,并调试对比结果:
class dongwu(object):
def __init__(self, name="dongwu", yanse="heise"):
self.name = name
self.yanse = yanse
def __del__(self):
print(self.name, end=" ")
print("a..............")
class gou(dongwu):
def priinfo(self):
print(self.name)
print(self.yanse)
dog1 = gou("gou gou")
dog1.priinfo()
gou gou
heise
gou gou a..............
↑可以看到程序按照我们预想的正确执行了。
那为什么去掉属性的私有控制(即删掉__)就会产生这样的差别呢?原因就继承的默认规则进行了限制:
带有__的属性或者方法,在子类中是无法直接被子类自己定义的方法去修改或者调用的!
↓解决方式为:在父类中定义一个方法,然后子类调用父类的这个方法来访问:
class dongwu(object):
def __init__(self, name="dongwu", yanse="heise"):
self.__name = name
self.__yanse = yanse
def __del__(self):
print(self.__name,end=" ")
print("a..............")
def priinfo(self):
print(self.__name)
print(self.__yanse)
class gou(dongwu):
pass
dog1 = gou("gou gou")
dog1.priinfo()
gou gou
heise
gou gou a..............
-
3-2 类的继承—私有方法在继承中的工作原理
↓下面我们在父类中加入一个私有的方法,就上例的代码做小改动:
class dongwu(object):
def __init__(self, name="dongwu", yanse="heise"):
self.__name = name
self.__yanse = yanse
def __del__(self):
print(self.__name,end=" ")
print("a..............")
def __priinfo(self):
print(self.__name)
print(self.__yanse)
def prii(self):
#此处可以进行相应的权限控制判断,实现对私有方法的保护
self.__priinfo()
class gou(dongwu):
pass
dog1 = gou("gou gou")
dog1.__priinfo()
↑看出改动在哪里了吗?对的,仅仅只是在父类的定义priinfo()
前面和dog1
的调用前面加了__
。
↓来运行一下看看:
Exception has occurred: AttributeError
'gou' object has no attribute '__priinfo'
File "/home/li/Desktop/py/jichen2.py", line 22, in <module>
dog1.__priinfo()
那如何来解决需要调用__priinfo()
的问题呢?对的,你可能已经看到了,那就是直接调用上列代码中写入的prii()
,原理就是通过父类的公共方法来调用它自己的私有方法↓
dog1 = gou("gou gou")
dog1.prii()
gou gou
heise
gou gou a..............
↑虽然稍微繁琐,但这确实是在实现了python的语言特性前提下,又很好的实现了软件的功能需求。
第4章节 父类方法的重写及调用父类方法
父类方法的重写可以理解为:子类自己定义了一个方法,这个方法实现的功能和父类不相同,但是名字却是一模一样的。
-
4-1 父类方法的重写及调用父类方法—重写
↓请看如下代码:
class dongwu(object):
def jiao(self):
print("aaaaaaaaaaaaaaaa")
class mao(dongwu):
def jiao(self):
print("mmmmmmmmmmmmmmm")
mao1 =mao()
mao1.jiao()
mmmmmmmmmmmmmmm
↑可以看到jiao
的方法在类mao
中被重写了,这是我们再调用mao1
的jiao()
方法的时候,执行的是print("mmmmmmmmmmmmmmm")
语句。
↓下面我们把子类的jiao()
方法注释掉,加上pass占位语句,再看运行结果:
class dongwu(object):
def jiao(self):
print("aaaaaaaaaaaaaaaa")
class mao(dongwu):
pass
# def jiao(self):
# print("mmmmmmmmmmmmmmm")
mao1 =mao()
mao1.jiao()
aaaaaaaaaaaaaaaa
↑看到对象mao1
调用的是父类的jiao()
方法的方法。
-
4-1 父类方法的重写及调用父类方法—调用父类方法
上面的例子我们是在子类中把jiao()
方法完全给改写掉了,但是如果我们需要父类中方法的部分或全部功能,然后在此基础上在子类中添加一些代码,该如何操作呢?看下面的代码↓
class dongwu(object):
def jiao(self):
print("aaaaaaaaaaaaaaaa")
class mao(dongwu):
# pass
def jiao(self):
##显式的调用###
dongwu.jiao(self)
#显式的调用###
print("mmmmmmmmmmmmmmm")
mao1 =mao()
mao1.jiao()
aaaaaaaaaaaaaaaa
mmmmmmmmmmmmmmm
↑上面的代码,我们在子类的方法中,显式的调用了dongwu.jiao(self)
(python2中就有的语言特性)这个父类的方法,然后再添加了部分代码,可见输出的时候,两个print都被执行了。
↓这种调用还有一种形式,可以写为:super().jiao()
。注意此类写法没有self
参数。
super().jiao()
aaaaaaaaaaaaaaaa
第5章节 多继承
↓发现的一个问题,稍后研究。
class a(object):
# def pri(self):
print("a================")
class b(object):
# def pri(self):
print("b================")
class c(a, b):
# # pass
# def pri(self):
print("c================")
a================
b================
c================
-
5-1 多继承—不同名方法的调用
↓下面代码定义了一个类a
,一个类b
,c
通过c(a,b)
的方式进行了多重继承。
class a(object):
def pria(self):
print("a================")
class b(object):
def prib(self):
print("b================")
class c(a, b):
def pric(self):
print("c================")
c1=c()
c1.pria()
c1.prib()
c1.pric()
a================
b================
c================
↑c
成功调用了a
和b
的pria|b()
方法。
!!!注意不要忘记:在继承中,父类的私有的属性和方法都是无法直接访问的!!!
-
5-2 多继承—同名方法的调用
刚才的三个类中,各自的pria|b|c()
方法是异名的,使用逻辑是比较清晰的。那如果在多重继承的时候,被继承的多个父类之中存在同名的方法,那子类在调用的时候,是什么情况呢?
↓我们看下面的代码:
class a(object):
def test(self):
print("test=a================")
class b(object):
def test(self):
print("test=b================")
class c(a, b):
pass
c1 = c()
c1.test()
test=a================
↓再稍作改动:
class c(b, a):
pass
c1 = c()
c1.test()
test=b================
是否有那么一点点头绪:父类方法重名,子类调用到底是谁的方法,关键看多重继承谁在前面
。
class c(a, b):
pass
#区别
class c(b, a):
pass
考虑稍微复杂的情形:
class base(object):
def test(self):
print("test=base================")
class a(base):
def test(self):
print("test=a================")
class b(base):
def test(self):
print("test=b================")
class c(a,b):
pass
c1 = c()
c1.test()
test=a================

↑这种找寻方式,被称为广度遍历(查找)方式。
↓有没有什么更直观的方式能显示这种顺序呢?有的,python提供了类似的功能,只要使用这么一行代码:
print(c.__mro__)
(<class '__main__.c'>, <class '__main__.a'>, <class '__main__.b'>, <class '__main__.base'>, <class 'object'>)
第6章节 多态
指调用的方法名是相同的,但是各自父亲、子类都有不同的方法的实现,那么各自方法执行起来的结果是不一样的。
class a(object):
def jiao(self):
print("aaaaaaaaaaaaaaa")
class b(a):
def jiao(self):
print("bbbbbbbbbbbb")
class c(a):
def jiao(self):
print("cccccccccccccc")
def jiaojiao(temp):
temp.jiao()
b1=b()
c1=c()
jiaojiao(b1)
jiaojiao(c1)
bbbbbbbbbbbb
cccccccccccccc
这个例子主要想突出的就是jiaojiao()
这个方法,不同的对象被同一个函数来调用,输出的结果却不一样。个人觉得这个例子的意义不是很明显,就好像不同的人用同一个锅炒菜,味道肯定是不可能完全一样的。
关键在于,python是弱类型语言,jiaojiao()的参数传入不要求规定参数的类型,可以随意传递。
第7章节 综合
↓考虑如下结构图:

↑左侧为类继承结构,右侧为类的属性和方法构成。在base之下的类的方法中参数非空的,表示这个类要重写这个方法;属性后有赋值的,表示要修改默认的父类的属性的值。首先我们构造base类:
class base(object):
def __init__(self, name="base", color="heise"):
self.name = name
self.color = color
def chi(self):
print("base eat")
def jiao(self):
print("base jiao")
def pao(self):
print("base pao")
def __str__(self):
msg="name="+self.name+" color="+self.color
return msg
↑其中name
属性的默认值是base,color
属性的默认值是heise。其余方法都显示出了base默认特征行为。
↓下面来构造a类及其他类。
class a(base):
def funcname(self):
pass
class b(base):
def funcname(self):
pass
class ab(a, b):
def funcname(self):
pass
class aa(a):
def funcname(self):
pass
a1=a("a1","baise")
print(a1)
a1.jiao()
a1.chi()
a1.pao()
name=a1 color=baise
base jiao
base eat
base pao
↑其实仅仅把类a构造成上示代码已经能够正确把程序运行起来了。
↓但是考虑这样一个需求:构造a类的实体的时候,能不能也有a类自己的默认的构造名字呢?这时可能会有这样一个想法:那我们重写__init__()
不就行了!
class a(base):
def __init__(self, name="a", color="heise"):
self.name = name
self.color = color
a1=a()
print(a1)
a1.jiao()
a1.chi()
a1.pao()
name=a color=heise
base jiao
base eat
base pao
↑但是发现什么问题没有?color="heise"
这一部分,是不是和父类重复了?有什么办法能解决这个细节的问题吗?
?把这个color="heise"
直接删掉?那似乎就没有办法给self.color
进行赋默认属性了。
class a(base):
def __init__(self, name="a"):
self.name = name
self.color=color#????????????
print("a_init")
?依靠父类的init方法?你已经重写了init了,父类的init根本就无法调用。
?参数的color和方法体内的赋值全部删掉?那你的a类实体就压根没了color这个属性了。
class a(base):
def __init__(self, name="a"):
self.name = name
#??????????????????
print("a_init")
那似乎已到南墙?未必,回头看看刚才的思维点,有哪一个是能利用的?对了:
class a(base):
def __init__(self, name="a"):
base.__init__(self)
self.name = name
print("a_init")
↑既然系统不会调用base的init,那就自己动手,丰衣足食好了。
↓输出结果如下:
a_init
base_init
name=a color=heise
base jiao
base eat
base pao
↑首先a的init被调用,随后立即调用base的init,这时name和color已经被赋了初值,然后base的init执行结束,回到了a的init, self.name = “a”被执行,color的值保持不变。
↓别忘了,调用父类方法还有一种形式哦:
super().__init__()
“回望,总是会发现自己能做的更好。”
↓刚才的a类还有什么不完美之处?对的,那就是似乎就只能使用父类默认构造的heise的color了。不行,a也得有自己的修改办法!
class a(base):
def __init__(self, name="a",color=""):
super().__init__()
self.name = name
if color== "":
None
else:
self.color = color
↑首先在方法的参数内再次加入color的形式参数,默认初值为空“”
,比较方便方法体内进行判断。然后方法体内写下这样的逻辑:如果color为空,则表明在生成a类对象的时候,没有传入这个color参数,那我们就沿用父类的color的赋值。否则就代表color参数有实际的值传入了,则按传入的值来进行赋值。
a1=a(color="lvse")
#由于init方法有多个参数,这里使用显式的传值方式
print(a1)
a1.jiao()
a1.chi()
a1.pao()
a_init
base_init
name=a color=lvse
base jiao
base eat
base pao
↓现在来按照程序架构图基本补全代码:
class base(object):
def __init__(self, name="base", color="heise"):
self.name = name
self.color = color
print("base_init")
def chi(self):
print("base eat")
def jiao(self):
print("base jiao")
def pao(self):
print("base pao")
def __str__(self):
msg="name="+self.name+" color="+self.color
return msg
class a(base):
def __init__(self, name="a",color=""):
super().__init__()
self.name = name
if color== "":
None
else:
self.color = color
def jiao(self):
print("a jiao")
def pao(self):
print("a pao")
print("a_init")
class b(base):
def jiao(self):
print("b jiao")
def pao(self):
print("b pao")
class ab(a, b):
def jiao(self):
print("ab jiao")
def pao(self):
print("ab pao")
class aa(a):
def jiao(self):
print("aa jiao")
def pao(self):
print("aa pao")
a1=a(color="lvse")
print(a1)
a1.jiao()
a1.chi()
a1.pao()
print("===================================================")
b1=b()
print(b1)
b1.jiao()
b1.chi()
b1.pao()
print("===================================================")
ab1=ab()
print(ab1)
ab1.jiao()
ab1.chi()
ab1.pao()
print("===================================================")
aa1=aa(color="red")
print(aa1)
aa1.jiao()
aa1.chi()
aa1.pao()
a_init
base_init
name=a color=lvse
a jiao
base eat
a pao
===================================================
base_init
name=base color=heise
b jiao
base eat
b pao
===================================================
base_init
name=a color=heise
ab jiao
base eat
ab pao
===================================================
base_init
name=a color=red
aa jiao
base eat
aa pao
-
7-1 综合—为某个类产生了多少个对象进行计数
如何完成标题的要求?
首先最容易想到的自然是全局变量。定义一个全局变量,在每次产生类的实体的时候,手动去把变量进行加1
的操作,需要这个数量则print即可。
还有其他办法么?可以添加一个类属性来实现,所谓类属性,就是一个变量,在类里面,但是在类方法外面
(类属性同样分公有和私有之分)。但是还是要进行手动加1
的操作。
class base(object):
#类属性
bcount = 0
def __init__(self, name="base", color="heise"):
self.name = name
self.color = color
print("base init")
b1=base()
#手动加1操作
base.bcount+=1
b2=base()
#手动加1操作
base.bcount+=1
print(base.bcount)
print(b1.bcount)
print(b2.bcount)
base init
base init
2
2
2
↓有什么好的改进方法能让类在创建实例对象的时候自动计数吗?既然类属性访问的方式很宽松,那么在类的定义代码中,自己访问自己就好了呀:
class base(object):
bcount = 0
def __init__(self, name="base", color="heise"):
self.name = name
self.color = color
print("base init")
#显式调用自己的类属性
base.bcount+=1
b1=base()
b2=base()
print(base.bcount)
print(b1.bcount)
print(b2.bcount)
base init
base init
2
2
2
↑同时可以看到,类的实例对象
也可以通过对象名.类属性名
的方式访问类属性。
-
7-2 综合—实例对象和类对象

↑实例对象中没有代码,代码是调用类对象的代码。
↑实例对象创建的时候,内部会包含一个对类对象的引用,从而能找到类对象的代码并运行之。
类和实例之前的互相访问:
1、
实例对象可以访问类属性(访问某个属性时,自己没有就找类对象中有没有,类对象也没有就报错)。

2、
公有的类属性可以通过类名直接访问,公有的实例属性(在方法内部定义的属性)不能
通过类名直接访问。

3、
类对象的私有属性,无法在类对象外部进行访问。


4、
实例对象可以访问类属性,但是不能 修改
类属性。下图的b1.bcount实际是创建了一个b1自己的实例属性(只属于实例对象自己),而这个属性和正好和类属性名字相同。可以通过类名直接修改,但是这种方式不太安全。最好不要采用。最好定义个方法,把类属性设置为私有类属性,通过方法来修改,还可以在方法中对传入数据进行一些安全性判断。

-
7-3 综合—类方法(注意参数为cls)
↓格式:在方法的上一行输入:@classmethod
@classmethod
def setcount(cls):
pass
如果不加@classmethod
,那相当于我们调用的还是实例的方法,想要用实例的方法去修改类属性,那还是不行的。这里一定注意参数的位置,由self
换成了cls
,所以cls.bcount
就是引用的类属性,而且这个方法还可以由实例来调用。
@classmethod
def setcount(cls,count):
cls.bcount=count
b1=base()
b1.setcount(100)
print(base.bcount)
base init
100
注意:类对象可以调用类属性及类方法,但是不能调用实例属性及方法。
注意:实例对象可以获取类属性的值,但是不能修改类属性。实例对象可以获取实例属性的值,也可以修改实例属性的值。但是可以调用实例方法和类方法。
↓下面我们把自动进行类实例计数的功能进行改进:
class base(object):
bcount = 0
def __init__(self, name="base", color="heise"):
self.name = name
self.color = color
print("base init")
self.record()
@classmethod
def record(cls):
cls.bcount+=1
b1=base()
print(base.bcount)
b2=base()
print(base.bcount)
base init
1
base init
2
-
7-4 综合—异常
↓具有如下格式,except来捕获特定的异常。如果异常没有选择对,一样会程序报错。
try:
open("123.txt","r")
except IOError:
print("chucuo")
↓也可以进行多个错误的捕获。
try:
open("123.txt","r")
except (IOError,NameError):
print("chucuo")
↓直接打印系统提示的错误信息
try:
open("123.txt","r")
except IOError as errmsg:
print(errmsg)
[Errno 2] No such file or directory: '123.txt'
↓不管程序执行出错不出错,finally
一定会执行。
try:
open("123.txt","r")
finally:
print("finally")
↓最后一种格式。
try:
# pass
open("123.txt","r")
except IOError as msg:
print(msg)
else:
print("ok!")
finally:
print("finally")
[Errno 2] No such file or directory: '123.txt'
finally
try:
pass
# open("123.txt","r")
except IOError as msg:
print(msg)
else:
print("ok!")
finally:
print("finally")
ok!
finally
-
7-5 综合—抛出异常
网友评论