Jacob Solinsky writes:

 > What I had hoped to do was use a preamble code block to collect all of the
 > most common queries called by the mutate function in the local namespace,
 > for example
 > 
 > C = 'bpgkdtszSZjCmnywh'
 > M = 'mn'
 > 
 > 
 > class Morpheme:
 >     #stuff
 > 
 > def preamble(self):
 > 
 >     ps = self.precedingmorpheme.form
 >     ss = self.succeedingmorpheme.form
 >     ssc = re.match(f'^[{C}]', self.succedingmorpheme.form) #Whether or not
 > the following morpheme is consonant initial
 >     ssm = re.match(f'[{M}]$', self.precedingmorpheme.form) #Whether or not
 > the preceding morpheme is nasal final
 > 
 > these local variables are used quite often in the mutate methods, of which
 > there are several dozen, so storing them by default saves a lot of
 > typing.

What you're asking for is basically a "Ruby block", AFAICS.  This has
been requested many times, but most of the senior Pythonistas consider
that it leads to a very high risk of unreadable and/or buggy code at
no gain in power (there are several ways to efficiently accomplish
what you want to do, you just don't like them[1]), and few cases where
it's more readable/less buggy.  I think if you search "ruby block
site:mail.python.org" you'll probably bring up the threads.  You won't
find a lot of encouraging discussion, I'm afraid.

What I would do in your case is

    class Morpheme:
        class Preamble:
            def __init__(self, m):    # "m" for "morpheme"
                self.ps = m.precedingmorpheme.form
                self.ss = m.succeedingmorpheme.form
                self.ssc = re.match(f'^[{C}]', m.succedingmorpheme.form)
                self.ssm = re.match(f'[{M}]$', m.precedingmorpheme.form)
        def mutate():
            p = self.Preamble(self)
            # use p.ps, p.ss, etc

It's a little less efficient, of course, because of overhead managing
the Preamble objects.

Another possibility would be to use properties, so that instead of
*storing* these temporary variables on the Morpheme, they would be
computed on the fly:

    class Morpheme:
    @property
    def ps(self):
        return self.precedingmorpheme.form
    @property
    def ss(self):
        return self.succeedingmorpheme.form
    @property
    def ssc(self):
        return re.match(f'^[{C}]', self.succeedingmorpheme.form)
    @property
    def ssm(self):
        return re.match(f'[{M}]$', self.precedingmorpheme.form)

and so on.  Then you can access them with "self.ps" etc in the mutate
method.  This might be considered elegant (although verbose in the
Morpheme definition) if these properties are usually used only once
per mutate call, and "expensive" properties like ssc and ssm are never
called more than once.  (If they are called multiple times, it's easy
to create a cache.)  Of course property accesses do add method call
overhead, but they look nicer than method call syntax.  On the other
hand, if "many" properties are expensive, and "most" mutate methods
use only a few of these, you could save runtime this way, since the
expensive methods are called only as-needed.

I don't understand the "need default value in __init__" issue, since
"inject" implied to me that you initialize before use.  But if that's
a problem for ordinary attributes, I presume it'll be more annoying
with properties because you have to write a method for it.  So I don't
know if this is helpful at all.

Footnotes: 
[1]  "I don't like it" is a sufficient reason to propose a change.
I'm simply saying you have the *power* to do what you want.

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to