Why is creating a class in Python so much slower than instantiating a class?

前端 未结 4 1233
谎友^
谎友^ 2021-01-31 17:33

I found that creation of a class is way slower than instantiation of a class.

>>> from timeit import Timer as T
>>> def calc(n):
...     return         


        
相关标签:
4条回答
  • 2021-01-31 17:47

    Ahahaha! Gotcha!

    Was this perchance done on a Python version without this patch? (HINT: IT WAS)

    Check the line numbers if you want proof.

    Marcin was right: when the results look screwy you've probably got a screwy benchmark. Run gc.disable() and the results reproduce themselves. It just shows that when you disable garbage collection you get garbage results!


    To be more clear, the reason running the long benchmark broke things is that:

    • timeit disables garbage collections, so overly large benchmarks take much (exponentially) longer

    • timeit wasn't restoring garbage collection on exceptions

    • You quit the long-running process with an asynchronous exception, turning off garbage collection

    0 讨论(0)
  • 2021-01-31 17:54

    A quick dis of the following functions:

    def a():
        class Haha(object):
             pass
    
    
    
    def b():
        Haha()
    

    gives:

    2           0 LOAD_CONST               1 ('Haha')
                3 LOAD_GLOBAL              0 (object)
                6 BUILD_TUPLE              1
                9 LOAD_CONST               2 (<code object Haha at 0x7ff3e468bab0, file "<stdin>", line 2>)
                12 MAKE_FUNCTION            0
                15 CALL_FUNCTION            0
                18 BUILD_CLASS         
                19 STORE_FAST               0 (Haha)
                22 LOAD_CONST               0 (None)
                25 RETURN_VALUE        
    

    and

    2           0 LOAD_GLOBAL              0 (Haha)
                3 CALL_FUNCTION            0
                6 POP_TOP             
                7 LOAD_CONST               0 (None)
                10 RETURN_VALUE        
    

    accordingly.

    By the looks of it, it simply does more stuff when creating a class. It has to initialize class, add it to dicts, and wherever else, while in case of Haha() is just calls a function.

    As you noticed doing garbage collection when it gets's too slow speeds stuff up again, so Marcin's right in saying that it's probably memory fragmentation issue.

    0 讨论(0)
  • 2021-01-31 17:55

    It isn't: Only your contrived tests show slow class creation. In fact, as @Veedrac shows in his answer, this result is an artifact of timeit disabling garbage collection.

    Downvoters: Show me a non-contrived example where class creation is slow.

    In any case, your timings are affected by the load on your system at the time. They are really only useful for comparisons performed at pretty much the same time. I get about 0.5s for 9000 class creations. In fact, it's about 0.3s on ideone, even when performed repeatedly: http://ideone.com/Du859. There isn't even an upward trend.

    So, in summary, it is much slower on your computer than others, and there is no upwards trend on other computers for repeated tests (as per your original claim). Testing massive numbers of instantiations does show slowing down, presumably because the process consumes a lot of memory. You have shown that allocating a huge amount of memory slows a process down. Well done.

    That ideone code in full:

    from timeit import Timer as T
    def calc(n):
    return T("class Haha(object): pass").timeit(n)
    
    for i in xrange(30):
    print calc(9000)
    
    0 讨论(0)
  • 2021-01-31 18:03

    This might give you the intuition:

    >>> class Haha(object): pass
    ...
    >>> sys.getsizeof(Haha)
    904
    >>> sys.getsizeof(Haha())
    64
    

    Class object is much more complex and expensive structure than an instance of that class.

    0 讨论(0)
提交回复
热议问题