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

Improper object initialization #36360

Closed
jacobs99 mannequin opened this issue Mar 31, 2002 · 6 comments
Closed

Improper object initialization #36360

jacobs99 mannequin opened this issue Mar 31, 2002 · 6 comments
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs)

Comments

@jacobs99
Copy link
Mannequin

jacobs99 mannequin commented Mar 31, 2002

BPO 537450
Nosy @gvanrossum, @tim-one
Files
  • diff-init: Patch to typeobject.c
  • 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/gvanrossum'
    closed_at = <Date 2002-10-07.18:09:17.000>
    created_at = <Date 2002-03-31.17:23:27.000>
    labels = ['interpreter-core']
    title = 'Improper object initialization'
    updated_at = <Date 2002-10-07.18:09:17.000>
    user = 'https://bugs.python.org/jacobs99'

    bugs.python.org fields:

    activity = <Date 2002-10-07.18:09:17.000>
    actor = 'gvanrossum'
    assignee = 'gvanrossum'
    closed = True
    closed_date = None
    closer = None
    components = ['Interpreter Core']
    creation = <Date 2002-03-31.17:23:27.000>
    creator = 'jacobs99'
    dependencies = []
    files = ['409']
    hgrepos = []
    issue_num = 537450
    keywords = []
    message_count = 6.0
    messages = ['10091', '10092', '10093', '10094', '10095', '10096']
    nosy_count = 3.0
    nosy_names = ['gvanrossum', 'tim.peters', 'jacobs99']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = None
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue537450'
    versions = ['Python 2.3']

    @jacobs99
    Copy link
    Mannequin Author

    jacobs99 mannequin commented Mar 31, 2002

    The descr tutorial specifies this rule:

    __new__ must return an object. There's nothing that
    requires that it return a new object that is an
    instance of its class argument, although that is the
    convention. If you return an existing object, the
    constructor call will still call its __init__
    method. If you return an object of a different
    class, its __init__ method will be called.

    I believe that this rule adds an unnecessary wart to
    the language, since it is not appropriate to call
    __init__, especially with the same arguments as
    __new__ on an 'unexpected' class returned by __new__.
    It is simple enough to check that the resulting class
    is an instance of the expected class and to only then
    call __init__. Otherwise, it should be assumed that
    __new__ is returning a fully constructed instance of
    another class. In the rare and obscure case that one
    does wish to call __init__ on an object of a different
    class, then it may be done manually from within
    __new__.

    So basically, my argument is for explicit versus
    implicit semantics. If __new__(cls) returns an
    instance where type(instance) is not cls, then
    __init__ should not be called implicitly. The
    burden should be on the programmer to explicitly
    ensure that the object is properly constructed.

    Here is an example where the current rule results
    in confusing and apparently random behavior
    (if one doesn't have initimate knowledge of the
    Python implementation, that is):

    class Foo(object):
      def __new__(cls, x):
        if x == 0:
          return [1,2,3]
        if x == 1:
          return 1
        if x == 2:
          return (1,2,3)
        if x == 3:
          return '1'
        if x == 4:
          return {1:1,2:2,3:3}
        else:
          return super(cls, Foo).__new__(cls)
    
    for i in range(6):
      try:
        print 'Foo(%d) =' % i,Foo(i)
      except:
        print 'Foo(%d) failed' % i

    Which under Python 2.2 results in the following output:
    Foo(0) failed
    Foo(1) = 1
    Foo(2) = (1, 2, 3)
    Foo(3) = 1
    Foo(4) failed
    Foo(5) = <main.Foo object at 0x8147f54>

    Under the proposed new rule, the output would be
    much more sensible:
    Foo(0) = [1,2,3]
    Foo(1) = 1
    Foo(2) = (1, 2, 3)
    Foo(3) = 1
    Foo(4) = {1:1,2:2,3:3}
    Foo(5) = <main.Foo object at 0x8147f54>

    If there is agreement on this issue, I will submit
    a very simple patch to address this.

    @jacobs99 jacobs99 mannequin closed this as completed Mar 31, 2002
    @jacobs99 jacobs99 mannequin assigned gvanrossum Mar 31, 2002
    @jacobs99 jacobs99 mannequin added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Mar 31, 2002
    @jacobs99 jacobs99 mannequin closed this as completed Mar 31, 2002
    @jacobs99 jacobs99 mannequin assigned gvanrossum Mar 31, 2002
    @jacobs99 jacobs99 mannequin added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Mar 31, 2002
    @jacobs99
    Copy link
    Mannequin Author

    jacobs99 mannequin commented Apr 1, 2002

    Logged In: YES
    user_id=459565

    Patch attached. Passes Python descr tests and our
    extremely comprehensive in-house test suite that
    tortures new-style classes in fairly gruesome ways.

    Note: The ugly test to avoid calling tp_init on
    type(x) calls was intentionally left in the code,
    to handle the case of calling type(type).
    It is very likely that the test is now unnecessary
    and can be removed since calling tp_init on type
    objects should be safe, because they do not implement
    their own tp_init. However, for the sake of
    simplicity, I'm going to leave this additional
    cleanup to Guido, or others.

    @tim-one
    Copy link
    Member

    tim-one commented Apr 1, 2002

    Logged In: YES
    user_id=31435

    Thanks, Kevin! Assigned to Guido, under the theory that it
    lands on his plate sooner or later, and better sooner.

    @gvanrossum
    Copy link
    Member

    Logged In: YES
    user_id=6380

    I think Kevin's suggestion is about right, but I'd like to
    add one twist: C.__new__ could return an instance of a
    subclass of C, and in that case I think that the __init__
    should still be called. I'll see about a proper fix.

    It's a clear semantic change, so I don't want to change this
    in 2.2.x.

    @gvanrossum
    Copy link
    Member

    Logged In: YES
    user_id=6380

    Fixed in CVS, using PyType_IsSubtype(obj->type, type).

    Note that the exception for type(x) is still needed (the
    test suite could have told you that).

    @gvanrossum
    Copy link
    Member

    Logged In: YES
    user_id=6380

    Given Kevin's plea, I've backported this to Python 2.2.2b1,
    with the caveat that I may undo it if problems arise during
    the (short!) beta release time.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 9, 2022
    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)
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants