Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add __slots__ entries. #4637

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

Open
knotapun wants to merge 3 commits into pymupdf:main
base: main
Choose a base branch
Loading
from knotapun:much-improve
Open

Add __slots__ entries. #4637

knotapun wants to merge 3 commits into pymupdf:main from knotapun:much-improve

Conversation

Copy link

@knotapun knotapun commented Jul 29, 2025

Hello, all this does is add a __slots__ entry to a few classes. this small change makes an outsized impact, reducing the size of instances dramatically, and leads the way to efficient and fully typed page extraction.

from pympler import asizeof
class Rect:
 def __init__(self, a, b, c, d):
 self.x0: float = float(a)
 self.y0: float = float(b)
 self.x1: float = float(c)
 self.y1: float = float(d)
class RectWSlot:
 __slots__ = ("x0", "y0", "x1", "y1")
 def __init__(self, a, b, c, d):
 self.x0: float = float(a)
 self.y0: float = float(b)
 self.x1: float = float(c)
 self.y1: float = float(d)
print(asizeof.asizeof(Rect(1, 2, 3, 4))) # 624
print(asizeof.asizeof(RectWSlot(1, 2, 3, 4))) # 160

Copy link
Author

I noticed the reasoning for non-typed values on the Structure of Dictionary Outputs section.

If this pull gets merged, would you accept a pull that types the dictionaries?

Copy link
Collaborator

Thanks for the idea - and you are quite right: we should have considered doing this.
Before we accept: could you please extend this PR to the Matrix class please? The slots here would carry the names "a" through "f".

@JorjMcKie JorjMcKie self-requested a review August 15, 2025 21:31
Copy link
Collaborator

@JorjMcKie JorjMcKie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please extend this idea to the remaining "geometry" class Matrix.

Copy link
Author

please extend this idea to the remaining "geometry" class Matrix.

Gladly! Note, this might be kind of limited in it's effectiveness because of some upstream code, namely the swig generated code. Seems easy enough to add.

Copy link
Collaborator

I think the test failures can be fixed by deleting IdentityMatrix's __setattr__() method. Could you try doing this in your PR?

[Presumably this was somehow forcing the creation of a __dict__ and so messing up lookups of in __slots__.]

Copy link
Author

Apologies, I've been trying to get a job, and I'm helping someone move. I also just found out how to run your tests locally via act, so it's a bit easier to make commits/changes.

Copy link
Author

I think the test failures can be fixed by deleting IdentityMatrix's __setattr__() method.

You have to be careful with that, as you don't want someone to change the identity matrix to be anything else.

Copy link
Collaborator

JorjMcKie commented Aug 29, 2025
edited
Loading

I haven't tested it but the only reason for the existence of pymupdf.IdentityMatrix is its immutability. This is ensured by __setattr__().
So deleting this method also deletes the reason for having IdentityMatrix at all.
(削除) I could think of a way out: (削除ここまで)
(削除) Define this object as a @property (削除ここまで)
Sorry, that will not work either!

Copy link
Collaborator

I think best is to give up supplying Matrix with slots.

Copy link
Collaborator

This passes tests for me:

class IdentityMatrix(Matrix):
 def __init__(self):
 # Deliberately do not call Matrix.__init__(self).
 pass
 
 @property
 def a(self):
 return 1
 
 @property
 def b(self):
 return 0
 
 @property
 def c(self):
 return 0
 
 @property
 def d(self):
 return 1
 
 @property
 def e(self):
 return 0
 
 @property
 def f(self):
 return 0
Identity = IdentityMatrix()
assert Identity.a == 1
assert Identity.b == 0
try:
 Identity.a = 23
except Exception:
 pass
else:
 assert 0
  • The error from Identity.a = 23 is AttributeError: property 'a' of 'IdentityMatrix' object has no setter.
  • Instances of IdentityMatrix() will not benefit from the __slots__ optimisation, but this probably doesn't matter.
JorjMcKie reacted with hooray emoji

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Reviewers

@JorjMcKie JorjMcKie JorjMcKie approved these changes

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /