• How does a method of a subclass become a method of the base class?

    From Jen Kris@21:1/5 to All on Sun Mar 26 19:43:44 2023
    The base class:


    class Constraint(object):

    def __init__(self, strength):
            super(Constraint, self).__init__()
            self.strength = strength

    def satisfy(self, mark):
            global planner
            self.choose_method(mark)

    The subclass:

    class UrnaryConstraint(Constraint):

    def __init__(self, v, strength):
            super(UrnaryConstraint, self).__init__(strength)
            self.my_output = v
            self.satisfied = False
            self.add_constraint()

        def choose_method(self, mark):
            if self.my_output.mark != mark and \
               Strength.stronger(self.strength, self.my_output.walk_strength):
    self.satisfied = True
            else:
                self.satisfied = False

    The base class Constraint doesn’t have a "choose_method" class method, but it’s called as self.choose_method(mark) on the final line of Constraint shown above. 

    My question is:  what makes "choose_method" a method of the base class, called as self.choose_method instead of UrnaryConstraint.choose_method?  Is it super(UrnaryConstraint, self).__init__(strength) or just the fact that Constraint is its base class? 

    Also, this program also has a class BinaryConstraint that is also a subclass of Constraint and it also has a choose_method class method that is similar but not identical:

    def choose_method(self, mark):
        if self.v1.mark == mark:
                if self.v2.mark != mark and Strength.stronger(self.strength, self.v2.walk_strength):
                    self.direction = Direction.FORWARD             else:
                    self.direction = Direction.BACKWARD

    When called from Constraint, it uses the one at UrnaryConstraint.  How does it know which one to use? 

    Thanks,

    Jen

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Stefan Ram@21:1/5 to Jen Kris on Sun Mar 26 18:06:59 2023
    Jen Kris <jenkris@tutanota.com> writes:
    My question is: what makes "choose_method" a method of the base class=
    , called as self.choose_method instead of UrnaryConstraint.choose_method?

    You can see that in the following code "b()" is called on the object
    "self" in the base class "A", even though there is no "def b" in the
    base class A:

    class A:
    def a( self ):
    return self.b()

    class B( A ):
    def b( self ):
    return "I am a string in B.b."

    print( B().a() )

    print( A().a() )

    . Please look at the following transcript of the execution of this
    code:

    I am a string in B.b.
    AttributeError: 'A' object has no attribute 'b'

    . Now, your question should be:

    |What makes "b" be a methode of "B()", but not of "A()"?

    . And maybe now you can answer it yourself!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Jen Kris via Python-list on Sun Mar 26 20:48:25 2023
    On 2023-03-26 19:43:44 +0200, Jen Kris via Python-list wrote:
    The base class:


    class Constraint(object):
    [...]
    def satisfy(self, mark):
            global planner
            self.choose_method(mark)

    The subclass:

    class UrnaryConstraint(Constraint):
    [...]
        def choose_method(self, mark):
            if self.my_output.mark != mark and \
               Strength.stronger(self.strength, self.my_output.walk_strength):
    self.satisfied = True
            else:
                self.satisfied = False

    The base class Constraint doesn’t have a "choose_method" class method,
    but it’s called as self.choose_method(mark) on the final line of
    Constraint shown above. 

    My question is:  what makes "choose_method" a method of the base
    class,

    Nothing. choose_method isn't a method of the base class.

    called as self.choose_method instead of
    UrnaryConstraint.choose_method?  Is it super(UrnaryConstraint, self).__init__(strength) or just the fact that Constraint is its base class? 

    This works only if satisfy() is called on a subclass of Constraint which actually implements this method.

    If you do something like

    x = UrnaryConstraint()
    x.satisfy(whatever)

    Then x is a member of class UrnaryConstraint and will have a
    choose_method() method which can be called.


    Also, this program also has a class BinaryConstraint that is also a
    subclass of Constraint and it also has a choose_method class method
    that is similar but not identical:
    ...
    When called from Constraint, it uses the one at UrnaryConstraint.  How
    does it know which one to use? 

    By inspecting self. If you call x.satisfy() on an object of class UrnaryConstraint, then self.choose_method will be the choose_method from UrnaryConstraint. If you call it on an object of class BinaryConstraint,
    then self.choose_method will be the choose_method from BinaryConstraint.

    hp

    PS: Pretty sure there's one "r" too many in UrnaryConstraint.

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmQgk3QACgkQ8g5IURL+ KF025g/9G/w+vN5TrbIXM0aMEIffDNGB6UczXrYwlPnYHKWrPt1N9sd0nFZzPno1 CLkPOVZYQe8hs3w08siAbHyif74rIPlQwhEVCBh1pXG/Ml2cOUrgHtbN4Rs9BMba hg1h9KtSrvHUCUrLT5/UHbkLqRkO8pQyKiH0pTC+pZNIY2y4vDrwwh++pN2sJD43 7GJBy0pgLTo/wZ23NVme/NShaIsFwtayRJ5SetO4M0dwenqZeQ5tmjtcsL8nIxEd j0w7uycZLO1V7gSULyIr3ela+61azIsubWEoKifNvEO+frHjhHWE3/jKriu++jln B+841aqW4j4QLt116USrNjsOcbtPawPbmUd9YG+vNkzxSzBpXMpuY/oGzAoFXtGM dK23QNp/l5TuToxfcvivESFQsx1LNcY0tpqR6afM11y0nIsrkAEEsIo3CdtjRXaJ BzeLLAdMTlCJWQNacl+9OP3qkpX3DXie5EGT/E5+D7Cw7Pezb72kCk1UgPfTavCf Tb6BjBk2QSktk5jR+UNFFBCSxtZq1iDE4KHtDVcvud+y5ANthhAWbNj/jG1+0uDL c1cL7Qiiz1v1fLx5n5nxymrvRQZpbW54CyVihfqruAf4qdd7tQk5qC5neghlTSWB s8vKalSoi1vQEx4usGHZiWYl4cPDSulc4Kdt3lH
  • From aapost@21:1/5 to Jen Kris on Sun Mar 26 14:42:14 2023
    On 3/26/23 13:43, Jen Kris wrote:

    My question is:  what makes "choose_method" a method of the base class, called as self.choose_method instead of UrnaryConstraint.choose_method?  Is it super(UrnaryConstraint, self).__init__(strength) or just the fact that Constraint is its base class?



    When referring to "self" you are referring to an "instance" of the class
    or classes, think in terms of objects (the instance, usually self) vs a blueprint (the class, usually cls).

    saying self.choose_method(mark) checks the "instance" of self to see if
    it has something called choose_method at run time (instances being
    created at run time). If you have an instance of just Constraint, and
    never had a choose_method defined for it, you will get an error because
    it can't find it (which in this case is presumed as designed). If the "instance" is of a subclass of Constraint that does have a
    choose_method, that also inherits the stuff from Constraint, it will successfully call it against the "instance" that has been constructed
    with attributes of both classes.

    if the instance of a subclass has a definition for something that is in
    the base class, for instance IF UrnaryConstraint had it's own def
    satisfy() method, the instance would call the subclass version. In the
    case given, it does not, so it looks to the parent to see if it has
    inherited satisfy() from higher up.

    Hopefully that helps a little bit.. just have to get a feel for OO
    instantiated object vs class..

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jen Kris@21:1/5 to All on Sun Mar 26 21:24:01 2023
    Thanks to Richard Damon and Peter Holzer for your replies.  I'm working through the call chain to understand better so I can post a followup question if needed. 

    Thanks again.

    Jen


    Mar 26, 2023, 19:21 by Richard@Damon-Family.org:

    On 3/26/23 1:43 PM, Jen Kris via Python-list wrote:

    The base class:


    class Constraint(object):

    def __init__(self, strength):
            super(Constraint, self).__init__()
            self.strength = strength

    def satisfy(self, mark):
            global planner
            self.choose_method(mark)

    The subclass:

    class UrnaryConstraint(Constraint):

    def __init__(self, v, strength):
            super(UrnaryConstraint, self).__init__(strength)
            self.my_output = v
            self.satisfied = False
            self.add_constraint()

        def choose_method(self, mark):
            if self.my_output.mark != mark and \
               Strength.stronger(self.strength, self.my_output.walk_strength):
    self.satisfied = True
            else:
                self.satisfied = False

    The base class Constraint doesn’t have a "choose_method" class method, but it’s called as self.choose_method(mark) on the final line of Constraint shown above.

    My question is:  what makes "choose_method" a method of the base class, called as self.choose_method instead of UrnaryConstraint.choose_method?  Is it super(UrnaryConstraint, self).__init__(strength) or just the fact that Constraint is its base
    class?

    Also, this program also has a class BinaryConstraint that is also a subclass of Constraint and it also has a choose_method class method that is similar but not identical:

    def choose_method(self, mark):
        if self.v1.mark == mark:
                if self.v2.mark != mark and Strength.stronger(self.strength, self.v2.walk_strength):
                    self.direction = Direction.FORWARD
                else:
                    self.direction = Direction.BACKWARD

    When called from Constraint, it uses the one at UrnaryConstraint.  How does it know which one to use?

    Thanks,

    Jen


    Perhaps the key point to remember is that when looking up the methods on an object, those methods are part of the object as a whole, not particually "attached" to a given class. When creating the subclass typed object, first the most base class part is
    built, and all the methods of that class are put into the object, then the next level, and so on, and if a duplicate method is found, it just overwrites the connection. Then when the object is used, we see if there is a method by that name to use, so
    methods in the base can find methods in subclasses to use.

    Perhaps a more modern approach would be to use the concept of an "abstract base" which allows the base to indicate that a derived class needs to define certain abstract methods, (If you need that sort of support, not defining a method might just mean
    the subclass doesn't support some optional behavior defined by the base)

    --
    Richard Damon

    --
    https://mail.python.org/mailman/listinfo/python-list


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Richard Damon@21:1/5 to Jen Kris via Python-list on Sun Mar 26 15:19:47 2023
    On 3/26/23 1:43 PM, Jen Kris via Python-list wrote:
    The base class:


    class Constraint(object):

    def __init__(self, strength):
            super(Constraint, self).__init__()
            self.strength = strength

    def satisfy(self, mark):
            global planner
            self.choose_method(mark)

    The subclass:

    class UrnaryConstraint(Constraint):

    def __init__(self, v, strength):
            super(UrnaryConstraint, self).__init__(strength)
            self.my_output = v
            self.satisfied = False
            self.add_constraint()

        def choose_method(self, mark):
            if self.my_output.mark != mark and \
               Strength.stronger(self.strength, self.my_output.walk_strength):
    self.satisfied = True
            else:
                self.satisfied = False

    The base class Constraint doesn’t have a "choose_method" class method, but it’s called as self.choose_method(mark) on the final line of Constraint shown above.

    My question is:  what makes "choose_method" a method of the base class, called as self.choose_method instead of UrnaryConstraint.choose_method?  Is it super(UrnaryConstraint, self).__init__(strength) or just the fact that Constraint is its base class?

    Also, this program also has a class BinaryConstraint that is also a subclass of Constraint and it also has a choose_method class method that is similar but not identical:

    def choose_method(self, mark):
        if self.v1.mark == mark:
                if self.v2.mark != mark and Strength.stronger(self.strength, self.v2.walk_strength):
                    self.direction = Direction.FORWARD
                else:
                    self.direction = Direction.BACKWARD

    When called from Constraint, it uses the one at UrnaryConstraint.  How does it know which one to use?

    Thanks,

    Jen

    Perhaps the key point to remember is that when looking up the methods on
    an object, those methods are part of the object as a whole, not
    particually "attached" to a given class. When creating the subclass
    typed object, first the most base class part is built, and all the
    methods of that class are put into the object, then the next level, and
    so on, and if a duplicate method is found, it just overwrites the
    connection. Then when the object is used, we see if there is a method by
    that name to use, so methods in the base can find methods in subclasses
    to use.

    Perhaps a more modern approach would be to use the concept of an
    "abstract base" which allows the base to indicate that a derived class
    needs to define certain abstract methods, (If you need that sort of
    support, not defining a method might just mean the subclass doesn't
    support some optional behavior defined by the base)

    --
    Richard Damon

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jen Kris@21:1/5 to All on Sun Mar 26 22:36:18 2023
    Based on your explanations, I went through the call chain and now I understand better how it works, but I have a follow-up question at the end.   

    This code comes from the DeltaBlue benchmark in the Python benchmark suite. 

    1
    The call chain starts in a non-class program with the following call:

    EqualityConstraint(prev, v, Strength.REQUIRED)

    2
    EqualityConstraint is a subclass of BinaryConstraint, so first it calls the __init__ method of BinaryConstraint:

         def __init__(self, v1, v2, strength):
            super(BinaryConstraint, self).__init__(strength)
            self.v1 = v1
            self.v2 = v2
            self.direction = Direction.NONE
            self.add_constraint()

    3
    At the final line shown above it calls add_constraint in the Constraint class, the base class of BinaryConstraint:

          def add_constraint(self):
            global planner
            self.add_to_graph()
            planner.incremental_add(self)

    4
    At planner.incremental_add it calls incremental_add in the Planner class because planner is a global instance of the Planner class: 

        def incremental_add(self, constraint):
            mark = self.new_mark()
            overridden = constraint.satisfy(mark)

    At the final line it calls "satisfy" in the Constraint class, and that line calls choose_method in the BinaryConstraint class.  Just as Peter Holzer said, it requires a call to "satisfy." 

    My only remaining question is, did it select the choose_method in the BinaryConstraint class instead of the choose_method in the UrnaryConstraint class because of "super(BinaryConstraint, self).__init__(strength)" in step 2 above? 

    Thanks for helping me clarify that. 

    Jen



    Mar 26, 2023, 18:55 by hjp-python@hjp.at:

    On 2023-03-26 19:43:44 +0200, Jen Kris via Python-list wrote:

    The base class:


    class Constraint(object):

    [...]

    def satisfy(self, mark):
            global planner
            self.choose_method(mark)

    The subclass:

    class UrnaryConstraint(Constraint):

    [...]

        def choose_method(self, mark):
            if self.my_output.mark != mark and \
               Strength.stronger(self.strength, self.my_output.walk_strength):
    self.satisfied = True
            else:
                self.satisfied = False

    The base class Constraint doesn’t have a "choose_method" class method,
    but it’s called as self.choose_method(mark) on the final line of
    Constraint shown above. 

    My question is:  what makes "choose_method" a method of the base
    class,


    Nothing. choose_method isn't a method of the base class.

    called as self.choose_method instead of
    UrnaryConstraint.choose_method?  Is it super(UrnaryConstraint,
    self).__init__(strength) or just the fact that Constraint is its base
    class? 


    This works only if satisfy() is called on a subclass of Constraint which actually implements this method.

    If you do something like

    x = UrnaryConstraint()
    x.satisfy(whatever)

    Then x is a member of class UrnaryConstraint and will have a
    choose_method() method which can be called.


    Also, this program also has a class BinaryConstraint that is also a
    subclass of Constraint and it also has a choose_method class method
    that is similar but not identical:

    ...

    When called from Constraint, it uses the one at UrnaryConstraint.  How
    does it know which one to use? 


    By inspecting self. If you call x.satisfy() on an object of class UrnaryConstraint, then self.choose_method will be the choose_method from UrnaryConstraint. If you call it on an object of class BinaryConstraint,
    then self.choose_method will be the choose_method from BinaryConstraint.

    hp

    PS: Pretty sure there's one "r" too many in UrnaryConstraint.

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cameron Simpson@21:1/5 to Jen Kris on Mon Mar 27 09:44:00 2023
    On 26Mar2023 22:36, Jen Kris <jenkris@tutanota.com> wrote:
    At the final line it calls "satisfy" in the Constraint class, and that
    line calls choose_method in the BinaryConstraint class.  Just as Peter >Holzer said, it requires a call to "satisfy." 

    My only remaining question is, did it select the choose_method in the >BinaryConstraint class instead of the choose_method in the
    UrnaryConstraint class because of "super(BinaryConstraint, >self).__init__(strength)" in step 2 above? 

    Basicly, no.

    You've omitting the "class" lines of the class definitions, and they
    define the class inheritance, _not "__init__". The "__init__" method
    just initialises the state of the new objects (which has already been
    created). The:

    super(BinaryConstraint,_ self).__init__(strength)

    line simply calls the appropriate superclass "__init__" with the
    "strength" parameter to do that aspect of the initialisation.

    You haven't cited the line which calls the "choose_method" method, but
    I'm imagining it calls "choose_method" like this:

    self.choose_method(...)

    That searchs for the "choose_method" method based on the method
    resolution order of the object "self". So if "self" was an instance of "EqualityConstraint", and I'm guessing abut its class definition,
    assuming this:

    class EqualityConstraint(BinaryConstraint):

    Then a call to "self.choose_method" would look for a "choose_method"
    method first in the EqualityConstraint class and then via the
    BinaryConstraint class. I'm also assuming UrnaryConstraint is not in
    that class ancestry i.e. not an ancestor of BinaryConstraint, for
    example.

    The first method found is used.

    In practice, when you define a class like:

    class EqualityConstraint(BinaryConstraint):

    the complete class ancestry (the addition classes from which
    BinaryConstraint inherits) gets flatterned into a "method resultion
    order" list of classes to inspect in order, and that is stored as the ".__mro__" field on the new class (EqualityConstraint). You can look at
    it directly as "EqualityConstraint.__mro__".

    So looking up:

    self.choose_method()

    looks for a "choose_method" method on the classes in
    "type(self).__mro__".

    Cheers,
    Cameron Simpson <cs@cskk.id.au>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jen Kris@21:1/5 to All on Mon Mar 27 01:53:49 2023
    Cameron,

    Thanks for your reply.  You are correct about the class definition lines – e.g. class EqualityConstraint(BinaryConstraint).  I didn’t post all of the code because this program is over 600 lines long.  It's DeltaBlue in the Python benchmark suite. 


    I’ve done some more work since this morning, and now I see what’s happening.  But it gave rise to another question, which I’ll ask at the end. 

    The call chain starts at

        EqualityConstraint(prev, v, Strength.REQUIRED) 

    The class EqualityConstraint is a subclass of BinaryConstraint.  The entire class code is:

        class EqualityConstraint(BinaryConstraint):
            def execute(self):
                self.output().value = self.input().value

    Because EqualityConstraint is a subclass of BinaryConstraint, the init method of BinaryConstraint is called first.  During that initialization (I showed the call chain in my previous message), it calls choose_method.  When I inspect the code at "self.
    choose_method(mark):" in PyCharm, it shows:

        <bound method BinaryConstraint.choose_method of <Trans_01_DeltaBlue.EqualityConstraint object at 0x7f7ac09c6ee0>>

    As EqualityConstraint is a subclass of BinaryConstraint it has bound the choose method from BinaryConstraint, apparently during the BinaryConstraint init process, and that’s the one it uses.  So that answers my original question. 

    But that brings up a new question.  I can create a class instance with x = BinaryConstraint(), but what happens when I have a line like "EqualityConstraint(prev, v, Strength.REQUIRED)"? Is it because the only method of EqualityConstraint is execute(self)
    ?  Is execute a special function like a class __init__?  I’ve done research on that but I haven’t found an answer. 

    I’m asking all these question because I have worked in a procedural style for many years, with class work limited to only simple classes, but now I’m studying classes in more depth. The three answers I have received today, including yours, have
    helped a lot. 

    Thanks very much. 

    Jen


    Mar 26, 2023, 22:45 by cs@cskk.id.au:

    On 26Mar2023 22:36, Jen Kris <jenkris@tutanota.com> wrote:

    At the final line it calls "satisfy" in the Constraint class, and that line calls choose_method in the BinaryConstraint class.  Just as Peter Holzer said, it requires a call to "satisfy." 

    My only remaining question is, did it select the choose_method in the BinaryConstraint class instead of the choose_method in the UrnaryConstraint class because of "super(BinaryConstraint, self).__init__(strength)" in step 2 above? 


    Basicly, no.

    You've omitting the "class" lines of the class definitions, and they define the class inheritance, _not "__init__". The "__init__" method just initialises the state of the new objects (which has already been created). The:

    super(BinaryConstraint,_ self).__init__(strength)

    line simply calls the appropriate superclass "__init__" with the "strength" parameter to do that aspect of the initialisation.

    You haven't cited the line which calls the "choose_method" method, but I'm imagining it calls "choose_method" like this:

    self.choose_method(...)

    That searchs for the "choose_method" method based on the method resolution order of the object "self". So if "self" was an instance of "EqualityConstraint", and I'm guessing abut its class definition, assuming this:

    class EqualityConstraint(BinaryConstraint):

    Then a call to "self.choose_method" would look for a "choose_method" method first in the EqualityConstraint class and then via the BinaryConstraint class. I'm also assuming UrnaryConstraint is not in that class ancestry i.e. not an ancestor of
    BinaryConstraint, for example.

    The first method found is used.

    In practice, when you define a class like:

    class EqualityConstraint(BinaryConstraint):

    the complete class ancestry (the addition classes from which BinaryConstraint inherits) gets flatterned into a "method resultion order" list of classes to inspect in order, and that is stored as the ".__mro__" field on the new class (EqualityConstraint)
    . You can look at it directly as "EqualityConstraint.__mro__".

    So looking up:

    self.choose_method()

    looks for a "choose_method" method on the classes in "type(self).__mro__".

    Cheers,
    Cameron Simpson <cs@cskk.id.au>
    --
    https://mail.python.org/mailman/listinfo/python-list


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cameron Simpson@21:1/5 to Jen Kris on Mon Mar 27 12:03:29 2023
    On 27Mar2023 01:53, Jen Kris <jenkris@tutanota.com> wrote:
    Thanks for your reply.  You are correct about the class definition
    lines – e.g. class EqualityConstraint(BinaryConstraint).  I didn’t post >all of the code because this program is over 600 lines long.  It's
    DeltaBlue in the Python benchmark suite. 

    Doubtless. But the "class ...:" line is the critical thing.

    I’ve done some more work since this morning, and now I see what’s happening.  But it gave rise to another question, which I’ll ask at the end. 

    The call chain starts at

        EqualityConstraint(prev, v, Strength.REQUIRED) 

    The class EqualityConstraint is a subclass of BinaryConstraint.  The entire class code is:

        class EqualityConstraint(BinaryConstraint):
            def execute(self):
                self.output().value = self.input().value

    Ok, so it is effectively a BinaryConstraint with a single customised
    execute() method.

    Because EqualityConstraint is a subclass of BinaryConstraint, the init method of BinaryConstraint is called first.

    That is courtesy of the MRO: EqualityConstraint has no __init__, so the
    one found in BinaryConstraint is found and used.

    During that initialization (I showed the call chain in my previous
    message), it calls choose_method.  When I inspect the code at >"self.choose_method(mark):" in PyCharm, it shows:

        <bound method BinaryConstraint.choose_method of <Trans_01_DeltaBlue.EqualityConstraint object at 0x7f7ac09c6ee0>>

    This says that it found found the choose_method method in the
    BinaryConstraint class definition, but that it is _bound_ to the EqualityConstraint instance you're using (self).

    As EqualityConstraint is a subclass of BinaryConstraint it has bound the choose method from BinaryConstraint, apparently during the BinaryConstraint init process, and that’s the one it uses.  So that answers my original question. 

    Incorrectly, I think.

    __init__ does _nothing_ about other methods, if you mean "__init__" in
    the sentence above.

    The class definition results in an EqualityConstraint.__mro__ list of
    classes, which is where _every_ method is looked for _at call time_.

    But that brings up a new question.  I can create a class instance with
    x = BinaryConstraint(),

    That makes an instance of EqualityConstraint.

    but what happens when I have a line like "EqualityConstraint(prev, v, >Strength.REQUIRED)"?

    That makes an instance of EqualityConstraint.

    Is it because the only method of EqualityConstraint is execute(self)?

    I don't know what you're asking here.

    Is execute a special function like a class __init__?

    No. It's just a method.

    In a sense, __init__ isn't very special either. It is just _called_
    during new instance setup as the final step. By that time, self is a
    fully set up instance of... whatever and the __init__ function is just
    being called to do whatever initial attribute setup every instance of
    that class needs.

    Python doesn't magicly call _all_ the __init__ methods of all the
    superclasses; it calls the first found. So for an EqualityConstraint it
    finds the one from BinaryConstraint because EqualityConstraint does not
    provide an overriding one of its own.

    If EqualityConstraint _did_ provide one, it might typically be
    structured as:

    class EqualityConstraint(BinaryConstraint):
    def __init__(self, prev, v, strength, something_extra):
    super().__init__(prev, v, strength)
    self.extra = something_extra

    So:
    - Python only calls _one_ __init__ method
    - in the example above, it finds one in EqualityConstraint and uses it
    - because Python calls _only_ that, in order to _also_ do the normal
    setup a BinaryConstraint needs, we pass the parameters used by
    BinaryConstraint to the new __init__ up the chain by calling
    super().__init__(BinaryConstraint-parameters-here)
    - we do our own special something with the something_extra

    That super().__init__() call is the _only_ thing which arranges that
    superclass inits get to run. This givens you full control to sompletely
    replace some superclass' init with a custom one. By calling
    super().__init__() we're saying we not replacing that stuff, we're
    running the old stuff and just doing something additional for our
    subclass.

    Cheers,
    Cameron Simpson <cs@cskk.id.au>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Cameron Simpson@21:1/5 to Cameron Simpson on Mon Mar 27 13:10:38 2023
    On 27Mar2023 12:03, Cameron Simpson <cs@cskk.id.au> wrote:
    On 27Mar2023 01:53, Jen Kris <jenkris@tutanota.com> wrote:
    But that brings up a new question.  I can create a class instance with
    x = BinaryConstraint(),

    That makes an instance of EqualityConstraint.

    Copy/paste mistake on my part. This makes an instance of
    BinaryConstraint.

    Apologies,
    Cameron Simpson <cs@cskk.id.au>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Jen Kris via Python-list on Mon Mar 27 14:52:15 2023
    On 2023-03-27 01:53:49 +0200, Jen Kris via Python-list wrote:
    But that brings up a new question.  I can create a class instance with
    x = BinaryConstraint(), but what happens when I have a line like "EqualityConstraint(prev, v, Strength.REQUIRED)"?

    If that is the whole statement it will create a new object of class EqualityConstraint and immediately discard it. That may have some useful
    side effect (for example the object may add itself to a list of
    constraints) but this is not apparent from this line.

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmQhkXgACgkQ8g5IURL+ KF0KiA/8CUphAaITbUw0B6qftv6yJl00OqTZF7goLkbkbsQSHyKmVyiztfLube7R rSG1/RHeAxMW1nHpGDJE1aZAVMomo/ezJ2Ybygj6Q5GS0K0RwIllJrxq8ffy81Jd gvc+QcNH5Uh2Oc3PSzH8hF7N1orN2UuWv0CSjJZJ2B9HBUZY02tN/Q0gW19golhO vm01Lw58eaIrNo+OCcDOYRirW3T9kKNBPoUL6odCfLnvW8b30GlcM6frS5Lo9ltb Ro/vnm4axG32pQOlJdSLv1I+kNt+5GhVQO+lTbQlWlxL5d1fsubMjXckFtae24OG TvzQSBz9SpIDtKi3X5qDaVW8BVGPOlXZq00GJw0FDH5MdsYtrV70GAejZ4po0+PF MOSxcrPVNwZqb7B52F3+fa+2WrFxfJKNfdwG8pd8e1c15PVGVQHfV4toeV53ZKB9 9RlZ6Ky+gceVI15xxvlpTuKvFzIWet9rudShbDdoNmP4xeeztgiR/4IINvXgFE4m /MzSGeaH5uKBG9xUsWac/VWQGIgiPiL+bJkjex3mSetHSvLtOOdLajt5Hju8p8h4 eJC5AJXXnD4Fi2Acf+inRQdbe85sdYvf5TYj9lbGyw3JFPz1sh0bvDLEezAi56IP 3yoESb5FVX1cHpCIatp9MObzYamXpXuvLrzwsZo
  • From Mats Wichmann@21:1/5 to Jen Kris via Python-list on Mon Mar 27 08:08:44 2023
    On 3/26/23 17:53, Jen Kris via Python-list wrote:

    I’m asking all these question because I have worked in a procedural style for many years, with class work limited to only simple classes, but now I’m studying classes in more depth. The three answers I have received today, including yours, have
    helped a lot.

    Classes in Python don't work quite like they do in many other languages.

    You may find a lightbulb if you listen to Raymond Hettinger talk about them:

    https://dailytechvideo.com/raymond-hettinger-pythons-class-development-toolkit/

    I'd also advise that benchmarks often do very strange things to set up
    the scenario they're trying to test, a benchmark sure wouldn't be my
    first place to look in learning a new piece of Python - I don't know if
    it was the first place, but thought this was worth a mention.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jen Kris@21:1/5 to All on Mon Mar 27 16:47:26 2023
    Thanks to everyone who answered this question.  Your answers have helped a lot. 

    Jen


    Mar 27, 2023, 14:12 by mats@wichmann.us:

    On 3/26/23 17:53, Jen Kris via Python-list wrote:

    I’m asking all these question because I have worked in a procedural style for many years, with class work limited to only simple classes, but now I’m studying classes in more depth. The three answers I have received today, including yours, have
    helped a lot.


    Classes in Python don't work quite like they do in many other languages.

    You may find a lightbulb if you listen to Raymond Hettinger talk about them:

    https://dailytechvideo.com/raymond-hettinger-pythons-class-development-toolkit/

    I'd also advise that benchmarks often do very strange things to set up the scenario they're trying to test, a benchmark sure wouldn't be my first place to look in learning a new piece of Python - I don't know if it was the first place, but thought this
    was worth a mention.


    --
    https://mail.python.org/mailman/listinfo/python-list


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)