You are micro-optimising, you should not worry about how many string objects are created there. A few string objects here and there are not going to affect the memory footprint to any noticeable extent, and as you are touching the filesystem here, any performance gains from one look-up method over another is going to melt into insignificance compared with waiting for I/O to complete. Instead, focus on readability and maintainability.
Your example could be simplified further:
project_dir = os.path.join(item_number, 'Project')
os.makedirs(os.path.join(project_dir, 'Images'))
os.makedirs(os.path.join(project_dir, 'Area Templates'))
The intervening directories will be created for you, there is no need to call os.makedirs()
quite so often.
CPython can and will re-use immutable objects created from literals, such as tuples and strings, within the same codeobject. That means that if you used 'Project'
multiple times in one function, then Python can opt to only store one such object in the code-object constants:
>>> def demo():
... project = "Project"
... os.makedirs(os.path.join(item_number, project))
... os.makedirs(os.path.join(item_number, project, 'Images'))
... os.makedirs(os.path.join(item_number, project, 'Area Templates'))
...
>>> demo.__code__.co_consts
(None, 'Project', 'Images', 'Area Templates')
See About the changing id of a Python immutable string for the full details. You should not rely on this behaviour however.