Python @staticmethod、super().__init__()和self

最近在看代码,由于之前没有系统学习过Python,就有些知识点不是很清楚,这里整理一下,方便以后查阅。

Python 装饰器

装饰器(decorators)是 Python 中的一种高级功能,它允许你动态地修改函数或类的行为。

装饰器是一种函数,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数。

装饰器的语法使用 @decorator_name 来应用在函数或方法上。

Python 还提供了一些内置的装饰器,比如 @staticmethod@classmethod,用于定义静态方法和类方法。

装饰器的应用场景:

  1. 日志记录: 装饰器可用于记录函数的调用信息、参数和返回值。
  2. 性能分析: 可以使用装饰器来测量函数的执行时间。
  3. 权限控制: 装饰器可用于限制对某些函数的访问权限。
  4. 缓存: 装饰器可用于实现函数结果的缓存,以提高性能。

使用装饰器

装饰器通过 @ 符号应用在函数定义之前,例如:

@time_logger
def target_function():
    pass

等同于:

def target_function():
    pass
target_function = time_logger(target_function)

这会将 target_function 函数传递给 decorator 装饰器,并将返回的函数重新赋值给 target_function。从而,每次调用 target_function 时,实际上是调用了经过装饰器处理后的函数。

通过装饰器,开发者可以在保持代码整洁的同时,灵活且高效地扩展程序的功能。

@staticmethod和@classmethod的作用与区别

作用

一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。但是使用@staticmethod或@classmethod,就可以不需要实例化。

所以@staticmethod或@classmethod作用:使用@staticmethod或@classmethod,就可以不需要实例化,直接“类名.方法名()”来调用。这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。

区别

  1. @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
  2. @classmethod 是一个函数修饰符,它表示接下来的是一个类方法,而对于平常我们见到的则叫做实例方法。类方法的第一个参数cls,而实例方法的第一个参数是self,表示该类的一个实例。
    类方法有类变量cls传入,从而可以用cls做一些相关的处理。并且有子类继承时,调用该类方法时,传入的类变量cls是子类,而非父类。
    对于类方法,可以通过类来调用,就像Test.foo(),有点类似C++中的静态方法, 也可以通过类的一个实例来调用,就像Test().foo(),这里Test(),写成这样之后它就是类的一个实例了。
  3. 静态方法它基本上跟一个全局函数相同,一般来说用的很少。
  4. 在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
    而@classmethod因为持有cls参数(当然,也可以用“self” 代替,个人认为是为了和类的self区分才用cls的),可以来调用类的属性,类的方法,实例化对象等,避免硬编码。

代码演示

class A(object):

    bar = 1
    
    def foo(self):
        print('foo')
 
    @staticmethod
    def static_foo():
        print('static_foo')
        print(A.bar)
        
    @classmethod
    def class_foo(cls):
        print('class_foo')
        print(cls.bar)
        cls().foo()
 

A.static_foo()
A.class_foo()
 
 
'''输出结果
static_foo
1
class_foo
1
foo
'''

super() 函数

super() 函数是用于调用父类(超类)的一个方法。

super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

super().init()函数

super().__init__() 是用于在 Python 中调用父类(也称为超类或基类)的构造方法(init 方法)的一种方式。这通常在子类的构造方法中使用,以便在添加子类特有的功能之前,初始化父类中定义的属性和执行其他必要的设置。

super()用来调用父类(基类)的方法,init()是类的构造方法,
super().__init__() 就是调用父类的__init__()方法, 同样可以使用super()去调用父类的其他方法。

super().init()基本用法

以下是一个基本示例,展示了如何在子类的构造方法中使用 super().init():

class Parent:
    def __init__(self, name):
        self.name = name

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name)  # 调用父类的构造方法以初始化 name
        self.age = age #添加自定义age属性

child = Child("Alice", 25)
print(child.name)  # 输出 "Alice"
print(child.age)   # 输出 25

super().init() 和 super(Child, self).init() 的区别

super().init() 和 super(Child, self).init() 都是用于调用父类的构造方法,但它们之间有一个重要的区别:

参数传递方式:

  • super().__init__(): 这种方式不需要显式传递当前类和实例(self)作为参数,Python会自动识别当前类和实例。这是一种简化的写法,通常用于单继承的情况。

  • super(Child, self).__init__(): 这种方式明确指定了当前类(Child)和实例(self)作为参数传递给 super()。这种方式通常在多继承的情况下使用,以明确指定要调用哪个父类的构造方法。

多继承中的 super().init()

如果类是多继承的,使用 super(Child, self).init() 可以更明确地控制调用的是哪个父类的构造方法,因为 super() 可以基于参数中的当前类(Child)找到正确的父类。

下面是一个多继承的示例,演示了使用super().init() 和 super(Child, self).init() 的区别:

class Parent1:
    def __init__(self):
        print("Parent1 constructor")

class Parent2:
    def __init__(self):
        print("Parent2 constructor")

class Parent3:
    def __init__(self):
        print("Parent3 constructor")

class Child(Parent1,Parent2,Parent3):    # 顺序为Parent1,Parent2,Parent3
    def __init__(self):
        super().__init__()               # 使用简化写法,调用了 Parent1 的构造方法
        
child = Child()
#输出结果:Parent1 constructor

接下来将Child继承父类中Parent1,Parent2的顺序进行调换,运行结果如下:

#把Parent1,Parent2的顺序进行调换
class Parent1:
    def __init__(self):
        print("Parent1 constructor")

class Parent2:
    def __init__(self):
        print("Parent2 constructor")

class Parent3:
    def __init__(self):
        print("Parent3 constructor")

class Child(Parent2,Parent1,Parent3):    # 顺序为Parent2,Parent1,Parent3
    def __init__(self):
        super().__init__()               # 使用简化写法,调用了 Parent2 的构造方法
        
child = Child()
#输出结果:
#Parent2 constructor

在上面的示例中,我们可以知道,在多继承的情况下,super().init() 调用的是子类(Child)继承父类中,第一个父类的构造方法。

多继承中的 super(Child, self).init()

class Parent1:
    def __init__(self):
        print("Parent1 constructor")

class Parent2:
    def __init__(self):
        print("Parent2 constructor")

class Parent3:
    def __init__(self):
        print("Parent3 constructor")

class Child(Parent1, Parent2,Parent3):
    def __init__(self):
        super(Child, self).__init__()     # 调用Child下一个父类的构造方法,即Parent1
        super(Parent2, self).__init__()   # 调用Parent2下一个父类的构造方法,即Parent3

child = Child()
#输出结果:
#Parent1 constructor
#Parent3 constructor

综上,我们可以知道,在多继承中,super().init() 继承的是子类继承的第一个父类,super(Parent2, self).init() 继承的是声明类的下一个父类

self 代表类的实例,而非类

类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。

class Test:
    def prt(self):
        print(self)
        print(self.__class__)
 
t = Test()
t.prt()

以上实例执行结果为:

<__main__.Test instance at 0x100771878>
__main__.Test

从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。

self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的:

class Test:
    def prt(runoob):
        print(runoob)
        print(runoob.__class__)
 
t = Test()
t.prt()

以上实例执行结果为:

<__main__.Test instance at 0x100771878>
__main__.Test

在 Python中,self 是一个惯用的名称,用于表示类的实例(对象)自身。它是一个指向实例的引用,使得类的方法能够访问和操作实例的属性。

当你定义一个类,并在类中定义方法时,第一个参数通常被命名为 self,尽管你可以使用其他名称,但强烈建议使用 self,以保持代码的一致性和可读性。

class MyClass:
    def __init__(self, value):
        self.value = value

    def display_value(self):
        print(self.value)

# 创建一个类的实例
obj = MyClass(42) 

# 调用实例的方法
obj.display_value() # 输出 42

参考资料

Python方法:@staticmethod和@classmethod

Python 装饰器

super().init()函数

Python super 详解

Python super() 函数

Python3 面向对象

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 13:46:02       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 13:46:02       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 13:46:02       45 阅读
  4. Python语言-面向对象

    2024-07-22 13:46:02       55 阅读

热门阅读

  1. WHAT - 通过 shadcn 组件源码学习 React

    2024-07-22 13:46:02       14 阅读
  2. 探索 PHP 与 JD 详情 API 接口的连接奥秘

    2024-07-22 13:46:02       20 阅读
  3. 多个返回值QT/C++

    2024-07-22 13:46:02       17 阅读
  4. C# --- .Net Framework中的Binding Redirect

    2024-07-22 13:46:02       19 阅读
  5. 深入语音识别:贝叶斯准则的细致解析

    2024-07-22 13:46:02       18 阅读
  6. 从统计学、到机器学习和ChatGPT

    2024-07-22 13:46:02       18 阅读
  7. MobaXterm远程工具

    2024-07-22 13:46:02       21 阅读
  8. 【TORCH】获取第一个batch数值的几种方法

    2024-07-22 13:46:02       19 阅读
  9. [Python]使用pyttsx3将文字转语音

    2024-07-22 13:46:02       14 阅读
  10. 【QT】线程控制和同步

    2024-07-22 13:46:02       15 阅读
  11. [基础算法理论] --- 双指针

    2024-07-22 13:46:02       18 阅读