On Tue, Jun 20, 2017 at 10:18 AM, Steven D'Aprano <[email protected]> wrote:
> Apparently you heavily use properties, and __getattr__, and find that
> the two don't interact well together when the property getters and
> setters themselves raise AttributeError. I think that's relevant
> information that helps explain the problem you are hoping to fix.
>
> So I *think* this demonstrates the problem:
>
> class A(object):
> eggs = "text"
> def __getattr__(self, name):
> if name == 'cheese':
> return "cheddar"
> raise AttributeError('%s missing' % name)
> @property
> def spam(self):
> return self.eggs.uper() # Oops.
I'm quoting Steven's post, but I'm addressing the OP.
One good solution to this is a "guard point" around your property functions.
def noleak(*exc):
def deco(func):
@functools.wraps(func)
def wrapper(*a, **kw):
try: return func(*a, **kw)
except exc: raise RuntimeError
return wrapper
return deco
@property
@noleak(AttributeError)
def spam(self):
return self.eggs.uper()
In fact, you could make this into a self-wrapping system if you like:
def property(func, *, _=property):
return _(noleak(AttributeError)(func))
Now, all your @property functions will be guarded: any AttributeErrors
they raise will actually bubble as RuntimeErrors instead.
Making this work with setters and deleters is left as an exercise for
the reader.
ChrisA
_______________________________________________
Python-ideas mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/