17、类的自定义属性访问及动态属性设置

前言:本文主要介绍python类的一些自定义属性访问的方法,以及类的动态属性设置即python的内置函数setattr()

自定义属性访问

什么是属性?下面的例子a和b是属性吗?不是,他们是全局变量,属性(attribute)是类中的成员变量,也可以理解为属性就是类变量。

a = 11234
b = 'python'

类中的变量是静态变量,类可以直接访问,python是一门动态语言,任何实例对象都可以动态地添加或删除属性,一个类定义了一个作用域,类实例对象也引入了一个作用域,这与类定义的作用域是不同的。在类实例对象中查找属性的时候,首先在实例自己的作用域中查找,如果没有找到,则再去类定义的作用域中查找。在对类实例属性进行赋值的时候,实际上会在类实例定义的作用域中添加一个属性或修改一个属性,但并不会影响到对应类中定义的同名属性。那么从访问属性到返回结果的过程是怎么运作的呢?是通过下面几个魔术方法来实现的。

相关方法的使用

  • __getattribute__:查找属性时会先触发该方法进行属性查找
  • __getattr__:查找属性没找到的时候触发
  • __setattr__:设置属性的时候触发
  • __delattr__:删除属性的时候触发

为了直观地感受实例访问属性时都做了什么,我们看一下下面的例子:

class TestCase:
    att_1 = 'hello'  # 定义类属性
    att_2 = 'python'

    def test_func(self):  # 定义方法
        print("这是一个方法")

    def __getattribute__(self, item):
        # 属性访问拦截器:当对象访问属性时,会自动触发这个方法,由这个方法来决定返回的属性值
        # 应用场景:访问不存在的属性时,不希望它报错,可以用try--except来捕获异常返回一个值或提示信息
        # try:
        #     return super().__getattribute__(item)  # 调用父类真正的__getattribute__方法返回正确的属性值
        # except AttributeError:
        #     print(item,':该属性不存在!')
        # 如果使用了try方法就不会触发__getattr__方法了,因为找不到属性时的异常已经在这里被捕获了
        print("我是__getattribute__,我正在工作")
        return super().__getattribute__(item)    # 调用父类的方法,返回找到的结果,不调用就不会返回

    def __getattr__(self, att_name):
        # 当对象访问属性时,属性不存在,引发异常,会被__getattr__方法捕获
        # 然后执行该方法的代码,相当于自带捕获异常
        print("我是__getattr__,我正在工作")
        return att_name + "这是我要找的东西,但是我找不到"

    def __setattr__(self, att_name, value):
        # 设置属性的时候就会触发该方法
        print("我是__setattr__,我正在工作")
        super().__setattr__(att_name, value)    # 调用父类的方法,设置属性,不调用就不会真的设置属性

    def __delattr__(self, att_name):
        print("我是__delattr__,我正在工作")
        print("这是我即将删除的东西{}".format(att_name))
        super().__delattr__(att_name)   # 调用父类的方法,删除属性,不调用就删除不了

res = TestCase()  # 实例化对象
print('-----------------访问属性----------------')
print(res.att_1)    # 访问类属性,通过运行结果看res实例对象访问属性时通过了方法__getattribute__

print('\n-----------------访问不存在的属性----------------')
print(res.att_3)

print('\n-----------------设置属性----------------')
res.att_3 = 'new_attr'

print('\n-----------------删除属性----------------')
del res.att_3

运行结果:

C:\software\python\python.exe D:/learn/python/test.py
-----------------访问属性----------------
我是__getattribute__,我正在工作
hello

-----------------访问不存在的属性----------------
我是__getattribute__,我正在工作
我是__getattr__,我正在工作
att_3这是我要找的东西,但是我找不到

-----------------设置属性----------------
我是__setattr__,我正在工作

-----------------删除属性----------------
我是__delattr__,我正在工作
这是我即将删除的东西att_3

Process finished with exit code 0

从结果中,我们可以看到当实例访问属性时,就会自动触发__getattribute__()方法,然后由这个方法来决定返回的属性值;当实例访问不存在的属性时,会引发异常,而这个异常会被__getattr__()方法捕获,然后执行该方法的代码,相当于自带捕获异常;同理,在设置属性或删除属性时,会自动触发对应的__setattr__()方法或__delattr__()方法。

但需要注意的是,在自定义这些方法的时候,一定要记得调用对应的父类方法,将结果返回,否则只是执行了你自定义的东西并没有真正去做它本身要去做的事情。

动态属性设置

setattr()是python的一个内置函数,用于动态设置实例属性,语法:setattr(object, name, value)

?? 参数1:object-对象

?? 参数2:name-给对象要设置的属性名(字符串类型)

?? 参数3:value-属性值

class TestCase:
    """这是一个存放测试用例数据的类"""
    pass

cases = [
    {'case_id': 1, 'data': '123', 'actual': '不通过', 'excepted': '通过'},
    {'case_id': 2, 'data': '123', 'actual': '通过', 'excepted': '通过'},
    {'case_id': 3, 'data': '123', 'actual': '不通过', 'excepted': '通过'},
    {'case_id': 4, 'data': '123', 'actual': '通过', 'excepted': '通过'},
]

res = []  # 新建空列表用于存放结果
for i in cases:
    case = TestCase()  # 创建一个实例对象
    for k, v in i.items():
        # 把毎条用例数据中字典的key和value设成该实例的属性与值,比如:case_id = 1,data = 123等,把一个字典的全部键值对设为一个实例的属性
        setattr(case, k, v)
    res.append(case)    # 把创建的对象存到结果中

print(res)  # 存放的是对象,共4个
print("\n按字段读取第一条测试用例数据:")
print("case_id:", res[0].case_id)   # 读取第一个对象的case_id属性值
print("data:", res[0].data)
print("actual:", res[0].actual)
print("excepted:", res[0].excepted)

print("\n读取完整的第一条测试用例数据:")
print(res[0].__dict__)

运行结果:

C:\software\python\python.exe D:/learn/python/test.py
[<__main__.TestCase object at 0x0000019F15F573C8>, <__main__.TestCase object at 0x0000019F15F57C18>, <__main__.TestCase object at 0x0000019F16009C18>, <__main__.TestCase object at 0x0000019F16009C50>]

按字段读取第一条测试用例数据:
case_id: 1
data: 123
actual: 不通过
excepted: 通过

读取完整的第一条测试用例数据:
{'case_id': 1, 'data': '123', 'actual': '不通过', 'excepted': '通过'}

Process finished with exit code 0

上面的运行结果中,像<main.TestCase object at 0x0000019F15F573C8>这就是一个TestCase()类的实例对象,这是它的内存地址,setattr()动态设置属性,就相当于case.case_id=1给实例设置一个属性,只是上面所举例是循环地把整个列表的数据拆分成4个实例的属性。

同样的,python中对应还有一个getattr(object, name)内置函数,它是用于返回一个实例的属性,需要两个参数,一个是对象名,一个是属性名,返回该属性的属性值,这里不再举例,自己使用一下吧!

另外,上述例子中最后还用到了一个__dict__对象属性,它是用于获取实例对象的所有属性,并以字典的形式返回。

原文地址:https://www.cnblogs.com/miki-peng/p/12245008.html

时间: 2024-10-21 04:59:19

17、类的自定义属性访问及动态属性设置的相关文章

实体类、数据访问类、属性扩展

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 实体类_数据访问类.App_Code { public class Users { private string _username; //封装 /// <summary> /// 用户名 /// </summary> public

只能通过类而不能通过类的实例访问常量属性

1.静态属性.静态方法 在面向对象编程中,我们不仅可以通过对象访问方法和属性,还可以通过类来访问它们.这样的方法和属性就是“静态的”(static),必须用static关键字来声明. [php] view plaincopyprint? class staticExample { staticpublic $num = 0; staticpublic function sayNum() { echoself::num; } } 静态方法是以类作为作用域的函数.静态方法不能访问这个类中的普通属性,

Windows Azure Storage (17) Azure Storage读取访问地域冗余(Read Access – Geo Redundant Storage, RA-GRS)

<Windows Azure Platform 系列文章目录> 细心的用户会发现,微软在国外和国内的数据中心建设都是成对的,比如香港数据中心(Asia East)和新加坡的数据中心(South East Asia).这是因为微软充分考虑了异地冗余的能力.在两对数据中心之间,比如香港和新加坡,会有专线连接,这个专线是内网数据中心之前数据同步专用的. 一般情况下,主节点和备用节点的对应关系如下: Primary Secondary North Central US South Central US

C++——派生类中的访问——可见性问题

C++中派生类对基类成员的访问形式主要有以下两种: 1.内部访问:由派生类中新增成员对基类继承来的成员的访问. 2.对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问.今天给大家介绍在3中继承方式下,派生类对基类成员的访问规则. 1.私有继承的访问规则 当类的继承方式为私有继承时,基类的public成员和protected成员被继承后成为派生类的private成员,派生类的其它成员可以直接访问它们,但是在类的外部通过派生类的对象无法访问.基类的private成员在私有派生类中是不

python-面向对象(四)——类成员的访问方式汇总

类成员的访问方式 #!/usr/bin/env python # _*_coding:utf-8 _*_ class pepole(object): '''This is __doc__ information!!!''' country = "CHINA" #静态字段 存在类里 __city = "BeiJing" #私有静态字段 def siyou(self): #私有字段在内部设置方法可以访问 return pepole.__city def __init__

Java日志组件logback使用:加载非类路径下的配置文件并设置定时更新

Java日志组件logback使用:加载非类路径下的配置文件并设置定时更新 摘自: https://blog.csdn.net/johnson_moon/article/details/78874499 2017年12月22日 16:20:29 阅读数:868 标签: javalogback日志配置文件logback-xm 更多 个人分类: Java日志 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/johnson_moon/article/d

重要!!!实体类、数据访问类

创建两个类: users类: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 实体类_数据访问类.App_Code { public class Users { private int _Ids; /// <summary> /// ids /// </summary> public int Ids { get { return _Ids;

实体类、数据访问类中的属性拓展

类中: using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; using System.Text; namespace 实体类_数据访问类.App_Code { public class Users { SqlConnection conn = null; SqlCommand cmd = null; public Users() { conn = new S

C++的继承操作---基类指针访问派生类问题---基类成员恢复访问属性问题

#include "stdafx.h" #include <iostream> #include <algorithm> using namespace std; class Base { public: int num; virtual void func() { cout<<"Do something in Base"<<endl; } }; class Derived:private Base { public: