Get classes from "self.MyClass" to improve subclassability

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Get classes from "self.MyClass" to improve subclassability

guettli
Here is a snippet from the argparse module:

{{{
    def parse_known_args(self, args=None, namespace=None):
        ...
        # default Namespace built from parser defaults
        if namespace is None:
            namespace = Namespace() # < ======= my issue
}}}

I subclass from the class of the above snippet.

I would like to use a different Namespace class.

if the above could would use

    namespace = self.Namespace()

it would be very easy for me to inject a different Namespace class.

Yes, I have seen the "namespace" kwarg.

This is not the first time I would like the upstream code to make subclassing more fun.

Some months ago I asked myself how to call the "self.Namespace()" pattern:
 
http://stackoverflow.com/questions/27571848/name-of-design-pattern-get-class-from-class-level

The answer with the most upvotes states it is the Factory method pattern.

I prefer "self.Namespace()" to namespace kwargs.

What do you think?

Reply | Threaded
Open this post in threaded view
|

Get classes from "self.MyClass" to improve subclassability

Chris Angelico
On Fri, Jun 12, 2015 at 9:12 PM, Thomas G?ttler <hv at tbz-pariv.de> wrote:
> I prefer "self.Namespace()" to namespace kwargs.
>
> What do you think?

Given that the namespace argument already exists, and you're proposing
a change, you'll need a much stronger justification than mere
preference. What's the downside of providing your own instance, rather
than injecting a class?

ChrisA

Reply | Threaded
Open this post in threaded view
|

Get classes from "self.MyClass" to improve subclassability

Steven D'Aprano-11
In reply to this post by guettli
On Fri, 12 Jun 2015 04:12:52 -0700, Thomas G?ttler wrote:

> Here is a snippet from the argparse module:
>
> {{{
>     def parse_known_args(self, args=None, namespace=None):
>         ...
>         # default Namespace built from parser defaults if namespace is
>         None:
>             namespace = Namespace() # < ======= my issue
> }}}
>
> I subclass from the class of the above snippet.
>
> I would like to use a different Namespace class.
>
> if the above could would use
>
>     namespace = self.Namespace()
>
> it would be very easy for me to inject a different Namespace class.

Yes it would.

And here is how you do it, even when the parent class doesn't:

    class MySubclass(ParentClass):
        Namespace = Namespace
        def parse_known_args(self, args=None, namespace=None):
            if namespace is None:
                namespace = self.Namespace()
            # any other method overriding needed
            return super().parse_known_args(args, namespace)

In Python 2, you cannot use super(), you have to explicitly provide the
arguments:

            return super(MySubclass,self).parse_known_args(args,namespace)


--
Steve

Reply | Threaded
Open this post in threaded view
|

Get classes from "self.MyClass" to improve subclassability

guettli
Hi Steven,

I understand your solution. It is correct and works.

But the missing five characters "self." in the upstream code
produces a lot of more lines in the final result.

Regards,
  Thomas G?ttler


Am Freitag, 12. Juni 2015 14:24:06 UTC+2 schrieb Steven D'Aprano:

> On Fri, 12 Jun 2015 04:12:52 -0700, Thomas G?ttler wrote:
>
> > Here is a snippet from the argparse module:
> >
> > {{{
> >     def parse_known_args(self, args=None, namespace=None):
> >         ...
> >         # default Namespace built from parser defaults if namespace is
> >         None:
> >             namespace = Namespace() # < ======= my issue
> > }}}
> >
> > I subclass from the class of the above snippet.
> >
> > I would like to use a different Namespace class.
> >
> > if the above could would use
> >
> >     namespace = self.Namespace()
> >
> > it would be very easy for me to inject a different Namespace class.
>
> Yes it would.
>
> And here is how you do it, even when the parent class doesn't:
>
>     class MySubclass(ParentClass):
>         Namespace = Namespace
>         def parse_known_args(self, args=None, namespace=None):
>             if namespace is None:
>                 namespace = self.Namespace()
>             # any other method overriding needed
>             return super().parse_known_args(args, namespace)
>
> In Python 2, you cannot use super(), you have to explicitly provide the
> arguments:
>
>             return super(MySubclass,self).parse_known_args(args,namespace)
>
>
> --
> Steve


Reply | Threaded
Open this post in threaded view
|

Get classes from "self.MyClass" to improve subclassability

Terry Reedy
In reply to this post by guettli
On 6/12/2015 7:12 AM, Thomas G?ttler wrote:

> Here is a snippet from the argparse module:
>
> {{{
>      def parse_known_args(self, args=None, namespace=None):
>          ...
>          # default Namespace built from parser defaults
>          if namespace is None:
>              namespace = Namespace() # < ======= my issue
> }}}
>
> I subclass from the class of the above snippet.
>
> I would like to use a different Namespace class.
>
> if the above could would use
>
>      namespace = self.Namespace()
>
> it would be very easy for me to inject a different Namespace class.

The default arg (None) for the namespace parameter of the
parse_known_args is an attribute of the function, not of the class or
instance thereof.  Unless the default Namespace is used elsewhere, this
seems sensible.

In CPython, at least, and probably in pypy, you can change this
attribute.  (But AFAIK, this is not guaranteed in all implementations.)

 >>> def f(n = 1): pass

 >>> f.__defaults__
(1,)
 >>> f.__defaults__ = (2,)
 >>> f.__defaults__
(2,)

So the following works

 >>> class C():
        def f(n=1): print(n)
       
 >>> class D(C):
        C.f.__defaults__ = (2,)
       
 >>> D.f()
2

Of course, this may or may not do more than you want.

 >>> C.f()
2

--
Terry Jan Reedy



Reply | Threaded
Open this post in threaded view
|

Get classes from "self.MyClass" to improve subclassability

guettli
In reply to this post by guettli
Hi,

crazy. I develop python since several years. I was not aware, that you can
change the defaults of kwargs. I am amazed, but won't use it :-)



Am Samstag, 13. Juni 2015 01:09:47 UTC+2 schrieb Terry Reedy:

> On 6/12/2015 7:12 AM, Thomas G?ttler wrote:
> > Here is a snippet from the argparse module:
> >
> > {{{
> >      def parse_known_args(self, args=None, namespace=None):
> >          ...
> >          # default Namespace built from parser defaults
> >          if namespace is None:
> >              namespace = Namespace() # < ======= my issue
> > }}}
> >
> > I subclass from the class of the above snippet.
> >
> > I would like to use a different Namespace class.
> >
> > if the above could would use
> >
> >      namespace = self.Namespace()
> >
> > it would be very easy for me to inject a different Namespace class.
>
> The default arg (None) for the namespace parameter of the
> parse_known_args is an attribute of the function, not of the class or
> instance thereof.  Unless the default Namespace is used elsewhere, this
> seems sensible.
>
> In CPython, at least, and probably in pypy, you can change this
> attribute.  (But AFAIK, this is not guaranteed in all implementations.)
>
>  >>> def f(n = 1): pass
>
>  >>> f.__defaults__
> (1,)
>  >>> f.__defaults__ = (2,)
>  >>> f.__defaults__
> (2,)
>
> So the following works
>
>  >>> class C():
> def f(n=1): print(n)
>
>  >>> class D(C):
> C.f.__defaults__ = (2,)
>
>  >>> D.f()
> 2
>
> Of course, this may or may not do more than you want.
>
>  >>> C.f()
> 2
>
> --
> Terry Jan Reedy