Two-Dimensional Expression Layout

Steve D'Aprano steve+python at pearwood.info
Sat Aug 20 21:13:19 EDT 2016


On Sun, 21 Aug 2016 08:22 am, Lawrence D’Oliveiro wrote:

> Another example, from <https://github.com/ldo/qahirah>: the sequence of
> values is laid out to allow easy additions/modifications in future.

When replying, I normally try to trim unnecessary code snippets down to the
critical line or two, but in this case I think that it is important that I
leave Lawrence's example in place in all its glory. See below for further
comments.


>     for \
>         symname, funcname \
>     in \
>         (
>             ("FC_FONT", "ft_font_face_create_for_ft_face"),
>             ("FT_FONT", "ft_font_face_create_for_pattern"),
>             ("IMAGE_SURFACE", "image_surface_create"),
>             # TODO: MIME_SURFACE, OBSERVER_SURFACE?
>             ("PDF_SURFACE", "pdf_surface_create"),
>             ("PNG_FUNCTIONS", "surface_write_to_png"),
>             ("PS_SURFACE", "ps_surface_create"),
>             ("RECORDING_SURFACE", "recording_surface_create"),
>             ("SCRIPT_SURFACE", "script_create"),
>             ("SVG_SURFACE", "svg_surface_create"),
>             {"USER_FONT", "user_font_face_create"},
>         ) \
>     :
>         setattr \
>           (
>             HAS,
>             symname,
>             hasattr(cairo, "cairo_" + funcname)
>           )
>     #end for
> 
> As a bonus, this also counts as an example of data-driven programming.


Is the subtle bug in your code also a bonus?

If this bug has never bit you, it will when you try to run it under a
version of Python with hash randomization turned on. (3.5 and above, I
think.) You're (accidentally, I presume) relying on the set:

    {"USER_FONT", "user_font_face_create"}

always iterating in the same order. It won't. I assume that's just a typo
and it's meant to be a tuple.

Your idiosyncratic layout obscures what should be a standard two-line for
loop in a jumble of unneeded backslashes, almost empty lines and
indentation.


    for symname, funcname in FONT_TABLE:
        setattr(HAS, symname, hasattr(cairo, "cairo_" + funcname))


where FONT_TABLE is defined previously. If you don't want to give this its
own name, you can embed it in the for loop:


    for symname, funcname in [
            ("FC_FONT", "ft_font_face_create_for_ft_face"),
            ("FT_FONT", "ft_font_face_create_for_pattern"),
            ("IMAGE_SURFACE", "image_surface_create"),
            # TODO: MIME_SURFACE, OBSERVER_SURFACE?
            ("PDF_SURFACE", "pdf_surface_create"),
            ("PNG_FUNCTIONS", "surface_write_to_png"),
            ("PS_SURFACE", "ps_surface_create"),
            ("RECORDING_SURFACE", "recording_surface_create"),
            ("SCRIPT_SURFACE", "script_create"),
            ("SVG_SURFACE", "svg_surface_create"),
            ("USER_FONT", "user_font_face_create"),
            ]:
        setattr(HAS, symname, hasattr(cairo, "cairo_" + funcname))



There's no need to arbitrarily indent parts of expressions to "allow easy
additions" in the future: it is already easy to add new tuples to the
table, or modify existing ones.



-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list