Steven D'Aprano wrote:
> On Tue, Aug 13, 2019 at 06:01:27PM -0400, Eric V. Smith wrote:
> > dataclasses does something similar: it wants to know
> > if something is a
> > typing.ClassVar, but it doesn't want to import typing to find out.
> > Why not? Is importing typing especially expensive or a bottleneck?
> Wouldn't it be a once-off cost?
> > So it has:
> > typing = sys.modules.get('typing')
> > if typing:
> > if (_is_classvar(a_type, typing)
> > or (isinstance(f.type, str)
> > and _is_type(f.type, cls, typing, typing.ClassVar,
> > _is_classvar))):
> >
> > If typing hasn't been imported, it knows that a_type can't be
> > typing.ClassVar.
> > That's very clever, but alas it's not clever enough because its false.
> Or rather, it's false in general. ClassVar is magic, it can't be used
> with isinstance() or issubclass(), so I won't argue about the above
> snippet. I don't understand it well enough to argue its correctness.
> But for regular classes like Decimal, this clever trick doesn't always
> work. Here's an example:
> py> import decimal
> py> x = decimal.Decimal()
> py> del decimal
> py> del sys.modules['decimal']
> At this point, we have a Decimal instance, but no "decimal" in the
> module cache. Your test for whether x is a Decimal will wrongly deny x
> is a Decimal:
> # the wrong way to do it
> py> _decimal = sys.modules.get('decimal')
> py> isinstance(x, _decimal.Decimal) if _decimal else False
> False
> but if we're a bit less clever, we get the truth:
> py> import decimal
> py> isinstance(x, decimal.Decimal)
> True
> You can't rely on the presence of 'decimal' in the module cache as a
> proxy for whether or not x might be a Decimal instance.
The `isinstance` check doesn't necessarily prevent tampering:
import decimal
d = decimal.Decimal('1.23')
# oops (1)
decimal.Decimal = type('Decimal', tuple(), {})
# oops (2)
import sys
sys.modules['decimal'] = type('decimal', tuple(),
dict(Decimal=type('Decimal', tuple(), {})))
# oops (3)
import sys
del sys.modules['decimal']
with open('decimal.py', 'w') as fh:
fh.write('Decimal = type("Decimal", tuple(), {})')
import json
json.dumps(d)
But I agree that this is reasonably weird to not be expected.
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/LNYZUJIA2ZZVJN5UL4EUXBSDTK5AZ4ZX/
Code of Conduct: http://python.org/psf/codeofconduct/