Python中__init__.py以及__new__() __init__()和__call__()的简单总结

 

     在实际的NLP项目中,看到了一种标准的封装引用导包和比较常用的类初始化以及魔术函数代码体系,特作总结。

1、__init__.py

看具体的代码包结构:

Python中__init__.py以及__new__() __init__()和__call__()的简单总结_第1张图片

红色方框中__init__.py的作用是什么呢?

首先看看evaluation包中的__init__.py的内容:

Python中__init__.py以及__new__() __init__()和__call__()的简单总结_第2张图片

到底起什么样的作用呢?

主要是起到一个简化导包的操作,同时起到一个管理控制的作用。当我们没有在__init__.py做类的初始化的话,在包外应用一些类的时候,代码就要写的很繁杂。图中实例:

Python中__init__.py以及__new__() __init__()和__call__()的简单总结_第3张图片

需要在mainPackage中调用package1、package2中的类,没有在__init__.py做类的初始化的话就需要些如下代码,同时还可能存在重名问题。

from pythonProjectStrcture.package1.p1class1 import p1class1,whole_name  #手动导包 遇到命名一样的类,和方法就要重命名
from pythonProjectStrcture.package2.walke import walke,whole_name

p1class1('第一', '第二')
p1class1(whole_name)

假如做了初始化的话,就只需要:

from pythonProjectStrcture import package1,package2#使用了__init__.py的作用就很方便的处理导包问题
p1_c1 = package1.p1class1('第一', '第二')
p1_c1.function1('第三')
p1_c2 = package1.p1class2('第四','第五')
p1_c2('key1','key2')

把包引用进来,然后再代码用在引用。这样的好处是,不管函数或者变量是不是重名,都可以调用出来,初始设计类中变量名和方法的时候限制就少一点。以后在做标注的封装的时候,可以考虑这样组织项目结构。

2、__new__() __init__()

这是三个方法是python中比较特殊的方法。

__new__()方法:它的作用就是进行对象的创建,这个差不多是python中最开始调用的方法。

__init__()方法:这个是在对象创建以后进行初始化过程中运行的,作用有点类似JAVA中的getter和setter方法的作用。就是初始化对象的一些属性。

 

具体的使用看代码:

class p1class1():
    def __init__(self,param1,param2):
        print('进入__init__函数中了')
        self.param1=param1
        self.param2=param2
        self.param3='package1class1的第三个属性'
        print('出__init__函数中了')
    def function1(self,param):
        print('进入function1函数中了')
        print('包1中类1的函数1打印出:',param)
        print('包1中类1的函数1打印出__init__传入的属性:'+ self.param1+self.param2)
        print('包1中类1的函数1打印出__init__写死的属性: '+self.param3)
        print('出function1函数中了')
        return '出function1函数中了'
    def __new__(cls, *args, **kwargs):
        print('进入__new__()函数')
        return super(p1class1,cls).__new__(cls)
if __name__ == '__main__':
    p=p1class1('第一','第二')
    p.function1('第三')

结果输出:

进入__new__()函数
进入__init__函数中了
出__init__函数中了
进入function1函数中了
包1中类1的函数1打印出: 第三
包1中类1的函数1打印出__init__传入的属性:第一第二
包1中类1的函数1打印出__init__写死的属性: package1class1的第三个属性
出function1函数中了

可以看到p=p1class1('第一','第二')代码执行后,最先执行的就是__new__(cls, *args, **kwargs),然后再是__init__(self,param1,param2)函数,最后才是其他的方法。注意到这里的执行顺序,先创建然后再初始化。另外,__new__函数是非必须的,我们自己定义class里面不写__new__方法,对象依然能被创建和初始化,它可以自动被调用。

__new__方法中的参数是cls,而__init__中的是self。当我们自己定义了__new__方法的时候,一定要返回一个super(class,cls).__new__(cls)这样的方法,不然会报错的。如下代码中__new__方法不返回内容就不会执行__init__()方法。

 

class p1class1():
    def __init__(self,param1,param2):
        print('进入__init__函数中了')
        self.param1=param1
        self.param2=param2
        self.param3='package1class1的第三个属性'
        print('出__init__函数中了')
    def function1(self,param):
        print('进入function1函数中了')
        print('包1中类1的函数1打印出:',param)
        print('包1中类1的函数1打印出__init__传入的属性:'+ self.param1+self.param2)
        print('包1中类1的函数1打印出__init__写死的属性: '+self.param3)
        print('出function1函数中了')
        return '出function1函数中了'
    def __new__(cls, *args, **kwargs):
        print('进入__new__()函数')
if __name__ == '__main__':
    p=p1class1('第一','第二')
    p.function1('第三')
进入__new__()函数
Traceback (most recent call last):
  File "F:/PycharmWorkspace/Python/pythonFundation/pythonProjectStrcture/package1/p1class1.py", line 34, in 
    p.function1('第三')
AttributeError: 'NoneType' object has no attribute 'function1'

报错!由于__new__()方法没有返回对象,__init__()方法得不到self的参数,因此__init__方法不执行。

在使用的时候,除非有很强的必要性,都不要自己去重写__new__()方法,一是没必要,而是容易出错。

3、__call__()

这个方法也是比一个特殊但是比较常用的方法,在class对象中写这个方法后,class就变成了callable了。

看代:

class p1class2():
    def __init__(self,param1,param2):
        self.param1=param1
        self.param2=param2
        self.param3='package1class1的第三个属性'
    def function1(self,param):
        print('包1中类2的函数1打印出:',param)
        print('包1中类2的函数1打印出__init__传入的属性:'+ self.param1+self.param2)
        print('包1中类2的函数1打印出__init__写死的属性: '+self.param3)

    def __call__(self,key1,key2):
        print('包1中类2的函数1打印出:__call__ 魔法函数  :%s %s '%(key1,key2))
        return 1



#类外调用

p1_c2 = package1.p1class2('第四','第五')
p1_c2('key1','key2')

结果如下:

进入__new__()函数
进入__new__()函数
包1中类2的函数1打印出:__call__ 魔法函数  :key1 key2 

代码中

p1_c2 = package1.p1class2('第四','第五')

放回的是一个对象,因为写入了__call__()魔法函数,这就使得

p1_c2对象可以像函数一样那要使用,引入自己的参数。
p1_c2('key1','key2')

这样的设计,给编程中带入了很高的灵活性,同时也需要一定的甄辨性。单看p1_c2('key1','key2')你不知道

p1_c2是一个函数还是一个对象,就有可能在出现Bug的时候很难找到原因。

参考文章:

https://www.jb51.net/article/147544.htm

https://www.cnblogs.com/aomi/archive/2017/08/01/7267008.html

你可能感兴趣的:(Python总结)