3

I have a program that must continuously create thousands of objects off of a class that has about 12–14 methods. Will the fact that they are of a complex class cause a performance hit over creating a simpler object like a list or dictionary, or even another object with fewer methods?

Some details about my situation: I have a bunch of “text” objects that continuously create and refresh “prints” of their contents. The print objects have many methods but only a handful of attributes. The print objects can’t be contained within the text objects because the text objects need to be “reusable” and make multiple independent copies of their prints, so that rules out just swapping out the print objects’ attributes on refresh.

Am I better off,

  • Continuously creating the new print objects with all their methods as the application refreshes?
  • Unraveling the class and turning the print objects into simple structs and the methods into independent functions that take the objects as arguments?

This I assume would depend on whether or not there is a large cost associated with generating new objects with all the methods included in them, versus having to import all the independent functions to wherever they would have been called as object methods.

kelvinsong
  • 218
  • 1
  • 7
  • A class contains data and methods, initialisation usually means assigning data, only one copy of the methods exists, however many objects you create, if you are worried about starting delay use a compiled language like C++ or C#, which is a better OO language, and easier to learn. A Closure has methods with private data so while a closure is compact in code if it is complex it can be large in memory. – Arif Burhan Mar 04 '16 at 01:57

3 Answers3

5

It doesn't matter how complex the class is; when you create an instance, you only store a reference to the class with the instance. All methods are accessed via this one reference.

chepner
  • 497,756
  • 71
  • 530
  • 681
1

No, it should not make a difference.

Consider that when you do the following:

a = Foo()
a.bar()

The call to the bar method is in fact translated under the covers to:

Foo.bar(a)

I.e. bar is "static" under the class definition, and there exists only one instance of the function. When you look at it this way then it suggests that no, there will be no significant impact from the number of methods. The methods are instantiated when you first run the Python program rather than create objects.

DaveBensonPhillips
  • 3,134
  • 1
  • 20
  • 32
0

I did some testing.

I have the following function:

def call_1000000_times(f):
     start = time.time()
     for i in xrange(1000000):
             f(a=i, b=10000-i)
     return time.time() - start

As you can see, this function takes another function, calls it 1000000 times, and returns how long that took, in seconds.

I also created two classes:

A small class:

class X(object):
     def __init__(self, a, b):
             self.a = a
             self.b = b

And a rather large one:

class Y(object):
     def __init__(self, a, b):
         self.a = a
         self.b = b
     def foo(self): pass
     def bar(self): pass
     def baz(self): pass
     def anothermethod(self):
         pass
     @classmethod
     def hey_a_class_method(cls, argument):
         pass
     def thisclassdoeswaytoomuch(self): pass
     def thisclassisbecomingbloated(self): pass
     def almostattheendoftheclass(self): pass
     def imgonnahaveacouplemore(self): pass
     def somanymethodssssss(self): pass
     def should_i_add_more(self): pass
     def yes_just_a_couple(self): pass
     def just_for_lolz(self): pass
     def coming_up_with_good_method_names_is_hard(self): pass

The results:

>>> call_1000000_times(dict)
0.2680389881134033
>>> call_1000000_times(X)
0.6771988868713379
>>> call_1000000_times(Y)
0.6260080337524414

As you can see, the difference between a large class and a small class is very small, with the large class even being faster in this case. I assume that if you ran this function multiple times with the same type, and averaged the numbers, they'd be even closer, but it's 3AM and I need sleep, so I'm not going to set that up right now.

On the other hand, just calling dict was about 2.5x faster, so if your bottleneck is instantiation, this might be a place to optimize things.

Be wary of premature optimization though. Classes, by holding data and code together, can make your code easier to understand and build upon (functional programming lovers, this is not the place for an argument). It might be a good idea to use the python profiler or other performance measuring tools to find out what parts of your code are slowing it down.

gariepy
  • 3,576
  • 6
  • 21
  • 34
bigblind
  • 12,539
  • 14
  • 68
  • 123
  • would subclassing `dict` be a better choice? – kelvinsong Mar 04 '16 at 02:17
  • Profile it. I'm in bed. – bigblind Mar 04 '16 at 02:22
  • 1
    @kelvinsong: Unlikely to matter. class instances are (excluding the special case of classes with `__slots__`) implemented in terms of a `dict` in any event, named `__dict__` (though in modern Python 3, it's an optimized key sharing `dict` that uses less memory than a normal `dict` if you initialize the same set of attribute names in `__init__` and don't add or remove names after `__init__`), so `dict` lookups happen no matter what. Extend `dict` only if you want to access with `foo['name']` syntax instead of `foo.name`. – ShadowRanger Mar 04 '16 at 03:09