1. __init__
Python在你实例化class类的时候会检查这个类中是否有init,如果有就会调用它。进行初始化。init()方法意义重大的原因有两个:
- 在对象生命周期中初始化;每个对象必须正确初始化后才能正常工作。
- _init__()参数值可以有多种形式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class song: def __init__(self,lyrics): self.ly = lyrics #空对象中把传来的lyrics,赋值给一个叫ly变量 print(type(self.ly)) def sing(self):#这里的self可以随便改成什么别的名字(se),下面也跟着改了就好(se.ly)。可以自己试一试,但是不能没有 for line in self.ly: #这里的ly名字不能改,改了(比如说改成sa)就提示说song这个类没有sa这个属性 print(line) def sng(sb): print(sb.ly) #这里的sb.ly还是__init__里头self.ly的值 a = song(['A','B','C']) self指向a,即self就是a,self. = a. b = song(['D','E','F']) a.sing() b.sing() a.sng() |
因为有很多种方式为init()提供参数值,对于对象创建有大量的用例,我们可以看看其中的几个。我们想尽可能的弄清楚,因此我们需要定义一个初始化来正确的描述问题区域。
2. __name__
name 是属于 python 中的内置类属性,就是它会天生就存在于一个 python 程序中,代表对应程序名称。
比如所示的一段代码里面(这个脚本命名为 pcRequests.py),我只设了一个函数,但是并没有地方运行它,所以当 run 了这一段代码之后我们有会发现这个函数并没有被调用。但是当我们在运行这个代码时这个代码的 name 的值为 main (一段程序作为主线运行程序时其内置名称就是 main)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import requests class requests(object): def __init__(self,url): self.url=url self.result=self.getHTMLText(self.url) def getHTMLText(url): try: r=requests.get(url,timeout=30) r.raise_for_status() r.encoding=r.apparent_encoding return r.text except: return "This is a error." print(__name__) |
结果:
1 2 |
__main__ Process finished with exit code 0 |
当这个 pcRequests.py 作为模块被调用时,则它的 name 就是它自己的名字:
import pcRequestspcRequestsc=pcRequestsc.__name__
结果:
'pcRequests'
看到这里应该能明白,自己的 name 在自己用时就是 main,当自己作为模块被调用时就是自己的名字,就相当于:我管自己叫我自己,但是在朋友眼里我就是小仙女一样。
3. __new__
- new方法默认返回实例对象供init方法、实例方法使用。
- init方法为初始化方法,为类的实例提供一些属性或完成一些动作。
- new方法创建实例对象供init方法使用,init方法定制实例对象。
new方法必须返回值,init方法不需要返回值。(如果返回非None值就报错) - 对象的创建和初始化过程示意图
- 执行流程:
- 创建Person类的对象student=Person(‘kb’,19),先执行等号右边的内容Person(‘kb’,19)
- 调用Person类中的new方法,并将Person类传给方法中的cls
- 创建obj对象
- 执行init方法,并将obj对象赋值给self
- 将self再传给student1对象
- 我们比较两个方法的参数,可以发现new方法是传入类(cls),而init方法传入类的实例化对象(self),而有意思的是,new方法返回的值就是一个实例化对象(ps:如果new方法返回None,则init方法不会被执行,并且返回值只能调用父类中的new方法,而不能调用毫无关系的类的new方法)。
我们可以这么理解它们之间的关系,new是开辟疆域的大将军,而init是在这片疆域上辛勤劳作的小老百姓,只有new执行完后,开辟好疆域后,init才能工作,结合到代码,也就是new的返回值正是init中self。
4. __call__
4.1. 使用示例
例类Run中展示call的使用方法,call接收对象传入的参数,可在call方法里执行某一特定对象的参数和方法(pytorch中模型正向传播的forward应该是对该函数的重写):
1 2 3 4 5 6 7 |
class Run(): def __init__(self,a): print('这是a:',a) def __call__(self, *args, **kwargs): print("这是call里的其他参数",args) test=Run(123) test('hehe') |
输出:
1 2 |
这是a: 123 这是call里的其他参数: ('hehe',) |
对象实例w的两种等价调用方式分别是Run.call(x)和Run(x),前者为普通的调用类方法的方式,后者为Python中的语法实现了将对象变为可调用的目的。
4.2. 类可调用的与对象可调用的不同
要注意类都是可调用的,而对象可通过call()函数来设计为可调用或者不可调用。如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class WaterMelon: def __init__(self): self.price = 0 self.price_per_kilo = 1.0 def __call__(self,weight): self.price = self.price_per_kilo * weight print("The pricce of WaterMelon is: ", self.price) class Apple: def __init__(self): self:price_per_kilo = 3.0 w = WaterMelon() w(6) #The pricce of WaterMelon is: 6 w.__call__(7) #The pricce of WaterMelon is: 7 callable(WaterMelon) #True callable(Apple) #True callable(w) #True callable(a) #False |
这里Apple类没有定义call()方法,因此其对象实例不是可调用对象,但是类本身是可调用的,因为调用类实际上就是返回一个实例,类似于执行init()函数。
4.3. call()函数还有其它用途
Python可以进行元编程。有一个技巧就是,当你不想让用户能够实例化一个类,而只能使用类的静态方法的时候,你可以通过结合call()函数与元编程来实现:
1 2 3 4 5 6 7 |
class NoInstances(type): def __call__(self, *args, **kwargs): raise TypeError("Class is not allowed to be instantiated") class Cherry(metaclass=NoInstances): @staticmethod def about(): print("樱桃") |
现在c = Cherry()
会报错,而c = Cherry().about()
可正常执行
5. __getitem__
例类Tag,自定义的对象如果没有迭代器 iter 、next 迭代器协议,使用[]运算符取对象列表或者字典中的值时,会自动调用它的 getitem 方法;可重定义此方法,使对象通过类似列表或者字典的调用方式实现迭代取值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class Tag: def __init__(self,id): self.list=[] self.id=id def __getitem__(self, item): self.list=[] for i in range(self.id): self.list.append('这是'+str(i)) print('这个方法被调用') return self.list[item] a=Tag(12) print(a.list) print(a[1]) print(a[2]) print(a[9]) print(a[4]) print(a.list) |
输出:
1 2 3 4 5 6 7 8 9 10 |
[] 这是1 这个方法被调用 这是2 这个方法被调用 这是9 这个方法被调用 这是4 这个方法被调用 ['这是0','这是1','这是2','这是3','这是4','这是5','这是6','这是7','这是8','这是9','这是10','这是11'] |
6. enter和exit
为了支持with语句,可以在类中定义enter和exit函数
1 2 3 4 5 6 7 8 9 10 11 |
class ceshi(): def __init__(self): pass def __enter__(self): print('进入with语句') return self def __exit__(self,*args): print('退出with') with ceshi() as c: print(c) |
输出:
1 2 3 |
进入with语句 <__main__.ceshi object at 0x000001ED96D6BE88> 退出with |
微信赞赏
支付宝赞赏