TL; DR:hasattr
是否有不触发属性获取器的替代方法?
我正在为一些现有代码编写Python接口,在其中获取和设置各种形状和截面类的值。由于存在大量可能的组合,因此我目前动态创建新类,将SectionHandler
类和形状类(例如Circle
)子类化。每个都有我要保留的特定方法。
由于此API将用于脚本中并以交互方式使用,因此我想确保在类实例化之后修改的所有属性都已经存在(这样,就不能从错别字创建新属性,并且当不存在时会警告用户属性)。由于此检查需要“跳过”子类化过程中添加的所有新属性,因此我使用type
函数中的属性字典将属性预加载到新类中(下面由name
和index
个属性)。
我正在使用hasattr
通过覆盖__setattr__
来检查创建的类中的属性是否存在,如this SO post中所建议。当属性不存在,但问题出在属性确实存在时,此方法起作用-因为hasattr
似乎可以通过调用属性getter来工作,所以我从getter那里获得了不必要的日志记录调用,这污染了许多属性修改的日志(尤其是较长的邮件)。
还有另一种方法来检查动态生成的类中的类属性吗?我尝试在self.__dict__
中查找而不是使用hasattr
,但是该字典在类创建时为空。有什么替代品?
我尝试给出一个最小的工作示例,以反映我正在使用的结构:
import logging
class CurveBase:
"""Base class for all curves/shapes."""
def __setattr__(self, attr, value):
"""Restrict to setting of existing attributes only."""
if hasattr(self, attr):
return super().__setattr__(attr, value)
else:
raise AttributeError(f'{attr} does not exist in {self.__class__.__name__}')
class Circle(CurveBase):
"""Circle-type shape base class."""
@property
def diameter(self):
logging.info(f'Getting {self.name} section {self.index} diameter')
# diameter = external_getter("Circle_Diameter")
# return diameter
@diameter.setter
def diameter(self, diameter):
logging.info(f'Setting {self.name} section {self.index} diameter to: {diameter}')
# external_setter("Circle_Diameter", diameter)
class SectionHandler:
def __init__(self):
# Minimal example init
self.name = 'section_1'
self.index = 1
if __name__ == '__main__':
# This is set up by the API code
logging.basicConfig(level='INFO', format='%(asctime)s - %(levelname)s - %(message)s')
shape = 'circle'
attribute_dict = {'name': None, 'index': None} # Generated based on classes used.
NewSectionClass = type(f'{shape.capitalize()}Section',
(SectionHandler, Circle),
attribute_dict)
section = NewSectionClass()
# This is an example of API usage
print(section.diameter)
# Returns:
# 2018-12-04 18:53:07,805 - INFO - Getting section_1 section 1 diameter
# None # <-- this would be a value from external_getter
section.diameter = 5
# Returns:
# 2018-12-04 18:53:07,805 - INFO - Getting section_1 section 1 diameter # <-- extra getter call from hasattr()!!!
# 2018-12-04 18:53:07,805 - INFO - Setting section_1 section 1 diameter to: 5
section.non_existent
# Correctly returns:
# Traceback (most recent call last):
# File "scratch_1.py", line 50, in <module>
# section.non_existent
# AttributeError: 'CircleSection' object has no attribute 'non_existent'
答案 0 :(得分:0)
您必须尝试调用 <Object>.__getattribute__()
并捕获错误
这样的东西可以工作
class CurveBase:
"""Base class for all curves/shapes."""
def __setattr__(self, attr, value):
"""Restrict to setting of existing attributes only."""
try:
super().__getattribute__(attr)
return super().__setattr__(attr, value)
except:
raise AttributeError(f'{attr} does not exist in {self.__class__.__name__}')
getattr_static()
来自 inspect
模块,如所描述的 here__getattribute__
try catch 包装到 bool 函数中,就像第 1 点的答案一样。__getattribute__