• 【python语法】@staticmethod、@classmethod、@property使用方法


    @staticmethod、@classmethod的联系与区别

    一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。而使用@staticmethod@classmethod,就可以不需要实例化,直接类名.方法名()来调用。

    这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。

    既然@staticmethod和@classmethod都可以直接类名.方法名()来调用,那他们有什么区别呢?

    • 从它们的使用上来看,

      • @staticmethod不需要表示自身对象的self自身类的cls参数,就跟使用普通函数一样。

      • @classmethod不需要self参数,但第一个参数需要是表示自身类的cls参数

      • 如果在@staticmethod要调用到这个类的一些属性方法,只能直接类名.属性名类名.方法名

      • @classmethod因为持有cls参数可以来调用类的属性,类的方法,实例化对象等,避免硬编码。

    class A(object):  
        bar = 1  
        def foo(self):  # self代表调用该方法的 当前的类对象
            print 'foo'  
    
        @staticmethod  
        def static_foo():  # 注意参数列表形式
            print 'static_foo'  
            print A.bar  # 注意调用方式 
    
        @classmethod  
        def class_foo(cls):  # 注意参数列表形式,cls代表调用该方法的类本身
            print 'class_foo'  
            print cls.bar  # # 注意调用方式 
            cls().foo()  # 注意调用方式 
    ###执行  
    A.static_foo()  
    A.class_foo()  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    输出

    static_foo
    1
    class_foo
    1
    foo
    
    • 1
    • 2
    • 3
    • 4
    • 5

    @staticmethod

    staticmethod用于修饰类中的方法,使其可以在不创建类实例的情况下调用方法,这样做的好处是执行效率比较高。当然,也可以像一般的方法一样用实例调用该方法。

    该方法一般被称为静态方法。静态方法不可以引用类中的属性或方法,其参数列表也不需要约定的默认参数self

    我个人觉得,静态方法就是类对外部函数的封装,有助于优化代码结构和提高程序的可读性(把类内常用到的外部函数放在类内,方便维护)。当然了,被封装的方法应该尽可能的和封装它的类的功能相匹配。

    代码示例

    class Time():
    
        def __init__(self,sec):
    
            self.sec = sec
    
        #声明一个静态方法
    
        @staticmethod
    
        def sec_minutes(s1,s2):
    
            #返回两个时间差
    
            return abs(s1-s2)
    
     
    
    #分别使用类名调用和使用实例调用静态方法
    
    print("----------------------不通过例化的方法调用----------")
    
    print(Time.sec_minutes(10,5)) #类直接调用
    
    #结果为5 5
    
    
    
    t = Time(10) #先实例化类,即对象
    
    print("----------------------通过例化方法调用----------")
    
    print(t.sec_minutes(t.sec,5)) #通过对象进行调用
    
    • 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
    • 30
    • 31
    • 32
    • 33

    @classmethod

    classmethod是用来指定一个类的方法为类方法,长的像下面这个样子:

    class cc:
        @classmethod
        def f(cls, arg1, arg2, ...): ...
    
    • 1
    • 2
    • 3

    cls通常用作类方法的第一参数 跟self有点类似( __init__里面的slef通常用作实例方法的第一参数)。即通常用self来传递当前类的实例–对象,cls传递当前类

    self 和cls 没有特别的含义,作用只是把参数绑定到普通的函数上, 不一定非得是self 或cls,可以换成别的xxx。

    那么为什么会出现classmethod?

    1. classmethod设计的目的是什么呢?事实上与Python面向对象编程有关的,由于Python不支持多个的參数重载构造函数,比方在C++里,构造函数能够依据參数个数不一样。能够写多个构造函数。Python为了解决问题,採用classmethod修饰符的方式,这样定义出来的函数就能够在类对象实例化之前调用这些函数,就相当于多个构造函数,解决多个构造函数的代码写在类外面的问题;

    2. 类最基本的作用是实例化出一个对象,但是有的时候再实例化之前,就需要先和类做一定的交互,这种交互可能会影响实际实例化的过程,所以必须放在调用构造函数之前。大概也可能是因为这个原因出现了classmethod;

    3. 直接一点来说,我们知道对于一个普通的类,我们要使用其中的函数的话,需要对类进行实例化,而一个类中,某个函数前面加上了staticmethod或者classmethod的话,那么这个函数就可以不通过实例化直接调用,可以通过类名进行调用的;

    4. @classmethod 定义的类方法是可选构造函数中,我们定义了一个类方法,类方法的第一个参数(cls)指代的就是类本身。类方法会用这个类来创建并返回最终的实例。使用类方法的另一个好处就是在继承的时候,保证了子类使用可选构造函数构造出来的类是子类的实例而不是父类的实例。

    代码示例

    class Data_test(object):
        day=0
        month=0
        year=0
        def __init__(self,year=0,month=0,day=0):
            self.day=day
            self.month=month
            self.year=year
     
        def out_date(self):
            print "year :"
            print self.year
            print "month :"
            print self.month
            print "day :"
            print self.day
     
    t=Data_test(2016,8,1)
    t.out_date()
    输出:
    year :
    2016
    month :
    8
    day :
    1
     
    符合期望。
      
    如果用户输入的是 "2016-8-1" 这样的字符格式,那么就需要调用Date_test 类前做一下处理:
      
    string_date='2016-8-1'
    year,month,day=map(int,string_date.split('-'))
    s=Data_test(year,month,day)
     
    先把‘2016-8-1’ 分解成 year,month,day 三个变量,然后转成int,再调用Date_test(year,month,day)函数。 也很符合期望。
      
    那我可不可以把这个字符串处理的函数放到 Date_test 类当中呢?
      
    那么@classmethod 就开始出场了
      
    class Data_test2(object):
        day=0
        month=0
        year=0
        def __init__(self,year=0,month=0,day=0):
            self.day=day
            self.month=month
            self.year=year
     
        @classmethod
        def get_date(cls,data_as_string):
            #这里第一个参数是cls, 表示调用当前的类名
            year,month,day=map(int,string_date.split('-'))
            date1=cls(year,month,day)
            #返回的是一个初始化后的类
            return date1
     
        def out_date(self):
            print "year :"
            print self.year
            print "month :"
            print self.month
            print "day :"
            print self.day
     
    在Date_test类里面创建一个成员函数, 前面用了@classmethod装饰。 它的作用就是有点像静态类,比静态类不一样的就是它可以传进来一个当前类作为第一个参数。
      
    那么如何调用呢?
      
    r=Data_test2.get_date("2016-8-6")
    r.out_date()
    输出:
    year :
    2016
    month :
    8
    day :
    1
    这样子等于先调用get_date()对字符串进行出来,然后才使用Data_test的构造函数初始化。 
    这样的好处就是你以后重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,然后使用装饰符 @classmethod 就可以了。
    
    • 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
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    @property

    Python中访问对象的属性可以这么做:实例名.变量名!!@property是python的一种装饰器,是用来修饰方法的。

    • 作用:
      我们可以使用@property装饰器来创建只读属性@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。

    • 通俗理解:
      可以使用@property装饰器将方法伪装成 属性 的样式使用
      @property 下方的函数只能是self参数 ,不能有其他的参数,property 常和私有属性相结合使用

    代码示例

    使用场景:1.修饰方法,是方法可以像属性一样访问。

    class DataSet(object):
    
      @property
    
      def method_with_property(self): ##含有@property
    
          return 15
    
      def method_without_property(self): ##不含@property
    
          return 15
    
    
    
    l = DataSet()
    
    print(l.method_with_property) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。
    
    print(l.method_without_property())  #没有加@property , 必须使用正常的调用方法的形式,即在后面加()
    
    两个都输出为15
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用场景:2.与所定义的属性配合使用,这样可以防止属性被修改。

    由于python进行属性的定义时,没办法设置私有属性,因此要通过@property的方法来进行设置。这样可以隐藏属性名,让用户进行使用的时候无法随意修改。

    class DataSet(object):
    
        def __init__(self):
    
            self._images = 1
    
            self._labels = 2    #定义属性的名称
    
        @property
    
        def images(self):   #方法加入@property后,这个方法相当于一个属性,这个属性可以让用户进行使用,而且用户有没办法随意修改。
    
            return self._images 
    
        @property
    
        def labels(self):
    
            return self._labels
    
    
    
    l = DataSet() #用户进行属性调用的时候,直接调用images即可,而不用知道属性名_images,因此用户无法更改属性,从而保护了类的属性。
    
    print(l.images) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。
    
    • 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
  • 相关阅读:
    (最优化理论与方法)第六章无约束优化算法-第一节:线搜索方法
    图 知识点总结(王道)
    【ACWing】1176. 消息的传递
    Rust 利用 Trait 实现多态性
    C# 结合 JS 暴改腾讯 IM SDK Demo
    Goland2023版新UI的debug模式调试框按钮功能说明
    站点到站点的流量监控
    盘点73个Python各行各业管理系统源码Python爱好者不容错过
    安全性证明
    【Python 千题 —— 基础篇】分割有效信息
  • 原文地址:https://blog.csdn.net/All_In_gzx_cc/article/details/126271417