Skip to content
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

__slots__ for subclasses of variable length types #41779

Open
mwhudson opened this issue Mar 30, 2005 · 13 comments
Open

__slots__ for subclasses of variable length types #41779

mwhudson opened this issue Mar 30, 2005 · 13 comments
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement

Comments

@mwhudson
Copy link

mwhudson commented Mar 30, 2005

BPO 1173475
Nosy @mwhudson, @rhettinger, @terryjreedy, @ronaldoussoren, @devdanzin, @vadmium
Files
  • var-sized-slots-1.diff: mwh's patch #1
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/arigo'
    closed_at = <Date 2010-08-11.22:03:01.354>
    created_at = <Date 2005-03-30.17:09:14.000>
    labels = ['interpreter-core', 'type-feature']
    title = '__slots__ for subclasses of variable length types'
    updated_at = <Date 2015-03-12.05:25:41.393>
    user = 'https://github.com/mwhudson'

    bugs.python.org fields:

    activity = <Date 2015-03-12.05:25:41.393>
    actor = 'martin.panter'
    assignee = 'arigo'
    closed = True
    closed_date = <Date 2010-08-11.22:03:01.354>
    closer = 'rhettinger'
    components = ['Interpreter Core']
    creation = <Date 2005-03-30.17:09:14.000>
    creator = 'mwh'
    dependencies = []
    files = ['6581']
    hgrepos = []
    issue_num = 1173475
    keywords = []
    message_count = 12.0
    messages = ['48094', '48095', '48096', '48097', '48098', '82173', '110432', '113454', '113615', '113630', '113631', '184641']
    nosy_count = 7.0
    nosy_names = ['mwh', 'rhettinger', 'terry.reedy', 'ronaldoussoren', 'ajaksu2', 'BreamoreBoy', 'martin.panter']
    pr_nums = []
    priority = 'normal'
    resolution = 'wont fix'
    stage = 'patch review'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue1173475'
    versions = ['Python 3.4']

    @mwhudson
    Copy link
    Author

    This is a first, rough cut at allowing subclasses of variable length
    types to have __slots__ of all flavours, not just __dict__.

    The motivation is trying to understand and document what's going on
    in typeobject.c, and the less special cases knocking around the
    better.

    This patch also allows instances of such classes to be weakly
    referenced.

    What is missing: tests, lots of tests, documentation. Also, the code
    is a bit hackish at various points; a degree of clean up can certainly
    be acheived.

    Also, I think my code probably fails to cope with code like:

    class A(str):
     pass # implicitly adds __dict__, __weakref__
    class B(A):
     __slots__ = ["a", "b"]
    
    b = B()
    b.c = 1

    Hmm, yes. Oh well, no time to fix today (I don't think it's that big a
    deal).

    @mwhudson mwhudson added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Mar 30, 2005
    @arigo
    Copy link
    Mannequin

    arigo mannequin commented Apr 3, 2005

    Logged In: YES
    user_id=4771

    I'm confused: the rule for negative slot offsets appear to be different to the one for tp_dictoffset, which only increases the amount of obscurity around here.

    tp_dictoffset counts relative to the end of the object, whereas in your patch negative slot offsets are a different trick to mean "relative to the start but skipping the varsized part". The difference shows up when subclassing increases tp_basicsize. This should be resolved one way or the other -- and I think that a clear picture of the various parts of the object and how they are measured would be a good start.

    That's also related to your proposed change to extra_ivars(), which would become slightly more permissive; I strongly suspect that it would allow more strange segfaulting cases to sneak in undetected...

    @mwhudson
    Copy link
    Author

    mwhudson commented Apr 3, 2005

    Logged In: YES
    user_id=6656

    I'm confused: the rule for negative slot offsets appear to be
    different to the one for tp_dictoffset

    Yes. I think this is actually necessary.

    Consider:

    class S(str):
        __slots__ = ['a']

    you'd except S.__dict__['a'].__offset__ (well, if the attribute existed) to be
    -4.

    Then

    class T(S):
        __slots__ = ['b']

    then using the 'from the end of the object' rule for T().a would actually find
    T.b. (IOW, T.__dict__['b'].__offset__ == T.__dict__['a'].__offset__ == -4).
    The alternative would be to somehow override all the slots in S when T is
    defined -- and this doesn't seem wise.

    __dict__ indeed works differently, because
    instance.__class__.__dictoffset__ is updated on subclassing. You could
    make __dict__ work like the slots mentioned above, but then you'd have to
    find the '__dict__' descriptor every time you wanted to access an
    instance's dictionary, and that would be slow (and might even not really
    work, but I don't want to risk brain-explosion by thinking about it too hard)

    which only increases the amount of obscurity around here.

    Yeah, sorry about that.

    I think something I've realised over the past few days is that __dict__
    really is special. I'm not sure __weakref__ is (though I guess it's special in
    that you want to be able to access it from C without any risk of executing
    Python level code, i.e. replacing Py_GETWEAKREFLIST(ob) with
    PyOjbect_GetAttrString(ob, "__weakref__") would be unfortunate).

    This should be resolved one way or the other

    See above -- don't think you can.

    -- and I think that
    a clear picture of the various parts of the object and how they
    are measured would be a good start.

    No kidding here!

    That's also related to your proposed change to extra_ivars(),
    which would become slightly more permissive; I strongly suspect
    that it would allow more strange segfaulting cases to sneak in
    undetected...

    Almost certainly!

    @arigo
    Copy link
    Mannequin

    arigo mannequin commented Apr 3, 2005

    Logged In: YES
    user_id=4771

    I think it's still possible to give slot.offset the same meaning as tp_dictoffset, even given the additional constrain that it can't change upon subclassing. In your example classes S and T, we can put 'b' before 'a' in memory, so that a.offset==-4 (for both S and T) and b.offset==-8.

    @mwhudson
    Copy link
    Author

    mwhudson commented Apr 3, 2005

    Logged In: YES
    user_id=6656

    Heh, yes that works, and completely hadn't occurred to me.

    @devdanzin
    Copy link
    Mannequin

    devdanzin mannequin commented Feb 15, 2009

    Patch has tests.

    @devdanzin devdanzin mannequin added the type-feature A feature request or enhancement label Feb 15, 2009
    @BreamoreBoy
    Copy link
    Mannequin

    BreamoreBoy mannequin commented Jul 16, 2010

    How much rework if any is needed to get this patch into py3k?

    @terryjreedy
    Copy link
    Member

    I believe this is covered by the PEP-3003 3.2 change moratorium.

    @rhettinger
    Copy link
    Contributor

    ISTM the space saving of value of __slots__ isn't typically needed in the context of variable length built-in types.

    Guido has long regarded __slots__ as a confusing hack. That should warn us away for extending its functionality.

    Unless there are some compelling use cases, a simple and clean patch, and a clear one sentence explanation for users, I recommend this feature request be closed.

    Michael, do you still want this?

    @mwhudson
    Copy link
    Author

    Well, I can think of some counters to that -- surely it's _more_ confusing if slots only works some of the time? -- but realistically I'm not going to work on this any further.

    @rhettinger
    Copy link
    Contributor

    Declaring YAGNI and closing.
    Thanks Michael.

    @ronaldoussoren
    Copy link
    Contributor

    I do have a usecase for this: subclasses of int.

    Having slots would be nice for a reasonably efficient implementation of named constants (as recently discussed on python-ideas), and I'm already using a subclass of int of PyObjC to attach a single other value to a Python integer. In both cases the overhead of the __dict__ is pretty large.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 9, 2022
    @serhiy-storchaka
    Copy link
    Member

    I have a use case for this for namedtuple subclasses, in particular to add fields to urllib.parse classes (#67041).

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    5 participants