• 第二十八篇 静态属性、类方法、静态方法


    静态属性

    静态属性:实际上说的就是数据属性

    需求:每个人都有自己的房子,想知道每个人自己的房子都有多大平米

    实现分析:
    每个人,表示有很多人,不可能一个人写一次计算面积的方法,那么就可以将它提炼出来,放到类里
    class Room:
        tag=1
        def __init__(self,name,owner,width,length,heigh):
            self.name=name
            self.owner=owner
            self.width=width
            self.length=length
            self.heigh=heigh
        
        # 计算面积
        def cal_area(self):
            # print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length))
    
    # 实例化
    R1=Room('大House','alex',100,100,100000)
    R2=Room('小平房','yuanhao',2,4,6)
    
    # 调用计算面积
    r1.cal_area()
    r2.cal_area()
    
    # alex 住的 大House 总面积是10000
    # yuanhao 住的 小平房 总面积是8
    View Code
    • 静态属性:@property

    静态属性是绑定到实例上的,是通过实例.方法名 进行调用的。

    静态属性的作用:就是封装逻辑,让用户再调用的时候完全感知不到后端的逻辑,就行在调用一个普通的数据属性一样。

    特点:定义一个静态属性,内部会有一个self位置参数,self代表实例,实例可以访问到实例的数据属性,实例同样也可以访问到类的数据属性和类的函数属性,也就是说

    静态属性,既可以访问实例属性,也可以访问类的属性(类的数据属性和类的函数属性)--->  self.类属性   或者  self.实例属性

    class Room:
        tag=1
        def __init__(self,name,owner,width,length,heigh):
            self.name=name
            self.owner=owner
            self.width=width
            self.length=length
            self.heigh=heigh
    
        @property   # 属性的意思。
        def cal_area(self):
            return  '%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length)   # 需要return值
    
    # 实例化
    R1=Room('大House','alex',100,100,100000)
    R2=Room('小平房','yuanhao',2,4,6)
    
    # 调用静待属性时,就不用再加小括号了。
    # 调用cal_area,实际上是个函数属性,但是加了@property 之后,再调用,直观感受上就跟调用实例的数据属性是一样的,调用者看不到背后的运行逻辑,
    # 调用者更不知道调用的这个到底是数据属性还是函数属性----这就是静态属性的作用。
    print(R1.cal_area) print(R2.cal_area) # 这是实例直接调用实例的数据属性。 print(R1.name) print(R2.name)
    • 类方法:@calssmethod

    不跟任何实例捆绑,只跟类捆绑的方法

    作用和目的:跟实例没有任何关系了,只是类级别的操作,类来调用自己的方法。

    特点:函数的位置参数默认就被写成了cls, cls代表类, 类能访问到类的数据属性和类的函数属性(---> cls.类属性 或者 cls.实例属性),但是类不能访问到实例的属性。

    需求:
    类调用类的函数属性
    class Room:
        tag=1  # 类的数据属性
        def __init__(self,name,owner,width,length,heigh):
            self.name=name
            self.owner=owner
            self.width=width
            self.length=length
            self.heigh=heigh
    
        @property
        def cal_area(self):
            return '%s 住的 %s 总面积是%s' % (self.owner, self.name, self.width * self.length)
    
        def test(self):
            print('from test',self.name)
    
    # 1. 类可以调用自己(类)的数据属性
    print(Room.tag)   # 1
    
    # 2.  类调用自己(类)的函数属性
    #  如果没有实例,直接调用函数属性
    Room.test(r1)     # 1.name
    # AttributeError: 'int' object has no attribute 'name'
    
    # 报错了,因为函数属性test(self), self指的就是实例,需要传入实例参数才能正常运行。所以要先实例化
    r1=Room('大House','alex',100,100,100000)
    Room.test(r1)     # r1.name
    #from test 大House
    没有类方法之前的这种方案,必须通过实例才能调用到

    使用类方法,就可以不再通过实例,而可以直接调用类的函数属性了。

    class Room:
        tag=1  # 类的数据属性
        def __init__(self,name,owner,width,length,heigh):
            self.name=name
            self.owner=owner
            self.width=width
            self.length=length
            self.heigh=heigh
    
        @property   # 静态属性
        def cal_area(self):
            return '%s 住的 %s 总面积是%s' % (self.owner, self.name, self.width * self.length)
    
        def test(self):
            print('from test',self.name)
    
        @classmethod  # 类方法:就把tell_info变成专门供类使用的方法
        def tell_info(cls,x):   # cls:本质上就是一个位置参数,但是python告诉你,cls接收的是一个类名,而这个类名是默认传的,不需要你再显示的写出来然后传进来
            # 打印类名
            print(cls)     # 运行结果:<class '__main__.Room'>  class表示类型是类,__main__表示当前文件,Room表示类名
            # cls.tag:类调用类的数据属性。
            print('--》',cls.tag)  # 相当于print('--》',Room.tag)
    
    
    # 调用方式:类名.函数属性
    # tell_info(cls,x): 有两个参数:第一个是位置参数cls,第二个是x
    # 可以为什么只传了一个参数12呢?因为该函数属性已经变成了类方法,第一个参数cls Python默认就给你传成了类名Room
    # 与self道理一样一样的。所以,调用者只需要传入第二个位置参数就可以拉。
    Room.tell_info(12)
    # 结果
    <class '__main__.Room'>
    --》 1
    
    看到了把,用了类方法,类想调用类的函数属性,就不比再通过实例这个中介来调用了,而是可以直接调用。

    注意:

    # 通过实例也可以调用类方法
    
    r1=Room('大House','alex',100,100,100000)
    r1.tell_info(13)
    
    # 结果
    <class '__main__.Room'>
    --》 1 13
    
    
    # 但是,前面说过了,@classmethod 就是专门供类使用的,所以,虽然能通过实例调用,但是千万别这么干,别给自己找不痛快
    注意,千万别给自己找别扭
    • 静态方法:@staticmethod

    @staticmethod,不跟类绑定,也不跟实例绑定,只是一个类的工具包

    用处:只是名义上归属类管理,不能使用类变量和实例变量,是类的工具包

    特定:函数里既没有self参数,也没有cls参数,所以静态方法不能访问类属性和实例属性

    class Room:
        tag=1
        def __init__(self,name,owner,width,length,heigh):
            self.name=name
            self.owner=owner
            self.width=width
            self.length=length
            self.heigh=heigh
    
        @property
        def cal_area(self):
            return '%s 住的 %s 总面积是%s' % (self.owner, self.name, self.width * self.length)
    
        @classmethod
        def tell_info(cls,x):
            print(cls)
            print('--》',cls.tag,x)    #print('--》',Room.tag)
    
        @staticmethod     # static:静态  staticmethod 就是类的工具包
        def wash_body(a,b,c):
            print('%s、 %s、 %s正在洗澡' %(a,b,c))

      # 通俗的说,静态方法里没有self或者cls等位置参数,让你可以向类方法或者self那样,通过点的方式调用类变量,比如:通过cls.tag这样的方式进行调用类变量
      # 在类里,这么写是没有任何实际意义的, 所以,此处这么写就是为了提示自己,这是无意义的,以后开发中别这么干
    def test(x,y): print(x,y) # @staticmethod 既可以通过类调用,也可以通过实例调用 # 1. 调用方式: 类名.函数属性名 Room.wash_body('alex','yuanhao','wupeiqi') # 2. 调用方式: 实例.函数属性名 r1=Room('厕所','alex',100,100,100000) r1.wash_body('alex','yuanhao','wupeiqi') # 那不加@staticmethod,有什么区别呢? # 1. 通过类调用test()函数,可以调用 Room.test(1,2) # 1 2 # 2. 通过实例调用test()函数,不可以调用,因为实例调用需要会自动把实例自己传给函数,而test()却没有self接收。 r1.test(1,2) # TypeError: test() takes 2 positional arguments but 3 were given

    问题:那静态方法到底定义到哪里去了呢?

    【答】静态属性@property、类方法@classmethod、静态方法@staticmethod, 都是定义到了类的数据字典里的。

    print(Room.__dict__)
    
    # {'__module__': '__main__', 'tag': 1, '__init__': <function Room.__init__ at 0x019A1C00>, 
    'cal_area': <property object at 0x0193CDE0>, 'tell_info': <classmethod object at 0x017993B0>,
    'wash_body': <staticmethod object at 0x019A5190>,
    'test': <function Room.test at 0x019A1AE0>, '__dict__': <attribute '__dict__' of 'Room' objects>,
    '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}
    # 通过上面可以看到,静态属性@property、类方法@classmethod、静态方法@staticmethod, 都是定义到了类的数据字典里的。
    print(r1.__dict__) # {'name': '厕所', 'owner': 'alex', 'width': 100, 'length': 100, 'heigh': 100000} #实例始终不变的就是只有自己的数据属性

    小总结:

    1、函数属性有参数self:表示该函数属性跟实例绑定

    2、@classmethod,函数属性有参数cls:表示该函数属性跟类绑定

    3、@staticmethod,函数属性既没有self参数,也没有cls参数:表示该函数属性既不跟类绑定,也不跟实例绑定,只是一个类的工具包

  • 相关阅读:
    for xml path(''),root('')
    [小明带你玩儿Photon]4.一起来看日志
    [小明带你玩儿Photon]3.Hello World i
    [小明带你玩儿Photon]2.从零开始一个程序
    [小明带你玩儿Photon]1.Photon介绍
    杂记
    FluentNHibernate初探[1]
    [Navigation]Navigation初探[2]
    [Navigation]Navigation初探[1]
    动画系统的animator
  • 原文地址:https://www.cnblogs.com/victorm/p/9314241.html
Copyright © 2020-2023  润新知