On 2020-02-09 4:46 p.m., Andrew Barnert wrote:
> On Feb 9, 2020, at 05:40, Soni L. <fakedme...@gmail.com> wrote:
>
> I'd rather have arg decorators tbh. they feel more natural than hacking on the type annotations.
Annotations look a lot more natural to me here.
Maybe that’s because your only example (besides the useless original one) looks
like an implicit cast a la C++ and zillions of other languages:
void cheese(Spam spam) {
// whatever
}
Eggs eggs(42);
cheese(eggs);
Oversimplifying the C++ rules a bit, this will call the Spam::Spam(Eggs)
constructor on eggs to get a Spam, and that will be the value of spam. Which is
exactly what you’re trying to do, so spelling it similarly seems reasonable:
@implicit_cast
def cheese(spam: Spam):
# whatever
eggs = Eggs(42)
cheese(eggs)
This would of course raise a TypeError at runtime instead of at compile time if
there is no way to construct a Spam from an Eggs, and it requires a decorator
because it’s not built deep into the language as it is in C++, but otherwise
it’s the same idea and the most obvious way to translate its spelling.
Maybe if you had a good example that wasn’t an implicit type cast, this
similarity would be an argument against using annotations rather than an
argument for using them? But it’s hard to know without seeing such an example,
or even knowing if you have such an example.
That's C++. But consider this:
class Foo:
def bar(self):
pass
x = Foo()
y = x.bar
The traits thing is just as much of an implicit cast as Python methods
are an implicit cast. Which is to say, it isn't. Traits don't have a
constructor - instead, calling them with an object will, if the object
allows it, create a wrapper object to handle the trait method lookups
and any necessary wrapping or unwrapping of objects. This is also the
way to access conflicting names: MyTrait(MyClass()).x() is defined in
the @impl(MyTrait) (and does print("Hello,") then print("World!")),
whereas MyClass().x() is the inherent method in MyClass (and only prints
"World!"). Note also that the @impl gets the full unwrapped object, and
not a TraitWrapper - this is by design.
This has many parallels to how methods in python do the "self" thing,
altho I can understand the confusion if you're not familiar with traits
in e.g. Rust.
> I'd need to create wrapper functions and deal with mixed args and kwargs. as
far as I know there aren't libraries that do it for me, either.
You only need to create one decorator that creates wrapping functions. There is
a library that deals with args and kwargs for you, and it comes with Python:
inspect. There are also libraries in PyPI to help write decorators, to do
cast-like stuff, etc. If there isn’t a library that puts it all together the
way you want, then that probably means there isn’t nearly enough demand for
this feature to even put it in the stdlib, much less add new syntax for it. But
that also means you can write it yourself and put it on PyPI and proselytize
its use, and maybe create that demand.
Don't forget: kw-only arguments, positional-only arguments, arguments
that can be either, default values, etc.
_______________________________________________
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/P5APZZX7L56YIMKAON7YKD274WAXLUNB/
Code of Conduct: http://python.org/psf/codeofconduct/