python中class使用总结

一 内部调用和__call__()

详细说明参考:https://blog.csdn.net/weixin_43593330/article/details/108174666
注意:双前导和双末尾下划线__var__在python中用于特殊用途,具体参考:https://www.runoob.com/w3cnote/python-5-underline.html,但是不是所有的此类都可以使得一个对象可以被调用,python中默认实现了__call__,pytorch的torch.utils.data.Dataset 中实现了__getitem__,keras的keras.utils.Sequence中实现了__getitem__。

Python 中下划线的 5 种含义:单前导下划线_var,单末尾下划线var_,双前导下划线__var,双前导和末尾下划线__var__,单下划线_ 参考:https://www.runoob.com/w3cnote/python-5-underline.html。

Python中的双下划线__xxx__(魔术方法) 参考:https://www.cnblogs.com/bigtreei/p/7930511.html

call()是一种magic method,在类中实现这一方法可以使该类的实例(对象)像函数一样被调用。默认情况下该方法在类中是没有被实现的。

call()方法的作用其实是把一个类的实例化对象变成了可调用对象,只要类里实现了__call__()方法就行。如当类里没有实现__call__()时,此时的对象p 只是个类的实例,不是一个可调用的对象,当调用它时会报错:‘Person’ object is not callable.

class People(object):
    def __init__(self, name):
        self.name = name

    def my_friend(self):
        print("hello "+self.name)

    def train(self,location):
        print("name"+location)

    def __call__(self):
        return self.my_friend()
        # return self.train(location)

    def update(self, newname):
        self.name = newname

a = People('无忌!')
a.__call__()       # 调用方法一
a()                # 调用方法二   调用就会直接激活__call__(),调用时必须加上括号

# 调用类中其他对象
a.update("赵敏")  # 更新类中变量,更新了类中的全局变量,调用时a后面不加括号
a()

在这里插入图片描述

class People(object):
    def __init__(self, name):
        self.name = name

    def add_interest(self, interest): # 定义类中新的全局变量,也就是在类中的初始化函数中没有定义的变量。
    # 不能直接给定,必须通过这种函数方法来传入
        self.interest = interest

    def change_interest(self):  # 前面定义好新的变量后,在这里更改
        self.interest = "play guitar"

    def speak(self):  # 不需要传入参数的对象
        print("come here please")

    def train(self, location):  # 初始化时传入的参数这里不能用,需要在这个对象中传入参数,只对这个函数起作用
        print("name"+" "+location)

    def my_friend(self, location):  # 调用类中的其他对象。如果被调用函数需要参数,则传入参数
        self.change_interest()  # 不需要参数的调用
        self.speak()  # 不需要参数的调用
        self.train(location)  # 需要参数的调用
        print("hello "+" "+self.name)
        print("I like"+" "+self.interest)

    def __call__(self, location):  # __call__()方法的作用其实是把一个类的实例化对象变成了可调用对象,
    # 只要类里实现了__call__()方法就行,即实例化类后,直接调用类就会调用__call__
        return self.my_friend(location)
        # return self.train(location)

    def update(self, newname):  # 更新类中全局变量的函数
        self.name = newname

    def play(self, ball):  # 跟类中其他对象没有关系的独立对象
        print("play"+ball)

a = People('无忌!')
a.add_interest("sing song")
a.__call__("北京")  # 调用方法一
print("---------------------")
a("北京")           # 调用方法二
print("---------------------")
# 调用类中其他对象
a.update("赵敏")  # 更新类中变量
a("北京")
print("---------------------")
# 调用类中独立对象
a.play("football")
print("---------------------")
# 打印类中的全局变量
print(a.name)
print(a.interest)

在这里插入图片描述

二 在循环遍历中更新类中的全局变量

如果想要在循环中自动更新类中的全局变量,则必须将类的初始化写到循环外面。

# 定义一个类
class step_batch():
    def __init__(self, lr=10):
        self.lr = lr

    def run(self):
        print(self.lr)

    def update(self):
        self.lr = self.lr / 2

# 类的初始化在循环里面,意味着每次循环都需要重新初始化,那么循环中的更新变量的操作就会被类的重新初始化给更改掉
def train_model(init_lr=10):
    for i in tqdm(range(10)):
        a = step_batch(lr=init_lr)  # 类的初始化
        a.run()
        if i % 2 == 0:
            a.update()

# 类的初始化在循环外面,意味着在进入循环之前只进行了一次初始化;在循环体内部,更新变量的操作就会将更新后的变量保存下来
def test_model(init_lr=10):
    a = step_batch(lr=init_lr)  # 类的初始化
    for i in tqdm(range(10)):
        a.run()
        if i % 2 == 0:
            a.update()

# 结果如下
类的初始化在循环中
10
10
10
10
10
10
10
10
10
10
---------------------
类的初始化在循环外面
10
5.0
5.0
2.5
2.5
1.25
1.25
0.625
0.625
0.3125
100%|██████████| 10/10 [00:00<?, ?it/s]
100%|██████████| 10/10 [00:00<?, ?it/s]

在这里插入图片描述
总结:
实例化 StepRunner() 类,会自动运行 init()进行初始化,给__init__()中定义的变量和函数传参数,赋值。

注意:实例化类以后,后面就可以去调用类中的对象,更改类中的对象。调用类中的哪一个对象(函数),这个对象(函数)才会受影响,没调用就不受影响,也就是,如果调用的这个对象(函数)不影响 init() 中的变量和函数,那么__init__() 中的变量和函数就不改变。如果调用的对象(函数)和__init__() 中的内容有关系,那么__init__() 中的变量和函数就改变。

初始化时候定义的那些类中的变量,也可以更改,这样就会永久改变。更改哪一个,哪一个才受影响,不更改就不会受影响。

这里最有迷惑性的是类中的__call__(), call()的作用就是在实例化后可以通过直接调用类名来调用__call__()中定义的内容,而不需要再写class().step() 类加函数 的形式。只需要关注__call__()中定义了什么就可以。

猜你喜欢

转载自blog.csdn.net/LIWEI940638093/article/details/126691442