目录
🏆一、前言
🏆二、类
🚩1、面向对象到底是什么
🚩2、数据成员and访问,汉堡店大升级(超难)
👍①、类变量(超难)
👍②、实例变量
🚩3、关于类的限制
🚩4、父类和子类,再开一家店
👍①什么是父类子类
👍②、方法重写
👍③、多继承
🚩5、类的内置方法
🚩6、静态类
🚩7、关于方法的返回值
🚩8、装饰器and各种方法
👍①、静态方法
👍②、实例方法
👍③、类方法
🏆三、尾声
本文为原创文章,抄袭必究!
🏆一、前言
为了排名现在都不择手段了,我也要卷起来。
12月发了5篇文章,和其他大佬比起来还是太逊了,所以我决定当老六:全部存在1月发。
上一篇文章讲了类的一半,怕你们学不懂就分了两篇文章,其实我也学不动哈哈哈。
类要学的东西实在太多了,一篇文章都学不完。
这篇文章会对类的用法进行详细讲解。写作不易,支持一下~(亿年客套话)
另外,大家元旦快乐呀~
🏆二、类
建议学习时长:学他个两天半(我是ikun)。
🚩1、面向对象到底是什么
这里先纠正一下,详解(4)类的命名是不规范的,大家不要学习,建议使用“大驼峰命名法”。
例如,yigelei最好命名成YiGeLei,这就是大驼峰命名法。
就算不这样命名,首字母也要大写。
有人要问了:为啥你要不规则命名呢?
因为…我是在中午写的这篇文章,早晚会出事(bushi。
python中万物皆可对象,类就是自己创建一个对象。
我们上一篇文章浅接触到了面向对象,我们这里来深究一下。
比如说,现在ikun汉堡店要给客人做一个汉堡。
面向过程,就是注重过程。他在给客人做汉堡的时候,会是这样:
欢迎客人,点餐,做汉堡,给客人,付钱,给好评,欢迎下次光临。
面向对象,就是注重对象,python就是面向对象。他在给客人做汉堡的时候,会先揪出来两个对象:老板和客人,然后给老板加一下属性和方法,再给客人加一下属性和方法,成为这样:
老板欢迎客人,客人点餐,老板做汉堡,老板把汉堡给客人,客人付钱并且给五星好评,老板欢迎下次光临客人。
这样讲就清晰一点了。
面向对象要弄出各个类,之后创建几个方法,对象分别调用这几个方法。
我们转换到python里面的类:
class ikun汉堡店:
桌子=10个
椅子=20个
def 欢迎客人(self):
print("欢迎客人,请点餐")
def 点餐(self):
print("我要一个汉堡")
def 做汉堡(self):
烤肉
夹在一起
给客人
def 给好评(self):
print("五星好评")
def 欢迎下次光临(self):
print("欢迎下次光临!")
老板=ikun汉堡店()
客人=ikun汉堡店()
老板.欢迎客人()
客人.点餐()
老板.做汉堡()
客人.给好评()
老板.欢迎下次光临()
在真正使用的时候肯定会有变量,例如空闲桌子,空闲凳子,汉堡材料等等,这里做一个省略。
有人可能认为面向对象比面向过程繁琐,是的,但是挡不住面向对象的条理清晰。
如果我们这个世界真像某些人说的那么玄乎一样是代码写成的,那也是用的面向对象编程。
🚩2、数据成员and访问,汉堡店大升级(超难)
三个新概念隆重登场:数据成员,类变量,实例变量。
类里面的函数叫做实例方法,类里面的变量呢?我们详解(4)已经接触过了,这叫做数据成员。
数据成员分为两种:
类变量,顾名思义就是一个类的变量,在一个类里声明(不加self的),这个类的所有实例都享有。
就相当于汉堡店目前的配置,所有客人都会享受这样的配置。
实例变量,顾名思义就是一个实例的变量,在init方法里声明,用self绑定,为每个实例独有。
就相当每个客人进店之后的不同需求,都是独自的不同的需求。
👍①、类变量(超难)
详解(4)那个程序中的banji就是类变量。
类变量,顾名思义就属于一个类的变量,在类里面创建。而类的所有实例全部享有这个变量。
例如ikun汉堡店的桌子,所有客人都能用。
无论什么时候,类变量都不能直接访问,通常用类名.类变量来访问,其他访问方法见下。
class IkunHanBaoDian:
zhuozi=10#zhuozi就是类变量
def __init__(self):
try:
print("1.",zhuozi)
print("可以在__init__里直接访问类变量")
except:
print("不能在__init__里直接访问类变量")
try:
print("2.",IkunHanBaoDian.zhuozi)
print("可以在__init__里用 类名.类变量 的形式访问类变量")
except:
print("不可以在__init__里用 类名.类变量 的形式访问类变量")
def abc(self):
try:
print("3.",zhuozi)
print("可以在方法里直接访问类变量")
except:
print("不可以在方法里直接访问类变量")
try:
print("4.",IkunHanBaoDian.zhuozi)
print("可以在方法里用 类名.类变量 的形式访问类变量")
except:
print("不可以在方法里用 类名.类变量 的形式访问类变量")
keren=IkunHanBaoDian()
keren.abc()
try:
print("5.",zhuozi)
print("可以在外部直接访问类变量")
except:
print("不能在外部直接访问类变量")
try:
print("6.",IkunHanBaoDian.zhuozi)
print("可以在外部用 类名.类变量 的形式访问类变量")
except:
print("不能在外部用 类名.类变量 的形式访问类变量")
try:
print("7.",keren.zhuozi)
print("可以在外部用 实例名.类变量 的形式访问类变量")
except:
print("不能在外部用 实例名.类变量 的形式访问类变量")
try:
print("8.",keren.zhuozi)
print("使用方法后可以用 类名.类变量 的形式访问类变量")
except:
print("使用方法后不能用 类名.类变量 的形式访问类变量")
输出:不能在__init__里直接访问类变量
2. 10
可以在__init__里用 类名.类变量 的形式访问类变量
不可以在方法里直接访问类变量
4. 10
可以在方法里用 类名.类变量 的形式访问类变量
不能在外部直接访问类变量
6. 10
可以在外部用 类名.类变量 的形式访问类变量
7. 10
可以在外部用 实例名.类变量 的形式访问类变量
8. 10
使用方法后可以用 类名.类变量 的形式访问类变量
我们用了一连串的try-except语句,查看那些访问是不报错的,就是可以访问的。
从上述例子中可以得知,在任何时候用类名.类变量的形式都能访问类变量。
但是实例名.类变量也可以访问,这是什么玩意儿?
让我们再看一个例子。
class IkunHanBaoDian:
zhuozi=10
keren=IkunHanBaoDian()
keren.zhuozi=9
print(keren.zhuozi)
print(IkunHanBaoDian.zhuozi)
输出:9
10
《皇帝的桌子》这特喵的是平行时空。
接下来,就是要锻炼在代码出现出乎意料的状况的时候进行检验与理解的能力。
我们如果把zhuozi=10去掉,程序也能照常运行,说明keren.zhuozi=10是新建了一个变量。
由于列表在改变之后地址不会变,我们将zhuozi换成一个列表:
class IkunHanBaoDian:
a=[]
keren=IkunHanBaoDian()
keren.a=[3]
print(id(keren.a))
print(id(IkunHanBaoDian.a))
输出:140430954056128
140430954692288
由这个例子可以看见,keren.a与IkunHanBaoDian.a不是同一个变量。
是不是感觉越来越玄乎了?
这里提前说一下,实例名.变量名是实例变量的访问形式。
所以,程序把a当成了一个实例变量,再次新建了另一个实例变量。
那么上面的代码就好理解了。keren.zhuozi=9是客人有九个桌子,而不是ikun汉堡店有9个桌子。
你们砸的是客人的桌子,关我ikun汉堡店什么事?
所以,结论可以改了。实例名.类变量的访问形式不成立。
在任何时候,我们都可以通过 类名.类变量 的形式访问一个类变量。
👍②、实例变量
接下来,我们学习实例变量。
实例变量是属于每一个实例的变量。
这么说吧,( self前缀 或者 实例名前缀用来改变实例变量 的)实例变量就是汉堡店的点餐机器,获取每一个用户的话语并且给每一个用户分发一个保存话语的变量。
创建方式:大部分在init或者实例方法里创建,用 self.实例变量= 或者实例名.实例变量= 的形式。
class IkunHanBaoDian:
def __init__(self,hua):
self.huayu=hua
def abc(self,hua):
self.huayu2=hua
keren=IkunHanBaoDian("老板我要牛肉汉堡")
keren.abc("老板我要田园汉堡")
print(keren.huayu)
print(keren.huayu2)
输出:老板我要牛肉汉堡
老板我要田园汉堡
来跟着程序执行脚步捋一下。
首先,创建一个实例为keren,执行init方法,创建一个实例变量huayu2保存说的话。
之后执行abc方法,创建一个实例变量huayu2保存说的话。
最后通过 实例名.实例变量 的格式输出这个实例变量。
有人可能要问了:self.实例变量和实例名.实例变量,这两个格式有什么区别呢?
没有区别,只是一个在类里面创建访问,一个在类外面创建访问而已。上面的程序,实例名.实例变量其实就是创建了一个实例变量,因为作用域不同,所以可以与类变量重名。
但是:实例名.实例变量可要分清楚一下。
实例名.实例变量这种形式创建的话,实例变量只能是在外面创建的,也就是说,他只能给一个实例享有。这就不是汉堡店的点餐机器了。这就像点餐的时候有的用户可能有备注,有的用户没有,如果有备注我们才给这个实例分发变量。
我们可以得出结论了:
实例变量属于每一个实例,用 self.实例变量的格式在内部创建和访问,用 实例名.实例变量 的形势在外部创建和访问。如果用实例名.实例变量的形式创建的话,这个实例变量仅有这一个实例享有。
看不懂吧?重新看去!
🚩3、关于类的限制
当客人离开汉堡店的时候,我们要删除这个客人。
删除可不是给客人kill了啊,是这个客人离开了ikun汉堡店。
其实,类的实例他是删除不了的,上网找了一圈都没找到。
其实,类的实例你假装他是自动删除的就行了,反正类是不能获取所有实例的,这就像一个人干完一件事,你要让他待用,等再次需要的时候让这个人去干其他事,还能给他kill了?
类不能获取所有实例同理,或许可以,但是上网转了半天都没有找到一个合理的教程。but,我们可以手动获取。
这里我们要了解一下,前缀可以有好几个点。比如列表a,他是在类b里面声明的一个类变量,我们在给列表a添加元素的时候就可以:
b.a.append()
不过顺序可不能搞反,程序看代码是从左往右看的,程序先看到b.a,知道你要调用类变量a,之后再让a添加。如果你写a.b.append(),就会报错。
那么,我们可以在印象中删除。
我们通过一个列表来储存每一个实例。同时可以储存别的平时不能储存的东西。
这样,就完美破解了不能删除、不能获取所有实例的问题。
from random import choice
class IKHBD:
zhanyong=[]
buzhanyong=[1,2,3,4,5,6,7,8,9,10]
def __init__(self):
self.hao=choice(IKHBD.buzhanyong)
IKHBD.buzhanyong.remove(self.hao)
IKHBD.zhanyong.append(self.hao)
def likai(self,zhuowei):
IKHBD.zhanyong.remove(zhuowei)
IKHBD.buzhanyong.append(zhuowei)
IKHBD.zhanyong.sort()
IKHBD.buzhanyong.sort()
print("现在的被占用座位有:",IKHBD.zhanyong)
print("空闲座位有:",IKHBD.buzhanyong)
c=IKHBD()
d=IKHBD()
e=IKHBD()
f=IKHBD()
c.likai(c.hao)
d.likai(d.hao)
e.likai(e.hao)
输出:现在的被占用座位有: [3, 4, 7]
空闲座位有: [1, 2, 5, 6, 8, 9, 10]
现在的被占用座位有: [3, 7]
空闲座位有: [1, 2, 4, 5, 6, 8, 9, 10]
现在的被占用座位有: [3]
空闲座位有: [1, 2, 4, 5, 6, 7, 8, 9, 10]
这是一个简单的座位占用统计程序。
思路:
第一行:导入随机数模块里的choice,回顾一下作用:在括号里所给的数组里随机选一个。
第二行:新建一个类ikun汉堡店,这里简写成IKHBD。
第三、四行:新建两个列表分别储存被占用和不被占用的座位。
第五行:新建init方法。
第六行:新建实例变量hao为未被占用座位列表中随机一个。
第七行:储存不占用座位的列表删除这个座位号。
第八行:储存占用座位的列表添加这个座位号。
第九行:新建实例方法likai,并且获取参数:离开客人的座位号。
第十行:储存占用座位的列表删除这个座位号。
第十一行:储存不占用座位的列表添加这个座位号。
第十二、十三行:将两个列表正序排序,美观一点。
第十四、十五行:输出占用座位和不占用座位。
第十六到十九行:四个客人来到汉堡店。
第二十到二十二行:三个客人依次离开。
我们在对一个问题一筹莫展的时候,可以根据自己的需求调整思维。这个例子的固化思维便是删除实例和添加实例,我们不用他,专门新建一个列表。这种逆向思维是在编程中很常见的。
这样的话,获取所有实例也可以用这种思维。
🚩4、父类和子类,再开一家店
👍①什么是父类子类
接下来,又是两个新的概念:父类,子类。
这么说吧,父类就是ikun汉堡店主店,子类就是ikun汉堡店的其他店,子类拥有父类的属性和方法。
创建一个子类的时候,要在后面加上括号,声明他的父类:
class IkunHanBaoDian:
zhuozi=10
dengzi=20
def __init__(self):
print("只因你太美")
def abc(self):
print("小黑子树枝666")
class IkunHanBaoDian2(IkunHanBaoDian):
pass
print(IkunHanBaoDian2.zhuozi)
print(IkunHanBaoDian2.dengzi)
keren1=IkunHanBaoDian2()
keren1.abc()
输出:10
20
只因你太美
小黑子树枝666
由此可见,子类会继承父类的属性和方法。
接下来给大家思考一下:同样的实例有可能存在于两个类吗?
class IkunHanBaoDian:
def __init__(self):
print("只因你太美")
class IkunHanBaoDian2(IkunHanBaoDian):
pass
keren1=IkunHanBaoDian()
keren1=IkunHanBaoDian2()
输出:只因你太美
只因你太美
输出了两次。
这时候有两种可能:
1,两个keren不是一个变量。
2,keren先进了第一家店,再进了第二家店。
我们查看全局命名空间,输出有这么一段:
'keren1': <__main__.IkunHanBaoDian2 object at 0x7ff6f695fb50>
所以,是keren先进了第一家店,再进了第二家店,因为没有第二个keren了。
这证明:一个实例不能同时在两个类里面,他的父类也不行。
👍②、方法重写
但是父类和子类肯定不完全一样,比如你的另外一个ikun汉堡店装修到一半没钱了,只好少装一个凳子或者桌子;或者你的第一个汉堡店实行了某个活动,但是第二个汉堡店不想实行,你可以改他。
这在python中叫做方法重写。
看例子:
class IKHBD:
zhuozi=10
def abc(self):
print("汉堡店新活动:买一送一!")
class IKHBD2:
zhuozi=8
def abc(self):
print("我们店没有这项活动")
a=IKHBD()
a.abc()#子类改变方法之后父类没有改变,输出“汉堡店新活动,买一送一!”
b=IKHBD2()
b.abc()#子类已经改变方法,覆盖了父类,输出“我们店没有这项活动”
print(IKHBD.zhuozi)#子类改变变量父类没有改变,输出10
print(IKHBD2.zhuozi)#子类改变了变量,覆盖了父类,输出8
还是那句话,理解了这个例子你就学会了。
另外,当init构造方法被重写,就不会执行父类的init。
👍③、多继承
我们可以让类继承多个类。
啥?你问为什么一个“子”能有多个“父”?
我们不要在意这些细节。方法就是在括号里填两个及以上的父类。
class IKHBD1:
def abc(self):
print("只因你太美")
class IKHBD2:
def aaa(self):
print("你干嘛哈哈诶呦")
class IKHBD3(IKHBD1,IKHBD2):
pass
keren=IKHBD3()
keren.abc()
keren.aaa()
输出:只因你太美
你干嘛哈哈诶呦
这就是多继承,应该很好理解。
我们来猜一下:如果多个父类都有init方法,子类怎么执行?
A,执行第一个父类
B,执行最后一个父类
C,从前往后依次执行
class IKHBD1:
def __init__(self):
print("只因你太美")
class IKHBD2:
def __init__(self):
print("你干嘛哈哈诶呦")
class IKHBD3(IKHBD1,IKHBD2):
pass
keren=IKHBD3()
输出:只因你太美
哈哈,让我看看谁选错了,正确答案选A。
所以如果多个父类都有init,那么会执行第一个父类的init方法。
🚩5、类的内置方法
类有一些内置的方法。要么说名字左右两边有下划线的就是很难懂的,这些都有下划线。init就是一个。
这些内置方法,有的很简单,有的直接改变了使用方法,很难。
内置方法有很多很多,这里只讲几个常见的,剩下的专门来一篇文章讲。
注意:后面的程序与讲解我们就不用汉堡店的思维了,我们尝试脱离这种思维,真正去学习类,毕竟是真的难编哈哈哈。
1:__dict__,他一直保存着类的属性。
使用格式:类名.__dict__
实例:
class IKHBD:
pass
print(IKHBD.__dict__)
输出:{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'IKHBD' objects>, '__weakref__': <attribute '__weakref__' of 'IKHBD' objects>, '__doc__': None}
2:__call__,比较牛掰,可以把实例当成函数使用,每次用函数的形式调用一个实例,都会执行call里面的程序。
格式:
def __call__(self,其他参数):
函数体
class IKHBD:
def __call__(self):
print("欢迎光临!")
keren=IKHBD()
keren()#call把实例变成函数,可以这样调用,执行call里面的脚本
输出:欢迎光临
3:__new__,这个是老大,执行顺序比init都靠前,在他面前init啥也不是。
new可以构造一个实例,不知道构造实例啥意思?慢慢学!
接下来,我们通过几个例子来了解new。
格式:
def __new__(cls,其他参数):
函数体
例①、有new在,init闭嘴
class IKHBD:
def __new__(cls):
print("5")
def __init__(self):
print("6")
keren=IKHBD()
输出:5
从这个例子可以看出来,当new存在的时候,init不敢说一句话,纯属大佬和小弟。
例②、一串神奇代码
一般在new的结尾,要加这么一段神奇的代码:
return super().__new__(cls)
用处后面会讲加就完了。
例③、大佬让init说话
我们也可以让init“说话”。
上面的那串神奇代码加上去之后,init就能说话了。
class IKHBD:
def __new__(cls):
return super().__new__(cls)
def __init__(self):
print("小黑子树枝666")
a=IKHBD()
输出:小黑子树枝666
例④:new后面的cls是什么
又是新概念:在类里面有两个方法,实例方法和类方法。
顾名思义,实例方法是针对实例的,类方法是针对类的。怎么区分呢?很简单:
实例方法要传入self,类方法要传入cls。
例如init,实例被创建之后运行,那他就是实例方法,加self的。
实例方法后面的self保存着每一个实例,类方法后面的cls呢?
我们试着访问这个cls。
class IKHBD:
def __new__(cls):
print(cls)
a=IKHBD()
输出:<class '__main__.IKHBD'>
类方法保存的是这个类,嗯,合理。
但是就算大佬让init说话,他也不能在cls前面。
例⑤:神奇代码他是啥
我们来探究上面的一串神奇代码保存了啥。
class IKHBD:
def __new__(cls):
a=super().__new__(cls)
print(a)
a=IKHBD()
输出:<__main__.IKHBD object at 0x7f1eabe398b0>
返回的是一个实例。
死概念:
new返回的是一个实例,会让init去处理。
这就能解释为啥没神奇代码,init就不运行了,神奇代码就是返回实例让init去运行的,不给实例运行不了。
有人要问了:诶诶诶,那init是怎么接收的呢?
接受实例的,他就是宇宙无敌超级惊天动地噼里啪啦横空出世非常牛掰的——self。
我们看看他们两个id一不一样。
class IKHBD:
def __new__(cls):
a=super().__new__(cls)
print(id(a))
return a
def __init__(self):
print(id(self))
a=IKHBD()
输出:140003344179696
140003344179696
所以,可以得出结论:
new构造的实例会传递给init那边的self。
我们试着返回一些奇怪的东西。
经过我自己的一些实验,分别返回了变量、其他类、其他类的实例。得出结论:
这些都是可以返回的,但是init就运行不了了,罢工了。
例⑥、重写new
new的重写很迷糊,看下面。
class IKHBD:
pass
class IKHBD2(IKHBD):
def __new__(cls):
return super().__new__(cls)
def __init__(self):
print("只因")
f=IKHBD2()
f=b()
输出:
init居然又罢工了。
研究这个,我们先了解一下执行顺序。
class IKHBD:
def __new__(cls):
print("只因")
class IKHBD2(IKHBD):
def __new__(cls):
print("只因你太美")
return super().__new__(cls)
e=IKHBD2()
输出:只因你太美
只因
奇迹出现了,父类的new没有被重写。
new其实不能被重写。当子类的new执行完后自动执行父类的new。
我们接着回顾到上一题。当程序执行完子类,是会执行父类的,所以神奇代码传递实例就迷迷糊糊传到了父类那边,估计是因为程序以为你要在父类叠加构造一遍实例。
其实,神奇代码的传递不分是不是init,他只会自动传递给下一个执行的方法,所以传给父类的new了,而父类就没有代码接着传递了。
咱就是说这个new啥也不分。这么说吧,神奇代码就是接力棒,他会把接力棒抛向下一个方法,管他有没有接错人。
解决方法,就是给父类也加上神奇代码。
class IKHBD:
def __new__(cls):
print("只因")
return super().__new__(cls)
class IKHBD2(IKHBD):
def __new__(cls):
print("只因你太美")
return super().__new__(cls)
def __init__(self):
print("init执行")
e=IKHBD2()
输出:只因你太美
只因
init执行
这部分疑惑的东西有很多,总结一下:
神奇代码会将实例传递给下一棒,下一棒就是接下来要执行的方法,but可能会认错人。因为new不能被重写,如果父类有new,那么实例就会传递给父类。
斯…咋像迭代器一样呢?
例⑦、参数界的大佬
在用new方法的时候,你经常会见到两个东西、
这就是代码界之参数界的两个传奇——他们在代码界叱咤风云…
(啪!)
啊,好的,我们要用上*arg和**kwargs。
详解3里面解释过,*是多余参数组成元组,**是组成字典,参数必须以关键字参数的形式。
至于他俩的名字···都是程序员约定俗成的,你可以改,但会获得大佬的鄙视。
这应该在学函数的时候讲,但是还是new运用比较多(绝对不是作者当时不会)。
来看例子:
def a(b,*args,**kwargs):
print(b,end=" ")
print(args,end=" ")
print(kwargs)
a(1,2,3,4,5,c=6,d=7,e=8)
输出:1 (2, 3, 4, 5) {'c': 6, 'd': 7, 'e': 8}
从这个例子可以看出来,程序会先对应其他参数,之后把普通参数保存到元组,关键字参数保存到字典,两者有别。
这样的话,无论传入什么参数都能保存了。
new的学习就到此结束了,有点杂乱,建议收藏。
4.__str__,在平常,我们print实例会输出地址,而加上str之后,则会调用str里面的语句,输出他的返回值。
格式:
class 类名:
def __str__(self):
函数体
看个例子:我们试着给str加参数。
class IKHBD:
def __str__(self,aaa=0):
print(aaa)
return "小黑子树枝666"
a=IKHBD()
print(a)
输出:0
小黑子树枝666
可以加参数。但是,该怎么填参数?
好吧我也不知道,网上也没有相关的资料,如果有大佬知道请在评论区指正,谢谢。
反正用这玩意儿不咋需要参数,就不学了(bushi。
那么,如果没有返回会怎么样呢?
我们试着不给str加返回值。
class IKHBD:
def __str__(self):
pass
a=IKHBD()
print(a)
输出:Traceback (most recent call last):
File "<string>", line 5, in <module>
TypeError: __str__ returned non-string (type NoneType)
你在想什么?
另外,返回也有讲究,必须是字符串,不然print输出不了。
等等,我知道你在想什么。
如果call和str一起用呢?
这样实例就同时拥有两个功能了。
这只是最常见的四个内置方法,其他内置方法,我会在下一篇文章:详解(5.5)更新。太特喵的多了,写太多质量分说不定还会扣。
🚩6、静态类
我们之前学的都是动态类,其实还有静态类,更简单一点。
它俩最大的区别是:静态类的方法都是类方法,参数不用加self,并且要用类名.方法调用。
class IKHBD:
def __init__():
print("6")
def abc():
print("7")
try:
a=IKHBD()
except:
print("静态类不能创建实例")
IKHBD.abc()#正确形式:类名.方法名形式调用函数
输出:静态类不能创建实例
由此可见,静态类是不能创建实例的。
其实,静态类就是很多函数的封装,通过类名.方法名的形式访问,不常用,就写十几行代码还再封装一遍,就算往以后想咱还没学到那一步,如果你是新手还非要用它,纯属闲得慌。
静态类里面的方法叫做静态方法,这点后面讲。
如果调用init方法,得用IKHBD.__init__()。
🚩7、关于方法的返回值
方法还有一种使用方法,就是返回值。一般的方法也是可以有返回值的。
我们可以通过实例获取返回值,也可以指定一个变量为这个方法的返回值。
如果我们直接print方法会怎么样?
class IKHBD:
def abc(self):
return "你干嘛"
print(IKHBD.abc)
输出:<function IKHBD.abc at 0x7fa75d07adc0>
还会是这一串地址。
这时候,我们就要创建一个实例来调用这个方法。其实也是可以用
class IKHBD:
def abc(self):
return "树枝"
a=IKHBD()
print(a.abc())
输出:树枝
这时候,返回值就生效了。
除此之外,我们还可以用变量保存返回值。
class IKHBD:
def abc(self):
return "树枝"
a=IKHBD().abc()
print(a)
输出:树枝
我们给一个方法or函数加括号的时候意思就是调用并且获取他的返回值。这里的.abc()就是调用IKHBD这个类的abc函数,并且用变量a储存他的返回值。
🚩8、装饰器and各种方法
别急别急,这是最后一部分,学习马上就要结束了。
方法也是分静态和动态的。静态类的所有方法都是静态方法。我们来了解一下这些方法。
还有两类,就是实例方法和类方法。接下来我们挨个学习。
这部分的教程网上是真的少,所以可能有一些错误请见谅。
👍①、静态方法
我们先来了解一个神奇的东西。他,在类和函数里面是顶尖的存在,所有人都要臣服于他之下,他就是···
(啪啪啪!)
啊,好的,他就是@。@后面跟一些文字可以产生不同的效果,这叫做装饰器。
这只是他在类里面最简单的用法,在函数里面也可以用装饰器且用法很多。
如果我们想让方法变成静态,就给他加上@staticmethod。
那么静态方法是什么呢?
这是从chatGPT那边来的资料:
真香~
静态类里面的所有方法都是静态方法,而用@staticmethod会将其中一个方法变为静态。静态方法和实例完全没有关系,用类名.变量名来调用。你可以把他看成一个单独的函数,只不过和类有关系而已。
看例子:
class IKHBD:
@staticmethod
def abc():
print("小黑子现实生活中一定挺紫杯吧")
a=IKHBD()#仍然可以创建实例
try:
a.abc()
except:
print("不能用实例名.变量名的形式调用静态方法")
IKHBD.abc()#静态类调用方法的形式
输出:小黑子现实生活中一定挺紫杯吧
小黑子现实生活中一定挺紫杯吧
@staticmethod将方法变为了静态。
静态方法其实也可以用实例调用,只不过你要是这么用迟早会出事,最好用类来调用。
👍②、实例方法
实例方法是什么呢?我们可以通过上文说的实例变量举一反三。
实例变量是属于每一个实例的变量,实例方法就是属于每一个实例的方法。
他最主要的特征就是加self。
通常情况下,一个类里面的方法默认都是实例方法,就是我们平常学的,十分常用,这里就不讲了。
👍③、类方法
类方法,顾名思义是属于类本身的方法。
有人说:诶诶诶,这套话不是已经在静态方法里用过了吗?而且init构造也差不多啊???
确实,类方法和静态方法极为相似。类方法的装饰器就是@classmethod。
类方法不用self,但是用cls。
而init构造可以说就和类方法一样了,但还是有点区分。我们把概念缩水缩水再缩水,得到了这么个概念:
类方法与静态方法相似,唯一不同的地方就是:cls。
这样是不是简洁多了?其实这仨玩意儿本身就可以放在一起区分。
静态方法对应@staticmethod,可不加任何参数,通过类调用,实例调用其实也行但会出事。
实例方法为默认方法,第一个参数必须为self,通过实例调用。
类方法对应@classmethod,第一个参数必须为cls,通过类调用。
愣着干啥?收藏啊!
🏆三、尾声
类的学习已经到此结束了,其实还有一些知识,但是太tnnd多了写不完了。
你以为你行了?不,你这仅仅是入门成功。后面就要多和第三方模块、算法啥的打交道了。
这篇文章写了快半个月,三连支持一波吧~
元旦快乐,祝大家新的一年里万事如意,写代码永无bug,写文章灵感多多~
散会!
----------------------------------------------------end----------------------------------------------------