Here comes the necromancer.
If AttributeError is thrown on attempting to write to a read-only attribute, as should happen, you catch:
def isro(o,attr):
v=getattr(o,attr);
try:
setattr(o,attr,v);
return False;
except AttributeError:
return True;
^Here we attempt to write with the already existing value, assumed to be valid for attr. If it fails, it's read only. Else it's not.
A simplistic test, to which there might be edge cases. Feel free to point them out if you know them.
I do not think this check would be fast if done in bulk, however; haven't tested. But my gut says filter out the read-only attributes in such cases:
filtered=[
attr for attr in attr_list
if not isro(o,attr)
];
You run the check once per attribute, as opposed to per attribute for each object: should be the more performant approach is what my senses tell me. What remains then is walking through the filtered list of attributes.
Again, feel free to point out anything missing. This is just the quick-n-dirty I applied to solve this issue for myself.
Ta-ta.
@property? What about interference via__getattr[ibute]__/__setattr__?)