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/

Reply via email to