How do you make issubclass work

Discussion in 'Python' started by Nathan Bullock, Sep 11, 2004.

  1. Okay I have two files:

    a.py:
    -----
    class cla_a(object): pass

    class cla_c(object): pass

    if __name__ == "__main__":
    mod = __import__("b")
    attr = getattr(mod, "cla_b")
    print issubclass(attr, cla_a)
    print issubclass(cla_c, cla_a)
    -----

    and b.py:
    -----
    from a import cla_a

    class cla_b(cla_a): pass
    -----

    now if I do 'python a.py'
    it gives me:
    False
    True

    Why is cla_b a subclass and not cla_c?

    I think that it has something to with the fact that cla_b is a
    subclass of a different instance of cla_a or something like that. But
    if that is the case how do I do this sort of thing in python?

    Nathan Bullock

    http://bullock.mooo.com
     
    Nathan Bullock, Sep 11, 2004
    #1
    1. Advertising

  2. Nathan Bullock

    Peter Otten Guest

    Nathan Bullock wrote:

    > Okay I have two files:
    >
    > a.py:
    > -----
    > class cla_a(object): pass
    >
    > class cla_c(object): pass
    >
    > if __name__ == "__main__":
    > mod = __import__("b")

    # why not
    import b as mod

    > attr = getattr(mod, "cla_b")


    # why not
    attr = mod.cla_b

    > print issubclass(attr, cla_a)
    > print issubclass(cla_c, cla_a)
    > -----
    >
    > and b.py:
    > -----
    > from a import cla_a
    >
    > class cla_b(cla_a): pass
    > -----
    >
    > now if I do 'python a.py'
    > it gives me:
    > False
    > True


    Should be:
    True
    False

    > Why is cla_b a subclass and not cla_c?


    Here you have it right again.

    That you have two different modules does not affect the class hierarchy.
    Y is a subclass of X if X can be found in the inheritance tree of Y, i. e.
    occurs directly in Y's bases

    >>> class X: pass

    ....
    >>> class Y(X): pass

    ....
    >>> issubclass(Y, X)

    True

    or indirectly in the bases' bases:

    >>> class X: pass

    ....
    >>> class Intermediate(X): pass

    ....
    >>> class Y(Intermediate): pass

    ....
    >>> issubclass(Y, X)

    True

    On the other hand it is not sufficient for a subclass relationship when two
    classes share a common ancestor:

    >>> class A: pass

    ....
    >>> class B(A): pass

    ....
    >>> class C(A): pass

    ....
    >>> issubclass(B, C), issubclass(C, B)

    (False, False)

    So you can think of subclasses as children and grandchildren, but not as
    cousins.

    [As modules are cached, subsequent imports of the same module yield the same
    module instance. Therefore the same classes (cla_a is cla_a == True) are
    seen by all parts of a program and it (normally) doesn't matter in what
    module a class is defined.]

    Peter
     
    Peter Otten, Sep 11, 2004
    #2
    1. Advertising

  3. I think my first post was a little unclear. I will try again.

    I have two files, the first is this:

    File b.py:
    -------------------
    from a import cla_a

    class cla_b(cla_a): pass
    -------------------


    File a.py
    -------------------
    class cla_a(object): pass

    class cla_c(cla_a): pass

    if __name__ == "__main__":
    import b as mod
    print issubclass(mod.cla_b, cla_a)
    print issubclass(mod.cla_b, mod.cla_a)
    print issubclass(cla_c, cla_a)
    print mod.cla_a is cla_a
    -------------------

    Results of 'python a.py'

    False
    True
    True
    False


    -----------------------------

    This is using python 2.3.3. Is this a bug? Why do we have two
    different cla_a's which are not the same? And do to this problem how
    in the world do I determine if a cla_b is a subclass of cla_a?
    Obviously they are, but issubclass doesn't realize it because the
    cla_a that I am testing with is not the same instance of cla_a as
    cla_b was derived from.

    >
    > [As modules are cached, subsequent imports of the same module yield the same
    > module instance. Therefore the same classes (cla_a is cla_a == True) are
    > seen by all parts of a program and it (normally) doesn't matter in what
    > module a class is defined.]
    >
    > Peter


    Now I take it from this answer from Peter, that if I did the test in a
    third file so that I was using an imported instance of cla_a that
    issubclass would then work properly.

    Nathan
     
    Nathan Bullock, Sep 11, 2004
    #3
  4. Nathan Bullock

    Andrew Dalke Guest

    Nathan Bullock wrote:
    > This is using python 2.3.3. Is this a bug? Why do we have two
    > different cla_a's which are not the same?


    Your file 'a.py' is two things. It's the code being used
    as the "__main__" module *and* it's used as the "a" module.

    Add this to your a.py:__main__ to see the difference.

    import sys
    main_module = sys.modules["__main__"]
    print "main is from", main_module.__file__
    a_module = sys.modules["a"]
    print "a is from", a_module.__file__
    print "Are the modules the same?", a_module == main_module
    print "Are the classes the same?", a_module.cla_a ==
    main_module.cla_a

    You'll see that the file a.py is used twice, and the
    class cla_a defined once as __main__.cla_a and the other
    as a.cla_a .

    To make what you want work, well, a good rule is to avoid
    circular imports. Another is that your main code should
    not be imported. But if you want so see your code to work
    as you expect it to work, you need to change b.py so that
    the "from a import cla_a" is instead
    "from __main__ import cla_a"


    > Now I take it from this answer from Peter, that if I did the test in a
    > third file so that I was using an imported instance of cla_a that
    > issubclass would then work properly.


    It should.

    Andrew
     
    Andrew Dalke, Sep 11, 2004
    #4
  5. Andrew Dalke <> wrote:
    ...
    > To make what you want work, well, a good rule is to avoid
    > circular imports. Another is that your main code should
    > not be imported. But if you want so see your code to work
    > as you expect it to work, you need to change b.py so that
    > the "from a import cla_a" is instead
    > "from __main__ import cla_a"


    I would suggest a different workaround if it's important that module
    a.py be runnable as main _and_ importable as a without getting two
    copies: start a.py with the incantation...

    import sys
    if __name__!='a': sys.modules[a]=sys.modules[__name__]


    After this, if any other module should 'import a', it WILL get the
    module from a.py, not a separate copy. This won't solve everything, by
    a long shot (circular imports _are_ trouble, period), but it will at
    least remove the single issue of the "two modules from the same a.py
    source file"...!


    Alex
     
    Alex Martelli, Sep 11, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Green

    when does issubclass fail?

    Chris Green, Apr 16, 2004, in forum: Python
    Replies:
    1
    Views:
    301
    =?ISO-8859-1?Q?Walter_D=F6rwald?=
    Apr 20, 2004
  2. Osmo Maatta
    Replies:
    3
    Views:
    479
    Osmo Maatta
    Aug 29, 2010
  3. kj

    issubclass(dict, Mapping)

    kj, Dec 22, 2010, in forum: Python
    Replies:
    10
    Views:
    536
  4. kj
    Replies:
    5
    Views:
    413
  5. Replies:
    1
    Views:
    153
    Steven D'Aprano
    May 31, 2012
Loading...

Share This Page