简体   繁体   中英

ValueError compatibility and multi-line string aesthetics?

I am trying to write a ValueError message in a nice compact, and clean looking way:

    raise ValueError("Model Architecture Not Recognized. Please ensure that your model's filename contains either"
    """ "vgg" and "16" for a 16 layer VGG model, "vgg" and "19" for a 19 layer VGG model, or "nin" for a Network"""
    " In Network model. Note that filenames are not case sensitive.")   

Will this work for both Python 2.7 and Python 3? Is there a better way to have a multi-line error message? Are there any issues with not using a + in between the strings used for the error message?

Will this work for both Python 2.7 and Python 3?

Yes, string literal concatenation works the same way in Python 2 and Python 3 .

Is there a better way to have a multi-line error message?

Yes. Especially since this isn't actually a multi-line error message in the first place. See below.

Are there any issues with not using a + in between the strings used for the error message?

Semantically, no. Adjacent string literals are concatenated into a single string value. String literals separated by + define a bunch of separate string values, then ask Python to concatenate them at runtime. But, because the compiler knows that the expression is made up of nothing but immutable constants, it will fold them together into a single value. 1, 2

But pragmatically, it can be hard to read code like this (especially when you're trying to read it on an 80-column display like a typical terminal-mode editor, or Stack Overflow). As a reader, how do I know whether you intended three string literals to be concatenated into one value, or three string literals with commas between them to be passed as three separate values to the ValueError constructor? Well, if I look carefully, and think about it, there's not much point to passing those two other strings as extra arguments to a ValueError (even though it's legal), and those spaces make it look like the strings are meant to go together, and so on… but it would be better if I could understand you code without looking carefully, scrolling the window to the right, and thinking about it. So, sometimes it's worth using a + , or even something ugly like backslash continuation, to avoid that confusion.


As mentioned above, you haven't produced a multi-line string. The strings get concatenated into one giant line. And it seems like you already know this, or you wouldn't have prepended a space to the start of the second and third literals.

If you actually want a multiline string, you could do that by adding \\n characters in appropriate places.

But it's a lot easier to just write a multiline string:

raise ValueError("""Model Architecture Not Recognized. Please ensure that your model's filename contains either
    "vgg" and "16" for a 16 layer VGG model, "vgg" and "19" for a 19 layer VGG model, or "nin" for a Network
    In Network model. Note that filenames are not case sensitive.""")

Or, even better, use textwrap , so you can write something that looks nice in your source but also looks nice on output:

raise ValueError(textwrap.fill(textwrap.dedent("""
    Model Architecture Not Recognized. Please ensure that your model's
    filename contains either "vgg" and "16" for a 16 layer VGG model, 
    "vgg" and "19" for a 19 layer VGG model, or "nin" for a Network
    In Network model. Note that filenames are not case sensitive.
"""))

But if you're expecting this to be printed as part of a traceback, rather than, say, except Exception as e: print(e) , it's still going to look funky:

ValueError:  Model Architecture Not Recognized. Please ensure that your model's
filename contains either "vgg" and "16" for a 16 layer VGG model,
"vgg" and "19" for a 19 layer VGG model, or "nin" for a Network In
Network model. Note that filenames are not case sensitive.

A better solution is probably to write a short error string plus a separate long (multi-line, if you want) description string. You can even make your own ValueError subclass that represents itself by dumping the long string. You can even throw the textwrap stuff into the subclass. So then, you'd write, say:

raise ModelArchitectureError(
    "Model Architecture Not Recognized.",
    """Please ensure that your model's
        filename contains either "vgg" and "16" for a 16 layer VGG model, 
        "vgg" and "19" for a 19 layer VGG model, or "nin" for a Network
        In Network model. Note that filenames are not case sensitive.
    """))

Or, even better, make those default values for the ModelArchitectureError 's constructor, so you can just do this:

raise ModelArchitectureError()

1. Of course Python doesn't require this constant evaluation, it just allows it. CPython 2.7 and 3.7, PyPy 6 2.7 and 3.5, and Jython 2.7 all do it, but some other implementation might not. In that case, the + version would have the same end-user-visible effect, but it would take more time and temporary memory (and possibly cache space and string-intern-table space) to do it.

2. If you write an import hook that transforms the code at the source, token, or AST level before passing it to the compiler, the two could conceivably be different, because they don't become the same until the compiler/optimizer gets to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM