On Sun, Apr 19, 2020 at 7:58 AM Stephen J. Turnbull <
turnbull.stephen...@u.tsukuba.ac.jp> wrote:

> Alex Hall writes:
>
>  > > And now Lisp bites me, because '::a' means ...
>
>  > And a single colon also means something else in Lisp.
>
> Yeah, and I already pointed that out myself in this subthread.  I
> don't like these notations, and the conflict with Lisp (which I read a
> lot of) is part of why.  My taste, or the existence of Lisp, doesn't
> rule the issue, but it's input.
>
>  > Does it matter much what that notation means in a different
>  > language?
>
> Of course it might.  That's why we use the usual arithmetic operators
> for their usual meanings.  :: is not a universally used notation, but
> if we can find an alternative that's even less used, why not use that
> alternative?
>
>  > Python will struggle to evolve if it can't conflict with other
>  > languages.
>
> Strawman.  Nobody said "can't".  The question is "better".
>

OK, that's fair. What about `{foo::}`?

 > > I myself am rarely annoyed by this issue, with
>  > > the single exception of "self.foo = foo" in __init__() defs (which
>  > > can't be handled by these notations).
>  > >
>  >
>  > It can be handled:
>  >
>  > ```
>  > self.__dict__.update(**, foo, bar, spam)
>  > ```
>
> I hope you're kidding.
>
>  > And here is some actual code of mine using it:
>  >
>  > ```
>  >     setattrs(cls,
>  >              text=text,
>  >              program=program,
>  >              messages=messages,
>  >              hints=hints)
>  > ```
>
> I once wrote code like that as needed; my point was that I now rarely
> need it.  There are already more concise, clearer, less ugly
> alternatives available, at least for the cases where *I* wrote code
> like that.
>

I don't understand what's happening. You clearly said you are still annoyed
by `self.foo = foo`, but that this proposal doesn't address that. I pointed
out that the proposal does address it. There's one way which is slightly
ugly but requires no setup. There's another way that's prettier and just
requires introducing one simple function.

I would personally be quite happy if I could replace:

```
class A:
    def __init__(self, foo, bar, spam):
        self.foo = foo
        self.spam = spam
        self.bar = bar
```

with something like:

```
class A:
    def __init__(self, foo, bar, spam):
        setattrs(self, **, foo, bar, spam)
```

Wouldn't you? Of course there's also dataclasses, but there's plenty of
places where those don't apply so nicely.

(the name 'setattrs' may not be the best for the purpose)

I can't speak for your needs, only guess.  But these
> examples of function *calls* don't give me enough information to
> decide for myself whether I think there's a need to write them, much
> less show you how I would write the program without them.
>

I provided a script to help find such cases. Let's make this more concrete.
Here is the script again, slightly improved:

```
import ast
import linecache
import sys
from collections import Counter
from pathlib import Path

root = Path(sys.argv[1])


def main():
    counts = Counter()
    for path in root.rglob("**/*.py"):
        if 'test' in str(path):
            continue
        try:
            source = path.read_text()
            tree = ast.parse(source)
        except (SyntaxError, UnicodeDecodeError):
            continue

        for node in ast.walk(tree):
            if isinstance(node, ast.Call):
                def is_same_name(keyword: ast.keyword):
                    return (
                            isinstance(keyword.value, ast.Name)
                            and keyword.value.id == keyword.arg
                    )

                args = node.keywords
            elif isinstance(node, ast.Dict):
                def is_same_name(pair):
                    key, value = pair
                    return (
                            isinstance(value, ast.Name) and
                            isinstance(key, (ast.Constant, ast.Str)) and
                            value.id == key.s
                    )

                args = zip(node.keys, node.values)
            else:
                continue

            count = sum(map(is_same_name, args))
            if count:
                counts[count] += 1
            if count < 7:
                continue

            print(f'File "{path}", line {node.lineno}')
            for lineno in range(node.lineno, node.end_lineno + 1):
                print(linecache.getline(str(path), lineno), end="")
            print()
    print("Counts:", counts)


main()
```

I ran this on master of the cpython repo. Here is the output with all the
cases with at least 7 same-named values:

```
File "setup.py", line 2232
        self.add(Extension('_decimal',
                           include_dirs=include_dirs,
                           libraries=libraries,
                           define_macros=define_macros,
                           undef_macros=undef_macros,
                           extra_compile_args=extra_compile_args,
                           sources=sources,
                           depends=depends))

File "Tools/clinic/clinic.py", line 1083
        d = {
            "docstring_prototype" : docstring_prototype,
            "docstring_definition" : docstring_definition,
            "impl_prototype" : impl_prototype,
            "methoddef_define" : methoddef_define,
            "parser_prototype" : parser_prototype,
            "parser_definition" : parser_definition,
            "impl_definition" : impl_definition,
            "cpp_if" : cpp_if,
            "cpp_endif" : cpp_endif,
            "methoddef_ifndef" : methoddef_ifndef,
        }

File "Lib/shutil.py", line 554
    return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
                     ignore=ignore, copy_function=copy_function,
                     ignore_dangling_symlinks=ignore_dangling_symlinks,
                     dirs_exist_ok=dirs_exist_ok)

File "Lib/tempfile.py", line 642
        self._TemporaryFileArgs = {'mode': mode, 'buffering': buffering,
                                   'suffix': suffix, 'prefix': prefix,
                                   'encoding': encoding, 'newline': newline,
                                   'dir': dir, 'errors': errors}

File "Lib/compileall.py", line 99
            results = executor.map(partial(compile_file,
                                           ddir=ddir, force=force,
                                           rx=rx, quiet=quiet,
                                           legacy=legacy,
                                           optimize=optimize,

 invalidation_mode=invalidation_mode,
                                           stripdir=stripdir,
                                           prependdir=prependdir,
                                           limit_sl_dest=limit_sl_dest),

File "Lib/argparse.py", line 879
        super().__init__(
            option_strings=_option_strings,
            dest=dest,
            nargs=0,
            default=default,
            type=type,
            choices=choices,
            required=required,
            help=help,
            metavar=metavar)

File "Lib/argparse.py", line 917
        super(_StoreAction, self).__init__(
            option_strings=option_strings,
            dest=dest,
            nargs=nargs,
            const=const,
            default=default,
            type=type,
            choices=choices,
            required=required,
            help=help,
            metavar=metavar)

File "Lib/argparse.py", line 1009
        super(_AppendAction, self).__init__(
            option_strings=option_strings,
            dest=dest,
            nargs=nargs,
            const=const,
            default=default,
            type=type,
            choices=choices,
            required=required,
            help=help,
            metavar=metavar)

File "Lib/argparse.py", line 1038
        super(_AppendConstAction, self).__init__(
            option_strings=option_strings,
            dest=dest,
            nargs=0,
            const=const,
            default=default,
            required=required,
            help=help,
            metavar=metavar)

File "Lib/json/__init__.py", line 234
    return cls(
        skipkeys=skipkeys, ensure_ascii=ensure_ascii,
        check_circular=check_circular, allow_nan=allow_nan, indent=indent,
        separators=separators, default=default, sort_keys=sort_keys,
        **kw).encode(obj)

File "Lib/json/__init__.py", line 173
        iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
            check_circular=check_circular, allow_nan=allow_nan,
indent=indent,
            separators=separators,
            default=default, sort_keys=sort_keys, **kw).iterencode(obj)

File "Lib/asyncio/base_events.py", line 1254
                opts = dict(local_addr=local_addr, remote_addr=remote_addr,
                            family=family, proto=proto, flags=flags,
                            reuse_address=reuse_address,
reuse_port=reuse_port,
                            allow_broadcast=allow_broadcast)

File "Lib/logging/__init__.py", line 108
_nameToLevel = {
    'CRITICAL': CRITICAL,
    'FATAL': FATAL,
    'ERROR': ERROR,
    'WARN': WARNING,
    'WARNING': WARNING,
    'INFO': INFO,
    'DEBUG': DEBUG,
    'NOTSET': NOTSET,
}
```

Please make a PR showing how you would refactor some of these.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/RJGWJVNGND6SFHKMQHKRINRGC5LNAH7N/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to