Python部分默认函数

1. __init__

Python在你实例化class类的时候会检查这个类中是否有init,如果有就会调用它。进行初始化。init()方法意义重大的原因有两个:

  1. 在对象生命周期中初始化;每个对象必须正确初始化后才能正常工作。
  2. _init__()参数值可以有多种形式。
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)。

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__)

结果:

__main__
Process finished with exit code 0

当这个 pcRequests.py 作为模块被调用时,则它的 name 就是它自己的名字:

import pcRequestspcRequestsc=pcRequestsc.__name__

结果:

'pcRequests'

看到这里应该能明白,自己的 name 在自己用时就是 main,当自己作为模块被调用时就是自己的名字,就相当于:我管自己叫我自己,但是在朋友眼里我就是小仙女一样。

3. __new__

  1. new方法默认返回实例对象供init方法、实例方法使用。
  2. init方法为初始化方法,为类的实例提供一些属性或完成一些动作。
  3. new方法创建实例对象供init方法使用,init方法定制实例对象。
    new方法必须返回值,init方法不需要返回值。(如果返回非None值就报错)
  4. 对象的创建和初始化过程示意图
  5. 执行流程:
    1. 创建Person类的对象student=Person(‘kb’,19),先执行等号右边的内容Person(‘kb’,19)
    2. 调用Person类中的new方法,并将Person类传给方法中的cls
    3. 创建obj对象
    4. 执行init方法,并将obj对象赋值给self
    5. 将self再传给student1对象
  6. 我们比较两个方法的参数,可以发现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应该是对该函数的重写):

class Run():
    def __init__(self,a):
        print('这是a:',a)
    def __call__(self, *args, **kwargs):
        print("这是call里的其他参数",args)
test=Run(123)
test('hehe')

输出:

这是a: 123
这是call里的其他参数: ('hehe',)

对象实例w的两种等价调用方式分别是Run.call(x)和Run(x),前者为普通的调用类方法的方式,后者为Python中的语法实现了将对象变为可调用的目的。

4.2. 类可调用的与对象可调用的不同

要注意类都是可调用的,而对象可通过call()函数来设计为可调用或者不可调用。如下代码

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()函数与元编程来实现:

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,自定义的对象如果没有迭代器 iternext 迭代器协议,使用[]运算符取对象列表或者字典中的值时,会自动调用它的 getitem 方法;可重定义此方法,使对象通过类似列表或者字典的调用方式实现迭代取值:

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
这个方法被调用
这是9
这个方法被调用
这是4
这个方法被调用
['这是0','这是1','这是2','这是3','这是4','这是5','这是6','这是7','这是8','这是9','这是10','这是11']

6. enterexit

为了支持with语句,可以在类中定义enterexit函数

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)

输出:

进入with语句
<__main__.ceshi object at 0x000001ED96D6BE88>
退出with

发表评论

邮箱地址不会被公开。 必填项已用*标注