[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Pylint false positives

On Sun, 19 Aug 2018 11:43:44 +0300, Marko Rauhamaa wrote:

> Steven D'Aprano <steve+comp.lang.python at pearwood.info>:
>> On Sun, 19 Aug 2018 00:11:30 +0300, Marko Rauhamaa wrote:
>>> In Python programming, I mostly run into closures through inner
>>> classes (as in Java).
>> Inner classes aren't closures.
> At least some of the methods of inner classes are closures (or there
> would be no point to an inner class).

(1) Ironically, the only times I've used an inner class, its methods were 
not closures. So yes, there are sometimes uses for inner classes that 
don't include closures. There's an example in the argparse module in the 
standard library, and it too has no closures.

(2) Whether or not the methods of an inner class are closures depends on 
the methods, not the fact that it is an inner class. There are no 
closures here:

    class Outer:
        class Inner:

no matter what methods Inner has. Nor is this a closure:

    class Outer:
        def method(self):
            class Inner:
                def spam(self):
                    return self.eggs
            return Inner

since the spam method doesn't close over any of the variables in method.

You made a vague comment about inner classes being equivalent to closures 
in some unknown fashion, but inner classes are not themselves closures, 
and the methods of inner classes are not necessarily closures.

>> Its also quite expensive to be populating your application with lots of
>> classes used only once each, which is a common pitfall when using inner
>> classes. Memory is cheap, but it's not so cheap that we ought to just
>> profligately waste it needlessly.
> That is a completely separate question.

It wasn't a question, it was an observation.

> There's is no a-priori reason for inner classes to be wasteful;

Not in languages where classes are declared statically and built at 
compile-time, no.

But in a language like Python where classes are executable statements 
that are built at run time, like constructing any other mutable object, 
it is very easy to use them badly and waste memory.

This doesn't look harmful:

def func(x):
    class Record:
        def __init__(self, a):
            self.a = a
    return Record(x)

but it is.

You might not like that design, but it is part of Python's execution 
model and whether you like it or not you have to deal with the 
consequences :-)

> they
> have been part and parcel of Java programming from its early days, and
> Java is widely used for high-performance applications.


> CPython does use memory quite liberally. I don't mind that as
> expressivity beats performance in 99% of programming tasks.

Fair enough, but in the example I showed above, the practical effect is 
to increase the de facto size of the objects returned by func() twenty 
times. And fragment memory as well. In a long-lived application where you 
are calling func() a lot, and saving the objects, it all adds up.

>>> populating an object with fields (methods) in a loop is very rarely a
>>> good idea.
>> Of course it is *rarely* a good idea
> So no dispute then.

Isn't there? Then why are you disagreeing with me about the exceptional 
cases where it *is* a good idea?

Steven D'Aprano
"Ever since I learned about confirmation bias, I've been seeing
it everywhere." -- Jon Ronson