Python-VBA函数之旅-setattr函数

目录

一、setattr函数的常见应用场景

二、setattr函数使用注意事项

三、如何用好setattr函数?

1、setattr函数:

1-1、Python:

1-2、VBA:

2、推荐阅读:

个人主页: https://blog.csdn.net/ygb_1024?spm=1010.2135.3001.5421

一、setattr函数的常见应用场景

        setattr函数在Python中有广泛的应用场景,特别是在动态实现类属性或方法、元编程(metaprogramming)以及处理对象时不知道具体属性名的情况下,常见的应用场景有:

1、动态实现类属性或方法:当你不确定类的所有属性或方法时,可以在运行时使用setattr()函数动态地添加它们,这可以用于创建可扩展的类,或者根据外部配置动态地添加功能。

2、简化对象属性的批量设置:如果你有一个对象,并且需要从字典或其他数据源中设置多个属性,setattr()函数可以帮助你简化这个过程。

3、实现代理对象或装饰器:在代理对象或装饰器模式中,你可能需要拦截对某个对象的属性访问,并在访问之前或之后执行一些操作,你可以使用setattr()函数来动态地修改被代理对象的属性。

4、结合描述符(Descriptors)使用:描述符是Python中一个强大的特性,允许你控制对对象属性的访问,当描述符与setattr()函数结合使用时,你可以实现更复杂的属性访问逻辑。

5、序列化和反序列化:在处理自定义对象的序列化和反序列化时,setattr()函数可以帮助你根据序列化的数据动态地设置对象的属性,这在处理JSON、XML或其他格式的数据时特别有用。

6、元编程:在元编程中,你编写操作其他代码的代码,setattr()函数允许你动态地修改对象的结构,这在创建代理、装饰器、元类等高级编程概念时非常有用。

7、处理用户输入:如果你正在编写一个接受用户输入并动态设置对象属性的程序,setattr()函数可以帮助你根据用户输入来设置属性。

        注意,过度使用setattr()函数可能会使代码难以理解和维护,因为它破坏了对象的明确性和封装性,因此,在使用setattr()函数时应该谨慎,并确保你的代码清晰、可读和可维护。

二、setattr函数使用注意事项

        在Python中,setattr()是一个内置函数,用于设置对象的属性值,它的基本用法是setattr(object, name, value),其中,object是你想要修改其属性的对象,name是属性的名称(作为一个字符串),而value是你想要设置的新值。

在使用setattr()函数时,需注意以下事项:

1、属性名称作为字符串:name参数必须是一个字符串,它指定了你想要设置的属性的名称,如果你尝试使用一个非字符串值,Python会抛出一个TypeError异常。
2、不存在的属性:如果对象没有名为name的属性,setattr()会创建一个新的属性,但是,如果你试图设置一个只读属性(如某些内置类型或扩展类型中的属性),可能会引发异常。
3、隐藏或覆盖内置方法:如果你使用setattr()函数设置了一个与对象现有方法同名的属性,那么这个方法将被该属性隐藏或覆盖,这可能会导致意外的行为,特别是如果后来你尝试调用那个方法但忘记了已经被覆盖。
4、动态属性:虽然setattr()函数允许你动态地设置对象的属性,但这并不意味着你应该滥用它,过度使用动态属性可能会使代码难以理解和维护,在可能的情况下,最好明确地在类定义中声明属性。
5、安全性:setattr()函数可以被用于修改对象的任何属性,包括私有属性(在Python中,以双下划线开头的属性名称被认为是私有的),这可能会破坏对象的内部状态,并导致不可预测的行为,因此,在使用setattr()函数时,你应该非常小心,确保你只修改你真正想要修改的属性。
6、异常处理:在设置属性时,可能会发生各种异常,如AttributeError(如果尝试访问不存在的属性)或TypeError(如果属性类型与赋值不兼容),你应该准备好处理这些异常,以防止程序崩溃。
7、性能:虽然setattr()函数在大多数情况下都足够快,但在某些情况下,频繁地使用它可能会导致性能问题,如果你需要频繁地设置大量属性,可能需要考虑其他更高效的方法。
8、结合getattr()/delattr()使用:getattr()/delattr()是另外两个与setattr()相关的内置函数,它们分别用于获取和删除对象的属性,在编写处理对象属性的代码时,这三个函数通常会一起使用。

三、如何用好setattr函数?

        要在Python中妥善使用setattr()函数,你需遵循以下建议:

1、明确目的:首先,确定你为何需要使用setattr()函数?在大多数情况下,直接在类定义中声明属性或使用常规的赋值语法是更简单、更直观的选择,如果你确实需要动态地设置属性,那么setattr()函数是一个有用的工具。

2、避免覆盖内置方法:在调用setattr()函数时,确保你没有意外地覆盖对象的内置方法或属性,你可以通过检查name参数的值来避免这种情况。

3、考虑封装:如果你经常需要动态地设置属性,可以考虑将setattr()的调用封装到一个类或方法中,这样可以隐藏底层复杂性,并提供一个更清晰的接口给调用者。

4、使用字典代替属性:如果你需要存储大量的动态属性,并且不关心它们作为对象的属性暴露给外部代码,那么使用字典来存储这些属性可能是一个更好的选择。字典提供了灵活的键值对存储,并且你可以使用dict.get(), dict.setdefault() 和dict.update()等方法来操作它们。

5、处理异常:当使用setattr()函数时,要准备好处理可能发生的异常,如AttributeError(如果尝试访问不存在的属性)或TypeError(如果赋值类型不兼容),你可以使用try/except块来捕获这些异常,并相应地处理它们。

6、文档化:如果你在你的代码中使用setattr()函数,确保在相关的文档或注释中解释清楚它的用途和潜在的影响,这可以帮助其他开发者更好地理解你的代码,并避免意外的副作用。

7、测试:编写测试用例来验证你使用setattr()函数的代码的正确性。确保你的测试覆盖了各种情况,包括正常情况和异常情况,这可以帮助你发现潜在的问题,并确保你的代码在所有预期的情况下都能正常工作。

8、谨慎使用:尽管setattr()函数在某些情况下很有用,但它也可能导致代码难以理解和维护,因此,你应该谨慎地使用它,并确保你的代码在不需要动态属性时仍然能够正常工作。

1、setattr函数:
1-1、Python:
# 1.函数:setattr
# 2.功能:用于设置对象的属性值
# 3.语法:setattr(object, name, value)
# 4.参数:
# 4-1、object:对象
# 4-2、name:字符串,表示对象属性
# 4-3、value:属性值
# 5.返回值:无
# 6.说明:
# 7.示例:
# 用dir()函数获取该函数内置的属性和方法
print(dir(setattr))
# ['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
# '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name__',
# '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__',
# '__str__', '__subclasshook__', '__text_signature__']# 用help()函数获取该函数的文档信息
help(setattr)# 应用一:动态实现类属性或方法
# 示例1:动态设置类实例的属性
class MyClass:def __init__(self):self.existing_attribute = 'I exist!'
# 创建一个类的实例
instance = MyClass()
# 使用setattr()动态地添加一个属性
setattr(instance, 'my_weight', '70.6kg')
# 访问动态添加的属性
print(instance.my_weight)
# 70.6kg# 示例2:动态设置类的方法
class MyClass:def existing_method(self):print('I am an existing method!')
# 创建一个类的实例
instance = MyClass()
# 定义一个要动态添加的方法
def dynamic_method(self):print('I am a dynamically added method!')
# 使用setattr()动态地添加一个方法
setattr(MyClass, 'dynamic_method', dynamic_method)
# 在类的实例上调用动态添加的方法(注意:我们是在类上添加的方法,所以所有实例都可以访问)
instance.dynamic_method()
# I am a dynamically added method!# 示例3:动态设置类的属性(即类变量)
class MyClass:existing_class_variable = 'I am a class variable!'
# 使用setattr()动态地添加一个类变量
setattr(MyClass, 'dynamic_class_variable', 'I was dynamically added as a class variable!')
# 访问动态添加的类变量(通过类本身或其实例)
print(MyClass.dynamic_class_variable)  # 输出: I was dynamically added as a class variable!
print(MyClass().dynamic_class_variable)  # 同样输出: I was dynamically added as a class variable!
# I was dynamically added as a class variable!
# I was dynamically added as a class variable!# 应用二:简化对象属性的批量设置
class Person:def __init__(self):self.name = Noneself.age = Noneself.city = None
# 创建一个Person实例
person = Person()
# 使用字典来存储要设置的属性值
attributes = {'name': 'Myelsa','age': 18,'city': 'Guangzhou'
}
# 使用setattr()批量设置属性
for key, value in attributes.items():setattr(person, key, value)
# 验证属性是否设置成功
print(person.name)
print(person.age)
print(person.city)
# Myelsa
# 18
# Guangzhou# 应用三:实现代理对象或装饰器
class Proxy:def __init__(self, obj):self._obj = objdef __setattr__(self, name, value):# 检查是否是要拦截的属性if name.startswith('_'):# 如果以'_'开头,则直接设置到代理对象本身super().__setattr__(name, value)else:# 否则,拦截对_obj属性的设置,并可能添加一些额外的逻辑print(f"Intercepted setattr for {name}. Original value: {getattr(self._obj, name, 'None')}")# 在这里可以添加一些逻辑,比如验证、转换等# ...# 设置值到_objsetattr(self._obj, name, value)print(f"Set {name} to {value} in the original object.")def __getattr__(self, name):# 如果访问的属性不存在于代理对象本身,则转发到_objreturn getattr(self._obj, name)
class MyClass:def __init__(self):self.x = 10
# 创建一个MyClass实例和一个代理对象
obj = MyClass()
proxy = Proxy(obj)
# 尝试设置代理对象的属性
proxy.x = 20
# 尝试访问代理对象的属性
print(proxy.x)
# Intercepted setattr for x. Original value: 10
# Set x to 20 in the original object.
# 20# 应用四:结合描述符(Descriptors)使用
class BoundedDescriptor:def __init__(self, name, lower=None, upper=None):self.name = nameself.lower = lowerself.upper = upperself._value = Nonedef __get__(self, instance, owner):if instance is None:return selfreturn self._valuedef __set__(self, instance, value):if self.lower is not None and value < self.lower:raise ValueError(f"{self.name} must be greater than or equal to {self.lower}")if self.upper is not None and value > self.upper:raise ValueError(f"{self.name} must be less than or equal to {self.upper}")self._value = valueprint(f"Setting {self.name} to {value}")def __delete__(self, instance):raise AttributeError("Cannot delete the descriptor")
class MyClass:x = BoundedDescriptor('x', 0, 10)
# 创建一个MyClass的实例
obj = MyClass()
# 使用setattr()设置属性(这实际上是调用描述符的__set__方法)
setattr(obj, 'x', 5)  # 输出: Setting x to 5
print(obj.x)  # 输出: 5
# 尝试设置一个超出范围的值
try:setattr(obj, 'x', -1)
except ValueError as e:print(e)  # 输出: x must be greater than or equal to 0
# 尝试删除描述符(会引发异常)
try:delattr(obj, 'x')
except AttributeError as e:print(e)  # 输出: Cannot delete the descriptor
# Setting x to 5
# 5
# x must be greater than or equal to 0
# Cannot delete the descriptor# 应用五:序列化和反序列化
class Person:def __init__(self, name, age):self.name = nameself.age = agedef __repr__(self):return f"Person(name={self.name}, age={self.age})"
def serialize_person(person):"""将Person对象序列化为字典"""return {'name': person.name,'age': person.age}
def deserialize_person(data):"""从字典反序列化为Person对象"""person = Person(None, None)  # 创建一个空的Person对象for key, value in data.items():setattr(person, key, value)  # 使用setattr()设置属性return person
# 示例用法
# 序列化
person = Person("Myelsa", 18)
serialized_data = serialize_person(person)
print(serialized_data)
# 反序列化
deserialized_person = deserialize_person(serialized_data)
print(deserialized_person)
# {'name': 'Myelsa', 'age': 18}
# Person(name=Myelsa, age=18)# 应用六:元编程
class DynamicClass:def __init__(self):# 用于存储动态方法的字典self._dynamic_methods = {}def add_method(self, name, func):"""动态地添加一个方法到类中"""setattr(self, name, func)# 同时将方法存储在字典中以便后续可能的操作self._dynamic_methods[name] = funcdef remove_method(self, name):"""动态地移除一个方法"""if hasattr(self, name):delattr(self, name)if name in self._dynamic_methods:del self._dynamic_methods[name]def list_methods(self):"""列出所有的动态方法(不包括内置方法)"""return list(self._dynamic_methods.keys())
# 示例函数
def hello_world():print("Hello, world!")
def greet(name):print(f"Hello, {name}!")
# 创建一个DynamicClass的实例
dynamic_instance = DynamicClass()
# 动态地添加一个方法
dynamic_instance.add_method('hello', hello_world)
# 调用动态添加的方法
dynamic_instance.hello()  # 输出: Hello, world!
# 列出所有的动态方法
print(dynamic_instance.list_methods())  # 输出: ['hello']
# 动态地添加另一个方法,这次使用lambda表达式
dynamic_instance.add_method('greet_by_name', lambda name: greet(name))
# 调用通过lambda添加的方法
dynamic_instance.greet_by_name('Myelsa')  # 输出: Hello, Myelsa!
# 移除一个方法
dynamic_instance.remove_method('hello')
# 再次列出所有的动态方法
print(dynamic_instance.list_methods())  # 输出: ['greet_by_name']
# 尝试调用已被移除的方法
# dynamic_instance.hello()  # 这将引发 AttributeError
# Hello, world!
# ['hello']
# Hello, Myelsa!
# ['greet_by_name']# 应用七:处理用户输入
class UserDefinedAttributes:def __init__(self):# 初始化一个空字典来存储用户定义的属性self._user_attributes = {}def set_attribute(self, name, value):# 检查属性名是否以"user_"开头,以限制可设置的属性范围if name.startswith("user_"):# 使用setattr()来设置属性setattr(self, name, value)# 同时将属性存储在字典中,以便后续可能的操作或检查self._user_attributes[name] = valueprint(f"Attribute {name} set to {value}")else:print(f"Error: Cannot set attribute {name}. Only attributes starting with 'user_' are allowed.")def get_attribute(self, name):# 检查属性是否存在if hasattr(self, name):return getattr(self, name)else:print(f"Error: Attribute {name} does not exist.")return Nonedef list_attributes(self):# 列出所有用户定义的属性return list(self._user_attributes.keys())
# 示例用法
obj = UserDefinedAttributes()
# 获取用户输入
name = input("Enter attribute name (must start with 'user_'): ")
value = input("Enter attribute value: ")
# 尝试设置属性
obj.set_attribute(name, value)
# 列出所有用户定义的属性
print("User defined attributes:")
for attr in obj.list_attributes():print(f"{attr}: {obj.get_attribute(attr)}")
# 尝试获取并打印一个属性
attr_to_get = input("Enter attribute name to get (or 'exit' to quit): ")
if attr_to_get.lower() != 'exit':print(f"Value of {attr_to_get}: {obj.get_attribute(attr_to_get)}")
else:print("Exiting...")
1-2、VBA:
略,待后补。
2、推荐阅读:

2-1、Python-VBA函数之旅-round()函数

Python算法之旅:Algorithm

Python函数之旅:Functions

个人主页: 神奇夜光杯-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/10412.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

宏集Panorama SCADA软件获BACnet BTL认证

Panorama 获得BACnet BTL认证 建筑物的组件&#xff08;空调系统、照明传感器等&#xff09;能否使用共同通讯协议&#xff1f;这正是标准化 BACnet协议&#xff08;Building Automation and Control Networks&#xff09;所提供的功能。该协议旨在实现建筑物中各种设备和系统…

【TS】入门

创建项目 vscode自动编译ts 生成配置文件 tsc --init 然后发现终端也改变了&#xff1a;

SOCKET编程(3):相关结构体与函数

相关结构体与函数 sockaddr、sockaddr_in结构体 sockaddr和sockaddr_in详解 struct sockaddr共16字节&#xff0c;协议族(family)占2字节&#xff0c;IP地址和端口号在sa_data字符数组中 /* Structure describing a generic socket address. */ struct sockaddr {__SOCKADDR…

抓大鹅教程电脑端秒通关……

大家好&#xff0c;我是小黄。 最近抓大鹅小程序游戏很火&#xff0c;抓大鹅小游戏是由青岛蓝飞互娱科技股份有限公司开发并推出的一款休闲益智类三消游戏。在游戏中&#xff0c;玩家需要在特定的“购物篮子”背景下&#xff0c;找到三个相同的物品并将其消除。游戏的玩法简单…

社工库信息查询

此网站需要注册账号&#xff0c;新用户注册送3点券&#xff0c;每日签到可获得1.5点券。也可通过充值来查 我这里有方法可以利用缺陷来无限获取点券查人

程序员的归宿。。

大家好&#xff0c;我是瑶琴呀。 相信每个进入职场的人都考虑过自己的职业生涯规划&#xff0c;在不同的年龄段可能面临不同挑战&#xff0c;这点对于 35 的人应该更为感同身受。 对于程序员来说&#xff0c;大部分人的职业道路主要是下面三种&#xff1a;第一条&#xff0c;…

【Delphi 爬虫库 6】使用正则表达式提取猫眼电影排行榜top100

正则表达式库的简单介绍 正则表达式易于使用&#xff0c;功能强大&#xff0c;可用于复杂的搜索和替换以及基于模板的文本检查。这对于输入形式的用户输入验证特别有用-验证电子邮件地址等。您还可以从网页或文档中提取电话号码&#xff0c;邮政编码等&#xff0c;在日志文件中…

人生是旷野,不是轨道

最近看到一句话&#xff0c;很喜欢&#xff0c;分享一下。"人生是旷野&#xff0c;不是轨道"。人生不是固定的方程式&#xff0c;也没有唯一答案&#xff0c;没有谁生来就应该是什么样。别太被太多世俗观念束缚住手脚&#xff0c;每个人都有权利自由生长&#xff0c;…

用友畅捷通T+ keyEdit sql注入漏洞

产品介绍 畅捷通 T 是一款灵动&#xff0c;智慧&#xff0c;时尚的基于互联网时代开发的管理软件&#xff0c;主要针对中小型工贸与商贸企业&#xff0c;尤其适合有异地多组织机构&#xff08;多工厂&#xff0c;多仓库&#xff0c;多办事处&#xff0c;多经销商&#xff09;的…

朋友圈刷屏的粘土风格照片,你体验过了吗?

Remini 的粘土风格真的丑萌丑萌的&#xff01; 从去年“妙鸭相机”的走红&#xff0c;到今年Remini的刷屏&#xff0c;其实可以看出大众对于图片趣玩的兴趣非常大&#xff01; 一张普通的照片经过工具的处理&#xff0c;一下子变成新风格&#xff0c;让人眼前一亮。如果你也对…

GPT-SoVits:语音克隆,语音融合

首发网站 https://tianfeng.space 前言 零样本文本到语音&#xff08;TTS&#xff09;&#xff1a; 输入 5 秒的声音样本&#xff0c;即刻体验文本到语音转换。少样本 TTS&#xff1a; 仅需 1 分钟的训练数据即可微调模型&#xff0c;提升声音相似度和真实感。跨语言支持&…

信息收集方法合集 第1期

前言 在工作中&#xff0c;经常被问到某个文件怎么下载&#xff0c;原文来自哪里。索性把我知道的所有信息收集方法全部整理一遍&#xff0c;希望对大家有用&#xff0c;如果有帮助到你&#xff0c;非常荣幸&#xff0c;我会坚持分享我的学习、工作经验。 信息种类&#xff1…

云启未来:“云计算与网络运维精英交流群”与“独家资料”等你来探索“

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆云计算学堂 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ &#x1f680; 云计算与运维精英交流群诚邀您的加入…

搭建Docker私服镜像仓库Harbor

1、概述 Harbor是由VMware公司开源的企业级的Docker Registry管理项目&#xff0c;它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。 Harbor 的所有组件都在 Dcoker 中部署&#xff0c;所以 Harbor 可使用 Docker Compose 快速部署。 …

PermissionError: [Errno 13] Permission denied: ‘xx.xlsx‘的解决办法

我在转换文件的时候遇到这个报错&#xff0c;原因是文件名与已有文件名重复了 解决办法很简单&#xff0c;如下图把" " 里的名字换成不重复的&#xff0c;再次允许代码&#xff0c;会恢复正常

ue引擎游戏开发笔记(37)——实现敌人接收攻击伤害,并作出反应

1.需求分析&#xff1a; 现在已经显示造成实际伤害&#xff0c;但敌人对实际伤害并未产生反馈&#xff0c;例如还击&#xff0c;或者死亡倒地等等&#xff0c;实现敌人对于受击的反馈。 2.操作实现&#xff1a; 1.思路&#xff1a;在动画蓝图中添加死亡动画&#xff0c;并通过…

【姿态解算与滤波算法】

姿态解算 一、主线 姿态表示方式&#xff1a;矩阵表示&#xff0c;轴角表示&#xff0c;欧拉角表示&#xff0c;四元数表示。 惯性测量单元IMU&#xff08;Inertial Measurement Unit&#xff09;&#xff1a;MPU6050芯片&#xff0c;包含陀螺仪和加速度计&#xff0c;分别测…

winhex工具,将文件转换为16进制数据放入代码。

今天介绍winhex工具&#xff0c;可以将任何内容读取读取为16进制数据。下面看下效果。 下载链接&#xff1a; WinHex: Hex Editor & Disk Editor, Computer Forensics & Data Recovery Software 一、WinHex打开文件 我们要打开的文件&#xff1a; 打开后&#xff1a; 我…

服务器远程桌面局域网连接不上的解决方法

在企业网络环境中&#xff0c;服务器远程桌面局域网连接不上是一个常见且棘手的问题。这种问题可能导致工作效率下降&#xff0c;甚至影响业务运营。因此&#xff0c;我们需要采取专业的方法来解决这一问题。 服务器远程桌面局域网连接不上的解决方法&#xff1a; 1、确保服务器…

解锁网站SEO优势,百度站长工具助您一臂之力(百度站长平台还提供了哪些工具供seo人员使用?)

在当今数字化时代&#xff0c;网站已经成为企业宣传、产品销售、信息发布的主要渠道之一。有着再好的网站&#xff0c;如果在百度等搜索引擎中无法被用户搜索到&#xff0c;那就等于白搭。因此&#xff0c;网站的SEO优化显得尤为重要。而作为国内最大的搜索引擎&#xff0c;百度…