I read the docs of structlog: Configuration
The goal is to reduce your per-file logging boilerplate to:
from structlog import get_logger logger = get_logger()
Is there a way to even reduce this to one import line (without ;
)?
I read the docs of structlog: Configuration
The goal is to reduce your per-file logging boilerplate to:
from structlog import get_logger logger = get_logger()
Is there a way to even reduce this to one import line (without ;
)?
It is not possible to perform a call inside of an import statement.
From Python's grammar:
import_stmt: import_name | import_from
import_name: 'import' dotted_as_names
import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
'import' ('*' | '(' import_as_names ')' | import_as_names))
import_as_name: NAME ['as' NAME]
dotted_as_name: dotted_name ['as' NAME]
import_as_names: import_as_name (',' import_as_name)* [',']
dotted_as_names: dotted_as_name (',' dotted_as_name)*
dotted_name: NAME ('.' NAME)*
The grammar does not specify a form for an import statement where a call is possible. In particular, the only form accepting parentheses is '(' import_as_names ')'
, where import_as_names
is defined as NAME ['as' NAME]
, while a call to a function requires the use of parameters
.
I recommend a thorough reading of the grammar specification for an in-depth understanding.
However, it is possible to accomplish what you are aiming at in one line. Here are three solutions.
The first one is what you mentioned in your question. The second one was evoked by Chris_Rands in comments (and later on in an answer). The third one is basically a cheat, that looks like a one-liner from the main file.
from structlog import get_logger; logger = get_logger()
__import__
functionlogger = __import__('structlog').get_logger()
Note that this is not an import statement, since it does not match any specified form of the above abstract.
interface.py
from structlog import get_logger
logger = get_logger()
main.py
from interface import logger
This is more like cheating, but from the point of view of the main file, the import is a single line.
If you pick this method, I strongly recommend to create a fresh file for the interface.py
. You could be tempted to add a logger = get_logger()
at the end of structlog.py
, but you could break the module, the most obvious situation being that some variable called logger
already exists.
This said, having your code in two lines is absolutely fine. I understand that one can want to make one-liners as often as possible, since Python is pretty good at it (I won't link my posts about lambda
expressions, but you can easily find some examples).
However, get_logger
is actually referenced as structlog.get_logger(*args, **kwargs)
, which means that it can receive arguments to initialize the logger it returns. The way these are used is documented in get_logger
's source.
Now, suppose you have to perform some processing to produce these arguments. Your code will look something like:
from structlog import get_logger
args = initialize_args()
kwargs = initialize_kwargs()
logger = get_logger(args, kwargs)
Well, you could still make it into a one-liner... But it would become unnecessarily long, and pretty much unreadable.
As I mentioned in my comment, to get a one liner, you could use __import__()
:
logger = __import__('structlog').get_logger()
However, as stated in the documentation, using __import__()
is not generally recommended:
Direct use of __import__() is also discouraged in favor of importlib.import_module().
importlib.import_module()
requires importing itself, adding another line via import importlib
, unless you import importlib
via __import__()
, which seems like a bad idea.
Anyway, you don't need __import__()
or importlib.import_module()
in your case, which are normally used when you are importing dynamically from a variable that stores the module name as a string. I think you should keep the two lines you have, which are concise and readable in my opinion.
As stated by others, there is no clean way to do import and function call on the same line. However, there might be a different approach to this problem.
I assume you want to enforce DRY principle. If this is the case, you can place small file in your code base doing both:
# mylog.py
from structlog import get_logger
logger = get_logger() # or any other logic to get a compatible logger
Now, in all other places you can simply get logger instance directly:
from mylog import logger