Is there any good reason for the way you define object variables in an __init__
method, should you build new variables using self.var
or just var
.
Does it matter? Is there a microscopic speed benefit?
Personally I prefer the latter as debatably clearer and less text. But I often see both.
class Person():
def __init__(self, firstname, lastname):
self.first = firstname
self.last = lastname
self.fullname = self.first + ' ' + self.last
Or:
class Person():
def __init__(self, firstname, lastname):
self.first = firstname
self.last = lastname
self.fullname = firstname + ' ' + lastname
Local names are slightly faster, so first
, not self.first
, as the latter requires looking up the local name self
, then looking up the attribute first
on that object. Local variable use is highly optimised compared to all other lookups.
However, the difference is miniscule, and focusing on that is a premature optimisation. Only worry about this if you have to use the same variable loads of times in critical code.
If you ignore the performance differences, then it comes down to requirements and clarity; instance attributes can behave very differently from local variables, which can be an advantage:
If you need to support subclasses that want to alter how self.first
and self.last
behave when assigned to or when accessed (using a property
), then you'd want to use the attributes.
Using the local parameter names on the other hand makes it clear that fullname
is independent of how self.first
and self.last
behave if not simple attributes. That could be intentional.
We can't give any more specific guidelines here because attributes can easily support different use-cases from locals.
If you do need to worry about performance, use the timeit
module to run a micro-benchmark:
>>> from timeit import timeit
>>> class PersonAttributes():
... def __init__(self, firstname, lastname):
... self.first = firstname
... self.last = lastname
... self.fullname = self.first + ' ' + self.last
...
>>> class PersonLocals():
... def __init__(self, firstname, lastname):
... self.first = firstname
... self.last = lastname
... self.fullname = firstname + ' ' + lastname
...
>>> timeit('P("Eric", "Idle")', 'from __main__ import PersonAttributes as P')
0.5858714409987442
>>> timeit('P("Eric", "Idle")', 'from __main__ import PersonLocals as P')
0.5170505980058806
The above creates an instance 1 million times, at which point you'll have saved 40 milliseconds by using local names.