-
Notifications
You must be signed in to change notification settings - Fork 181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
prevent erroneous setting of dps/prec on mpmath module #678
Conversation
What we really want for Issue mpmath#657 is an exception on write access. Instead here is a partial implementation for read access. Not even close to a solution sadly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt this will fix the issue. Misunderstanding starts with setting dps/prec attributes...
This really doesn't work very well, not sure I understand why:
eh? I was expecting an exception. So unless I've done this wrong PEP 562 really doesn't offer much control here. |
Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
Unfortunately, this is not like the property attribute on classes. If 'dps' exists in the namespace of the module - the
Certainly not. |
Fixes Issue mpmath#657. Co-authored-by: Warren Weckesser <warren.weckesser@gmail.com>
It seems, release notes (CHANGES) update happens just before release. Probably, it's a good idea to automate this and keep things more up to date. But don't worry here. Yes, lets add tests. Shouldn't be hard. I don't think there is any performance penalty. @oscarbenjamin? UPD: And, BTW, this fix #657 |
Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
Well, I see measurable (~2x) speed regression for attribute access. Not sure if this is significant for the mpmath, however. An example: $ cat b.py
x = 1
$ python -m timeit -r11 -s 'import b' 'b.x'
5000000 loops, best of 11: 48.8 nsec per loop
$ cat c.py
import sys, types
x = 1
class _Foo(types.ModuleType): pass
sys.modules[__name__].__class__ = _Foo
del sys, types
$ python -m timeit -r11 -s 'import c' 'c.x'
2000000 loops, best of 11: 131 nsec per loop No speed regression for this scenario on my branch with $ cat d.py
x = 1
def __setattr__(name, value):
if name == 'spam':
raise AttributeError
globals()[name] = value
$ python -m timeit -r11 -s 'import d' 'd.x'
5000000 loops, best of 11: 48.8 nsec per loop |
I don't know if this is significant here or not... I figure it potentially matters when calling frunctions from
import mpmath
def test1():
f = mpmath.sin
for i in range(0, 1000):
f(i / 10)
def test2():
for i in range(0, 1000):
mpmath.sin(i / 10)
So its insignficant there, compared to the computation cost. Of course, if I remove the computation, then I see the same results as @skirpichev: import mpmath
def test1():
f = mpmath.sin
for i in range(0, 1000):
f
def test2():
for i in range(0, 1000):
mpmath.sin
So is there some situation where one would tight-loop access to an attribute of Even if we cannot think of a "real life" example here, it definitely sounds like a point to make if you submit a PEP! |
Here's an example, only one letter different import mpmath
def test1():
f = mpmath.sign
a = 0
for i in range(0, 1000):
a += f(i)
def test2():
a = 0
for i in range(0, 1000):
a += mpmath.sign(i)
And we see the slow down in a vaguely real-life example... |
Something like
Of course, all this can be workarounded by using test1() layout (or
Unfortunately, I don't see too much usage examples for this "feature". And mpmath's case seems to be very special. What else? To prevent mutations of the module |
I think that replacing the module in Being able to define It would be better to focus on designing an interface for precision control that is less prone to mistakes and misunderstanding. |
Could you provide an example? We can't reject pr only on the ground of unspecified potential problems.
I doubt it will be accepted. (As I said above, there are no good practical examples of why it could be helpful.) But if it will - we can switch the present workaround to that solution.
Actually, Python does support customizing module attribute access, it is only slow. The recommended way in the CPython docs is exactly how things are implemented in this pr. UPD, FYI: python/cpython#67175 |
@fredrik-johansson, how this solution looks for you? |
I think this could be merged as-is, I will do this on monday. Unfortunately, from the discussion thread it seems for me, that proposing a PEP for
|
I don't have any specific examples. My experience is that when you do something like this it seems like you can reason about whether it should work but then something somewhere else turns out to have made some assumptions that will be broken as a result of the change. I think it would be better to reflect on whether setting a global dps attribute is actually a good interface in the first place (I don't think it is) rather than making the change here to give an error for someone who sets the attribute on the wrong object. After that I would consider whether the docs can be improved so that the mistake is less likely. After that I would just do nothing. It isn't ultimately necessary to do anything in response to gh-657: sometimes an issue is just an issue but does not need to be "fixed". |
Perhaps we should just leave this open, then see if such an alternative interface as @oscarbenjamin describes) can be developed. If no such alternative materializes then we can revisit this, say in 6 months or so. To be concrete: if the docs in the dev tree are are still recommending |
Good news. Then I don't see technical objections: this pr does very tiny and fine grained customization of the module behavior, exactly on the way the official docs recommends.
I think we all agreed that the context management could be better. But this is much more complex change (and probably with API breakage).
This is a common gotcha for mpmath users (2-3 duplicates of this issue were mentioned in the issue thread), that's why I would like to include some fix in the next (minor?) release. Alternatively, we can add something to the docs (as a note/warning or a dedicated section), but this solution seems much better for me: it just forbids wrong scenarios of altering context attributes. |
I think it's worth at least trying out #657 (comment). It's much less invasive. I think if we put the check in the right place it won't be a major performance issue. |
Ok. |
I don't see any reason to wait until 2024: if you're going to do it then just do it now. Personally I would not do this now or later because it would be better to fix the interface design rather than add hacky workarounds to make the current interface slightly less confusing. Especially there should be no noticeable performance penalty for users who are using mpmath correctly just to provide better error messages to someone who uses it incorrectly. It would be better to have an interface that does not depend on either attribute access or setting global variables at all and the docs could easily recommend that: from mpmath import make_context
mp = make_context(real=True, dps=100) Note this from the README:
I suggest that we think about what is (or could be) a good recommended way for users to use |
I've opened an issue #683
I don't think there is a practical performance penalty.
@asmeurer, I doubt there is such "right place". You will have to do it differently for every context (mp, fp, etc). E.g. for the mp context you, probably, should adapt defun* decorators, for the fp - |
Ok, I'm going to merge this in few days. Regardless on the PEP fate (python/steering-council#216) - we don't have yet a better workaround for the issue. |
Thanks |
Thanks, all! |
What we really want for Issue #657 is an exception on write access. Instead here is a partial implementation for read access. Not even close to a solution sadly.update: exceptions on write access to
.dps
and.prec
inmpmath
module.Todo list
depends on Drop support for old py3 versions (<3.8) #663any performance concerns?potential changelog entry
My feeling is this maybe doesn't need a changelog, but just in case here's one:
Closes #657