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

posted on 2020-08-28 13:00  crystal1126  阅读(254)  评论(0编辑  收藏  举报

导航