Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #101442 > unrolled thread

What use of these _ prefix members?

Started byRobert <rxjwg98@gmail.com>
First post2016-01-10 09:55 -0800
Last post2016-01-12 10:01 -0500
Articles 6 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  What use of these _ prefix members? Robert <rxjwg98@gmail.com> - 2016-01-10 09:55 -0800
    Re: What use of these _ prefix members? Steven D'Aprano <steve@pearwood.info> - 2016-01-11 05:03 +1100
    Re: What use of these _ prefix members? Peter Otten <__peter__@web.de> - 2016-01-10 19:34 +0100
      Re: What use of these _ prefix members? me <self@example.org> - 2016-01-12 14:12 +0000
        Re: What use of these _ prefix members? Peter Otten <__peter__@web.de> - 2016-01-12 15:52 +0100
        Re: What use of these _ prefix members? Jason Swails <jason.swails@gmail.com> - 2016-01-12 10:01 -0500

#101442 — What use of these _ prefix members?

FromRobert <rxjwg98@gmail.com>
Date2016-01-10 09:55 -0800
SubjectWhat use of these _ prefix members?
Message-ID<4ee5810e-abe9-4c4b-9ebd-d989b5c2b341@googlegroups.com>
Hi,

When I read a sample file from hmm learn package, which is on top of 
scikit-learn package, I see there are many member functions (prefix with 
'_') have no caller. That is, I don't see anything uses those functions.
Below is a sample part from class GMMHMM(_BaseHMM):





//////////
    def __init__(self, n_components=1, n_mix=1,........
                 params="stmcw", init_params="stmcw"):
        _BaseHMM.__init__(self, n_components,.........
                          params=params, init_params=init_params)

        # XXX: Hotfit for n_mix that is incompatible with the scikit's
        # BaseEstimator API
        self.n_mix = n_mix
        self.covariance_type = covariance_type
        self.covars_prior = covars_prior
        self.gmms_ = []
        for x in range(self.n_components):
            if covariance_type is None:
                gmm = GMM(n_mix)
            else:
                gmm = GMM(n_mix, covariance_type=covariance_type)
            self.gmms_.append(gmm)

    def _init(self, X, lengths=None):
        super(GMMHMM, self)._init(X, lengths=lengths)

        for g in self.gmms_:
            g.set_params(init_params=self.init_params, n_iter=0)
            g.fit(X)

    def _compute_log_likelihood(self, X):
        return np.array([g.score(X) for g in self.gmms_]).T

    def _generate_sample_from_state(self, state, random_state=None):
        return self.gmms_[state].sample(1, random_state=random_state).flatten()
////////////

Some online tutorials tell me '_' prefix is a kind of convention of private 
members. hmm is not a formal package. Do these '_' member functions are
unfinished? Or, they may be used in some way I don't know yet?

Thanks,

[toc] | [next] | [standalone]


#101443

FromSteven D'Aprano <steve@pearwood.info>
Date2016-01-11 05:03 +1100
Message-ID<56929cef$0$1612$c3e8da3$5496439d@news.astraweb.com>
In reply to#101442
On Mon, 11 Jan 2016 04:55 am, Robert wrote:

> Some online tutorials tell me '_' prefix is a kind of convention of
> private members. 

Correct. Not just private members, but private *anything*.

Any time you see anything starting with a single underscore, whether it is a
module, class, method, attribute or variable, you can assume that it is
private (unless explicitly documented otherwise) and avoid it.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#101444

FromPeter Otten <__peter__@web.de>
Date2016-01-10 19:34 +0100
Message-ID<mailman.7.1452450908.3151.python-list@python.org>
In reply to#101442
Robert wrote:


> When I read a sample file from hmm learn package, which is on top of
> scikit-learn package, I see there are many member functions (prefix with
> '_') have no caller. That is, I don't see anything uses those functions.
> Below is a sample part from class GMMHMM(_BaseHMM):

I bet the caller is in the superclass _BaseHMM, like in the following made-
up example:

>>> class Base:
...     def __init__(self, x):
...         self._init(x)
...     def _init(self, x): print("do something with", x)
... 
>>> class Derived(Base):
...     def _init(self, x):
...         super()._init(x)
...         print("do something else with", x)
... 
>>> Derived(42)
do something with 42
do something else with 42
<__main__.Derived object at 0x7f8e6b3e9b70>

[toc] | [prev] | [next] | [standalone]


#101543

Fromme <self@example.org>
Date2016-01-12 14:12 +0000
Message-ID<n731jm$1apr$1@gioia.aioe.org>
In reply to#101444
On 2016-01-10, Peter Otten <__peter__@web.de> wrote:
>>>> class Derived(Base):
> ...     def _init(self, x):
> ...         super()._init(x)
> ...         print("do something else with", x)
> ... 
>>>> Derived(42)
> do something with 42
> do something else with 42
><__main__.Derived object at 0x7f8e6b3e9b70>
>

I think you are doing inheritance wrong.

AFAIK you should call directly the __init__() of the parent class, and
pass *args and **kwargs instead.

Except for that, yes, the _init would be conventionally private. Not
enforced by name mangling though.

[toc] | [prev] | [next] | [standalone]


#101545

FromPeter Otten <__peter__@web.de>
Date2016-01-12 15:52 +0100
Message-ID<mailman.63.1452610366.13488.python-list@python.org>
In reply to#101543
Someone else posting as "me" wrote:

> On 2016-01-10, Peter Otten <__peter__@web.de> wrote:
>>>>> class Derived(Base):
>> ...     def _init(self, x):
>> ...         super()._init(x)
>> ...         print("do something else with", x)
>> ...
>>>>> Derived(42)
>> do something with 42
>> do something else with 42
>><__main__.Derived object at 0x7f8e6b3e9b70>
>>
> 
> I think you are doing inheritance wrong.

If by "you" you mean "me" -- the above sample is an illustration of the 
pattern I expected to see elsewhere in the software Robert was quoting, not 
an endorsement. I have now looked into the hmmlearn source, and it turns out 
that _init() is invoked by the fit() method rather than the initializer. 
But...
 
> AFAIK you should call directly the __init__() of the parent class, and
> pass *args and **kwargs instead.

you sometimes want to break initialisation or any other method into distinct 
steps that don't make sense stand-alone:

class Foo:
    def method(...)
        self._one(...)
        self._two(...)
        self._three(...)

That way subclasses have the option to override only _two() instead of 
method() and users of Foo won't try to invoke _two(...) on its own.

I think this is a good approach.

What arguments you need to accept and/or pass on is a question that you can 
decide depending on the actual use-case. I use

*args, **kwargs

only if function is very generic because it makes code hard to follow.

> Except for that, yes, the _init would be conventionally private. Not
> enforced by name mangling though.

[toc] | [prev] | [next] | [standalone]


#101546

FromJason Swails <jason.swails@gmail.com>
Date2016-01-12 10:01 -0500
Message-ID<mailman.64.1452610921.13488.python-list@python.org>
In reply to#101543
On Tue, Jan 12, 2016 at 9:12 AM, me <self@example.org> wrote:

> On 2016-01-10, Peter Otten <__peter__@web.de> wrote:
> >>>> class Derived(Base):
> > ...     def _init(self, x):
> > ...         super()._init(x)
> > ...         print("do something else with", x)
> > ...
> >>>> Derived(42)
> > do something with 42
> > do something else with 42
> ><__main__.Derived object at 0x7f8e6b3e9b70>
> >
>
> I think you are doing inheritance wrong.
>

​There's nothing "wrong" about this, and there are times this type of
pattern is justified.  Sure, *this* example doesn't make sense to do it
this way, but this is just an illustrative example.  I would even call this
type of pattern pythonic.
​
​

> AFAIK you should call directly the __init__() of the parent class, and
> ​​
> pass *args and **kwargs instead.
>

Sometimes there's no need to call __init__ on the parent class directly,
and the base class's __init__ is sufficient for the derived class.  And
perhaps initialization requires numerous "steps" that are easiest to grok
when split out into different, private sub-methods. For example:

class Derived(Base):
​    def __init__(self, arg1, arg2, arg3):
        self._initial_object_setup()
        self._process_arg1(arg1)
        self._process_arg23(arg2, arg3)
        self._postprocess_new_object()​

This makes it clear what is involved in the initialization of the new
object.  And it allows the functionality to be split up into more atomic
units.  It also has the added benefit of subclasses being able to more
selectively override base class functionality.  Suppose Derived only needs
to change how it reacts to arg1 -- all Derived needs to implement directly
is _process_arg1.  This reduces code duplication and improves
maintainability, and is a pattern I've used myself and like enough to use
again (not necessarily in __init__, but outside of being automatically
called during construction I don't see anything else inherently "specialer"
about __init__ than any other method).

All the best,
Jason

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web