zoukankan      html  css  js  c++  java
  • python面向对象之数据和自省(私有属性、内置属性、自定义属性和描述器)

    一、私有属性

    • 类里面定义的变量叫类属性,类属性有两种:公有属性和私有属性
    • 私有属性定义:

            单下划线开头:_attr

            双下划线开头:__attr

    python中并未实现属性的真正私有化,但可以用下划线实现伪私有。

    class MyClass():
        attr1="attr1"
        _attr2="attr2"
        __attr3="attr3"
    
    m=MyClass()
    #访问公有属性
    print(MyClass.attr1)
    print(m.attr1)
    
    #访问单下划线私有属性
    print(MyClass._attr2)
    print(m._attr2)
    
    #访问双划线私有属性
    print(MyClass._MyClass__attr3)  #访问私有属性需要在属性名称前面加上"_类名"
    print(m._MyClass__attr3)
    
    print(MyClass.__dict__)   #查看该类的所有属性和方法

    运行结果:

    attr1
    attr1
    attr2
    attr2
    attr3
    attr3
    {'__module__': '__main__', 'attr1': 'attr1', '_attr2': 'attr2', '_MyClass__attr3': 'attr3', '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

    二、__dict__

    类调用__dict__属性,返回类的属性和方法的字典。

    实例调用__dict__属性,返回实例相关的属性和方法。

    class MyClass():
        attr1="attr1"
    
        def __init__(self,name):
            self.name=name
    
        def test(self):
            print("这是一个test方法")
    
    m=MyClass("crystal")
    print(m.__dict__)  #运行结果: {'name': 'crystal'}
    print(MyClass.__dict__)    #运行结果:{'__module__': '__main__', 'attr1': 'attr1', '__init__': <function MyClass.__init__ at 0x10f8460d0>, 'test': <function MyClass.test at 0x10f846158>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

    三、内置属性__slots__

    默认情况下,类的实例有一个字典用于存储属性,这对于具有很少实例变量的对象会浪费空间。当创建大量实例时,空间消耗会很大。

    可以通过在类定义中定义__slots__来覆盖默认__dict__行为。

    class Base(object):
        #指定类对象所能绑定的属性
        #限制属性
        #节约内存,定义了__slots__属性后,那么该对象不会再自动生成__dict__属性
        __slots__ = ['name']
        pass
    
    b=Base()
    # b.age="20"   #  'Base' object has no attribute 'age'
    b.name="crystal"
    
    # print(b.__dict__)   #'Base' object has no attribute '__dict__'

    四、自定义属性访问

    可以定义下面的方法来访问、赋值或删除自定义类实例。

    • object.__getattr__:当查找不到属性,触发AttributeError异常时会调用此方法
    • object.__getattribute__:查找属性时,第一时间会调用此方法
    • object.__setattr__:设置属性时,调用此方法给属性赋值
    • object.__delattr__:删除属性时触发此方法

    (1)获取属性方法

    class Test:
    
        def __getattr__(self, item):
            print("这是__getattr__方法")
            return 100
    
        def __getattribute__(self, item):
            print("这是__getattribute__方法")
            return super().__getattribute__(item)
    
    t=Test()
    
    t.name=999
    print(t.name)
    print("-------------------")
    print(t.name1)

    运行结果:

    这是__getattribute__方法
    999
    -------------------
    这是__getattribute__方法
    这是__getattr__方法
    100

    (2)设置属性方法

    class Test:
    
        def __setattr__(self, key, value):
            #此方法在给对象设置属性时会触发
            print("这是__setattr__方法")
            if key=="age":
                super().__setattr__(key, 18)
            else:
                super().__setattr__(key,value)
    
    t=Test()
    
    t.name=999
    print(t.name)
    print("-------------------")
    t.age=200
    print(t.age)

    运行结果:

    这是__setattr__方法
    999
    -------------------
    这是__setattr__方法
    18

    (3)删除对象属性方法

    class Test:
    
        def __delattr__(self, item):
            print("这是__delattr__方法")
            super().__delattr__(item)
    t=Test()
    
    t.name=999
    print(t.name)
    print("--------------")
    del t.name
    print(t.name)

    运行结果:

    999
    --------------
    这是__delattr__方法
    Traceback (most recent call last):
      File "/Users/grace/PycharmProjects/selenium/test.py", line 375, in <module>
        print(t.name)
    AttributeError: 'Test' object has no attribute 'name'

    五、描述器

    描述器是一个具有绑定行为的对象属性,如果一个对象定义以下方法中的任何一个,它被称为描述器。

    object.__get__(self,instance,owner):获取属主类的属性或者该类的一个实例的属性。

    object.__set__(self,instance,value):设置属主类实例的属性的值

    object.__delete(self,instance,value):删除属主类实例的属性。

    实例:

    class Field:
    
        def __get__(self, instance, owner):
            print("__get__方法被触发")
            print("owner:", owner)  #属主类:<class '__main__.Model'>
            return self.value
    
        def __set__(self, instance, value):
            print("__set__方法被触发")
            print("self:", self)  #描述器的实例:<__main__.Field object at 0x1128d3048>
            print("instance:", instance) #属主类的实例: <__main__.Model object at 0x1128d3080>
            print("value:", value)
            self.value=value
    
        def __delete__(self, instance):
            print("__delete__方法被触发")
            del self.value
    
    class Model(object):
        name="musen"
        attr=Field()
    
    m=Model()
    m.attr=10
    print("-----------")
    print(m.attr)
    print("-------------")
    del m.attr

    运行结果:

    __set__方法被触发
    self: <__main__.Field object at 0x10679e080>
    instance: <__main__.Model object at 0x10679e0f0>
    value: 10
    -----------
    __get__方法被触发
    owner: <class '__main__.Model'>
    10
    -------------
    __delete__方法被触发

    使用描述器实现ORM模型中的字段类型: 参考https://www.cnblogs.com/crystal1126/p/13625306.html

  • 相关阅读:
    Scala进阶之路-idea下进行spark编程
    Scala进阶之路-Spark本地模式搭建
    Scala进阶之路-Scala高级语法之隐式(implicit)详解
    Scala进阶之路-Spark底层通信小案例
    Scala进阶之路-并发编程模型Akka入门篇
    Scala进阶之路-统计商家id的标签数以及TopN示例案例分析
    Scala进阶之路-Scala中的泛型介绍
    Scala进阶之路-尾递归优化
    Scala进阶之路-Scala特征类与unapply反向抽取
    Java基础-爬虫实战之爬去校花网网站内容
  • 原文地址:https://www.cnblogs.com/crystal1126/p/13576875.html
Copyright © 2011-2022 走看看