[Python-ideas] Re: symbolic math in Python

2021-05-26 Thread Sergey B Kirpichev
> Although nothing in Python prevents defining __eq__() how you want and
> having it return other values can still be problematic to do so
> because of the way that __eq__() is tied to __hash__() and used in
> dicts and sets.

I think, this can work if you guarantee there are no hash collisions.  This is 
doable,
if you restrict yourself by some symbolic class hierarchy: e.g. you can 
enumerate
symbolic objects within the session.  Probably, id() will work: remember - all 
your
objects are singletons!

But you will not be able to mix built-in data types and your symbolic objects in
same set, for example.  In fact, this might be not a too high price: e.g. SymPy
already uses Integer's and Rational's instead of built-in types.  So, every 
"external"
object must be converted to your class hierarchy.

> Also a==b should only return True

That's an easy thing, but I doubt that the docs enforce us to do this.
___
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/BLZGOFVE6MMKDCS3TK2NJ6JJMFZGXJYD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Eric V. Smith

On 5/26/2021 7:07 AM, Chris Angelico wrote:

Either way, it would be a string. The difference is that string
literals can be placed adjacent to each other:


"{1}" f' - {1+2=} - ' '{2}'

'{1} - 1+2=3 - {2}'

Which goes to show, btw, that an f-string is still a literal, even
though it's not a constant.


Again unrelated to the topic at hand, but I think it's interesting to 
see what's going on behind the scenes:


>>> dis.dis("'{1}' f' - {1+2=} - ' '{2}'")
  1   0 LOAD_CONST   0 ('{1} - 1+2=')
  2 LOAD_CONST   1 (3)
  4 FORMAT_VALUE 2 (repr)
  6 LOAD_CONST   2 (' - {2}')
  8 BUILD_STRING 3
 10 RETURN_VALUE

The 1+2 expression is replaced by 3 by some optimizer step. Regular 
strings and the literal part of f-strings are merged by the f-string 
"compiler".


I keep forgetting about this behavior. I usually start doubling the 
braces, but this auto-concatenation is probably a better idea.


Eric

___
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/IGUTSS7ADRA45RK4VVVZIIDWAVP47U6N/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Rob Cliffe via Python-ideas
I have certainly overridden sys.stdout, it's USEFUL, Shreyan.  (One use 
case was to make programs pause after each screenful of output. Probably 
I've also used it to suppress output.)

But I didn't know about sys.__stdout__, thanks Steven.
And yes, I'm at least as confused as to what the proposal is as anybody 
else.

Rob Cliffe

On 26/05/2021 14:20, Steven D'Aprano wrote:

On Wed, May 26, 2021 at 12:53:32PM -, Shreyan Avigyan wrote:

I've already given one. Since Python is dynamically typed changing a critical 
variable can cause huge instability. Want a demonstration? Here we go,

import sys
sys.stdout = None

Now what? Now how can we print anything? Isn't this a bug?

Assigning to None is probably a TypeError, because None doesn't
implement the file object interface. But assigning to a file is
perfectly correct.

stdout, stdin and stderr are designed to be assigned to.

That's why the sys module defines `sys.__stdout__` etc, so you can
easily restore them to the originals.

You should also note that there are many circumstances where sys.stdout
etc are all set to None. See the documentation.

https://docs.python.org/3/library/sys.html#sys.__stdin__




___
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/RK74MBNQEL7NIU4ZGWK6Z2T5OTX43YX4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: A __decoration_call__ method for Callable objects (WAS: Decorators on variables)

2021-05-26 Thread Ricky Teachey
On Wed, May 26, 2021 at 2:22 PM Matt del Valle  wrote:

> I'm still digesting this proposal (though I think I like it quite a bit),
> but there's one thing in particular that just really doesn't gel with me.
>
> Is there any particular reason why you've proposed assignment decorators
> as being on the same line as the assignment statement rather than on the
> preceding line(s)?
>

No reason, very bikesheddable.

I like this:
>
> @typing.TypeVar
> T = str, bytes
>
>
> about a million times better than:
>
> @typing.TypeVar T = str, bytes
>
>
> Because the latter feels (to me) too similar for comfort to this:
>
> int foo = 3
>
>
> Which is in my mind not very pythonic. Also, my brain just has an easier
> time parsing the multiline version than the single-line one (though I
> concede that a combination of familiarity and syntax highlighting would
> solve that issue eventually).
>
> It also represents an asymmetry between the syntax of the proposed
> assignment decorators and the syntax for function and class decorators.
>
> And finally, it doesn't cleanly accommodate use-cases like those proposed
> by Stéfane in the previous thread:
>
> @acl(READ, WRITE)
> @constraint(10 < _ < 100)
> @not_null
> @indexed
> @depends_on(whatever)
> @inject
> first_name: str
>
>
> Whereas the multiline variant does.
>
> Another question I've got is whether you've got any solution in mind for
> more complex assignment cases?
>

I do not as of yet. Still thinking about it.


> After thinking about the proposals in the Steven's thread (the googly-eye
> symbol), I think I'm a fan of providing the name as a *tuple of tuple of
> strings*, like so:
>
> @decorate
> foo = first, _, third, *rest = bar = [0, 1, 2, 3, 4]
>
>
> such that __decoration_call__ receives the following tuple for its second
> argument:
>
> (('foo',), ('first', '_', 'third', '*rest'), ('bar',)
>
> And it can then choose to do whatever it likes with all the available
> names without having to implement its own logic for parsing the names back
> out from a string.
>
> My only other question would be, what would you think of adding a third
> argument to pass the type hint along? Function decorators can always access
> the __annotations__ on the function object they act on, but currently your
> __decoration_call__ can't capture type information. With such an argument,
> this:
>
> @decorate
> foo: int = 3
>
>
> Would be provided to 'decorate' as:
>
> def __decoration_call__(self, obj, names, annotation):
> print(obj)  # 3
> print(names)# (('foo',),)
> print(annotation)   # int
>
>
I'd not be opposed.

Another (fourth) argument could be the code object from the RHS (if
inspect.getsource can't be shoehorned into getting it for us).

---
Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home
or actually going home." - Happy Chandler
___
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/25FRSQJJPY3SLH3D3SXLNRO2H4IBMDO4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: A __decoration_call__ method for Callable objects (WAS: Decorators on variables)

2021-05-26 Thread Matt del Valle
I'm still digesting this proposal (though I think I like it quite a bit),
but there's one thing in particular that just really doesn't gel with me.

Is there any particular reason why you've proposed assignment decorators as
being on the same line as the assignment statement rather than on the
preceding line(s)?

I like this:

@typing.TypeVar
T = str, bytes


about a million times better than:

@typing.TypeVar T = str, bytes


Because the latter feels (to me) too similar for comfort to this:

int foo = 3


Which is in my mind not very pythonic. Also, my brain just has an easier
time parsing the multiline version than the single-line one (though I
concede that a combination of familiarity and syntax highlighting would
solve that issue eventually).

It also represents an asymmetry between the syntax of the proposed
assignment decorators and the syntax for function and class decorators.

And finally, it doesn't cleanly accommodate use-cases like those proposed
by Stéfane in the previous thread:

@acl(READ, WRITE)
@constraint(10 < _ < 100)
@not_null
@indexed
@depends_on(whatever)
@inject
first_name: str


Whereas the multiline variant does.

Another question I've got is whether you've got any solution in mind for
more complex assignment cases?

After thinking about the proposals in the Steven's thread (the googly-eye
symbol), I think I'm a fan of providing the name as a *tuple of tuple of
strings*, like so:

@decorate
foo = first, _, third, *rest = bar = [0, 1, 2, 3, 4]


such that __decoration_call__ receives the following tuple for its second
argument:

(('foo',), ('first', '_', 'third', '*rest'), ('bar',)

And it can then choose to do whatever it likes with all the available names
without having to implement its own logic for parsing the names back out
from a string.

My only other question would be, what would you think of adding a third
argument to pass the type hint along? Function decorators can always access
the __annotations__ on the function object they act on, but currently your
__decoration_call__ can't capture type information. With such an argument,
this:

@decorate
foo: int = 3


Would be provided to 'decorate' as:

def __decoration_call__(self, obj, names, annotation):
print(obj)  # 3
print(names)# (('foo',),)
print(annotation)   # int


But yeah, overall I'm liking this proposal best out of the ones that have
been discussed recently. The google-eyes symbol is a solid idea, and is
sufficient for many basic use-cases, but it's not really as powerful as
real decorators and cannot accommodate the more complex cases (like the
example above with several chained decorators, some of which are actually
decorator factories).


On Wed, May 26, 2021 at 5:52 PM Ricky Teachey  wrote:

> I made a mistake. This sentence:
>
> My idea is to optionally allow any callable object to write a
>> __decoration_call__ method that gets called in lieu of the __call__ method
>> when the callable object is employed using decorator syntax. When this
>> happens, the decorated named is supplied- not counting self- as the first
>> argument (e.g., by_name), which contains the str value of the name the
>> decorator was applied to.
>
>
> Should read:
>
> My idea is to optionally allow any callable object to write a
> __decoration_call__ method that gets called in lieu of the __call__ method
> when the callable object is employed using decorator syntax. When this
> happens, the decorated named is supplied- not counting self- as the
> *SECOND* argument (e.g., by_name), which contains the str value of the
> name the decorator was applied to.
>
> ---
> Ricky.
>
> "I've never met a Kentucky man who wasn't either thinking about going home
> or actually going home." - Happy Chandler
>
>
> On Wed, May 26, 2021 at 12:43 PM Ricky Teachey  wrote:
>
>> On Wed, May 26, 2021 at 7:54 AM Steven D'Aprano 
>> wrote:
>>
>>> On Wed, May 26, 2021 at 01:33:07PM +0200, Stéfane Fermigier wrote:
>>>
>>> > Last point that I like in the decorator syntax: it's
>>> >
>>> > I can compose N different decorators and keep the intent obvious:
>>> >
>>> > @acl(READ, WRITE)
>>> > @constraint(10 < _ < 100)
>>> > @not_null
>>> > @indexed
>>> > @depends_on(whatever)
>>> > @inject
>>> > @...
>>> > first_name: str
>>>
>>> Hmm, that's a good point.
>>>
>>> On the other hand, it would be terribly confusing if the same syntax:
>>>
>>> @decorate
>>>
>>> had radically different meaning depending on whether it was followed by
>>> a class/function or a bare name.
>>>
>>>
>>> --
>>> Steve
>>>
>>
>> and previously Steve also said:
>>
>> On Tue, May 25, 2021 at 3:28 AM Steven D'Aprano 
>> wrote:
>>
>>> On Mon, May 24, 2021 at 06:36:47PM -0700, micro codery wrote:
>>>
>>> > Basically this would add syntax to python that would transform
>>> > @decorator("spam this") variable
>>> > into
>>> > variable = decorator("variable", "spam this")
>>>
>>> That is confusingly different from decorator syntax in other contexts
>>>
>>> @decorator("spam 

[Python-ideas] Re: Decorators on variables

2021-05-26 Thread micro codery
While I am not at this point dropping the idea of @decorator(expression)
targetname
a thought occurred to me yesterday after discussing targetname as a string
in
assignments (and I appreciate the continued discussion in a new thread but
this is a new counter proposal so keeping it here).
There is at least one other place where python saves us from retyping the
lhs
in an assignment statement: augmented assignment. It is not being used as a
string, true, and it's much more difficult to introduce a subtle bug by
mis-typing
the name if one were to use the standard operator instead. But we still have
augmented assignment for all operators IMO because programmers are
productively lazy and came up with a way to not retype their variable.

What if, instead of adding a new magic symbol to the assignment
statement (statements? still not sure which ones are supported in the
counter proposal) we add a new assignment operator and corresponding
dunder method that would perform the real operation behind the syntactic
sugar.

For now I propose the operator "<==" and dunder "__assign__". Both
very bikeshedable, but allows us to draw some examples

RED <== str

would become

RED = str.__assign__("RED")
# or is this how it's actually done? don't remember
# RED = type(str).__assign__(str, "RED")

where str now has the method

def __assign__(cls, assignment_name):
return assignment_name

Following the example of augmented assignment, both of these would
be SyntaxErrors:

spam = eggs <== str
spam, eggs <== str

Although there is probably a way to make the second one work, that
can be experimented with in a reference implementation or saved for
a later PEP.

Some more of my original examples with the new operator:

Point <== namedtuple("x y z")

UUIDType: str <== NewType

Colors <== Enum("RED GREEN BLUE")

class Colors(Enum):
RED <== str
GREEN <== str
BLUE< == str

It would also be possible to reuse a factory, similar to the way a
decorator that takes arguments first creates a sort of closure and
is then that is passed the function object in a subsequent call.

SPAM_DB <== get_sql_db(pass=_secret, user=user)
TABLE1 <== SPAM_DB
TABLE2 <== SPAM_DB

would be the same as

SPAM_DB = get_sql_db(pass=_secret, user=user).__assign__("SPAM_DB")
TABLE1 = SPAM_DB.__assign__("TABLE1")
TABLE2 = SPAM_DB.__assign__("TABLE2")

Regards
~Jeremiah
___
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/XOLERYBQ7CQ7VEKCUUN2XKQR4SJQN6VR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: A __decoration_call__ method for Callable objects (WAS: Decorators on variables)

2021-05-26 Thread Valentin Berlier
Now this is a really interesting proposal. Something wasn't right in the other 
discussion, I didn't think making variable decorators inconsistent with the 
current class and function decorators by providing the variable name was 
particularly good. I've always felt like that something like 
__decoration_call__ was missing, so I'm really grateful that someone took the 
time to think about it. I'd say this looks pretty promising, and I can't see 
any specific downside compared to the alternative proposals.
___
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/KX5ZOTCYLGLUT365VKE6U45HAISKI7ZC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: A __decoration_call__ method for Callable objects (WAS: Decorators on variables)

2021-05-26 Thread Ricky Teachey
I made a mistake. This sentence:

My idea is to optionally allow any callable object to write a
> __decoration_call__ method that gets called in lieu of the __call__ method
> when the callable object is employed using decorator syntax. When this
> happens, the decorated named is supplied- not counting self- as the first
> argument (e.g., by_name), which contains the str value of the name the
> decorator was applied to.


Should read:

My idea is to optionally allow any callable object to write a
__decoration_call__ method that gets called in lieu of the __call__ method
when the callable object is employed using decorator syntax. When this
happens, the decorated named is supplied- not counting self- as the
*SECOND* argument
(e.g., by_name), which contains the str value of the name the decorator was
applied to.

---
Ricky.

"I've never met a Kentucky man who wasn't either thinking about going home
or actually going home." - Happy Chandler


On Wed, May 26, 2021 at 12:43 PM Ricky Teachey  wrote:

> On Wed, May 26, 2021 at 7:54 AM Steven D'Aprano 
> wrote:
>
>> On Wed, May 26, 2021 at 01:33:07PM +0200, Stéfane Fermigier wrote:
>>
>> > Last point that I like in the decorator syntax: it's
>> >
>> > I can compose N different decorators and keep the intent obvious:
>> >
>> > @acl(READ, WRITE)
>> > @constraint(10 < _ < 100)
>> > @not_null
>> > @indexed
>> > @depends_on(whatever)
>> > @inject
>> > @...
>> > first_name: str
>>
>> Hmm, that's a good point.
>>
>> On the other hand, it would be terribly confusing if the same syntax:
>>
>> @decorate
>>
>> had radically different meaning depending on whether it was followed by
>> a class/function or a bare name.
>>
>>
>> --
>> Steve
>>
>
> and previously Steve also said:
>
> On Tue, May 25, 2021 at 3:28 AM Steven D'Aprano 
> wrote:
>
>> On Mon, May 24, 2021 at 06:36:47PM -0700, micro codery wrote:
>>
>> > Basically this would add syntax to python that would transform
>> > @decorator("spam this") variable
>> > into
>> > variable = decorator("variable", "spam this")
>>
>> That is confusingly different from decorator syntax in other contexts
>>
>> @decorator("spam this")
>> def func(): pass
>>
>> # transformed to:
>>
>> def func(): pass
>> func = decorator("spam this")(func)
>>
>> ...the critical difference is that the argument "spam this" should be
>> passed to the decorator *factory*, which then returns the actual
>> decorator that gets applied to the variable. (Or function/ class in the
>> case of regulator decorator syntax.)
>
>
> Well, in actuality even if it were implemented the way you described, it
> is still going to be very different--- I might even say radically different.
>
> These two ideas of a decorator syntax result are not the same:
>
> RESULT A: function decorator
> # func = decorator("spam")(func)
>
> RESULT B: variable decorator
> # name = decorator("spam")("name")
>
> ...because func is passed as an object, but "name" a string representing
> the name of the object. Two very different things.
>
> For this reason I think I would agree even more so that the differences in
> the decorator behavior would be an extremely significant point of confusion.
>
> This got me to thinking: what if access to the variable name were provided
> by another means, and ONLY when the decorator syntax is employed?
>
> So then I started to write this big long email and it kind of got out of
> hand. Hopefully it isn't a disaster.
>
> FIRST LAYER: RICK'S (LIKELY HALF-BAKED) COUNTER PROPOSAL
>
> Maybe employment of decorator syntax could OPTIONALLY trigger a new dunder
> method-- here I'll just call it __decoration_call__-- with the signature:
>
> def  __decoration_call__(self, obj: Any, by_name: str) -> Any: ...
>
> Before I describe what I intend by this, first I will stipulated that what
> I am proposing here should only be implemented so that the behavior of all
> currently existing decorators (i.e., all callables) would remain exactly as
> it does today.
>
> So, for any existing callable with the name decorator, this:
>
> @decorator("spam this")
> def func(): ...
>
> ...continues to mean this, just as it does today:
>
> def func(): ...
> func = decorator("spam this")(func)
>
> My idea is to optionally allow any callable object to write a
> __decoration_call__ method that gets called in lieu of the __call__ method
> when the callable object is employed using decorator syntax. When this
> happens, the decorated named is supplied- not counting self- as the first
> argument (e.g., by_name), which contains the str value of the name the
> decorator was applied to.
>
> Let's explain using code examples.
>
> In actuality, unless I'm wrong (I might be; not an expert) current
> decorator syntax is really sugar for:
>
> def func(): ...
> func = decorator.__call__("spam this").__call__(func)
>
> My proposal is to make it such that:
>
> @decorator
> def func(): ...
>
> ...*can result* in this:
>
> def func(): ...
> func = decorator.__decoration_call__( 

[Python-ideas] A __decoration_call__ method for Callable objects (WAS: Decorators on variables)

2021-05-26 Thread Ricky Teachey
On Wed, May 26, 2021 at 7:54 AM Steven D'Aprano  wrote:

> On Wed, May 26, 2021 at 01:33:07PM +0200, Stéfane Fermigier wrote:
>
> > Last point that I like in the decorator syntax: it's
> >
> > I can compose N different decorators and keep the intent obvious:
> >
> > @acl(READ, WRITE)
> > @constraint(10 < _ < 100)
> > @not_null
> > @indexed
> > @depends_on(whatever)
> > @inject
> > @...
> > first_name: str
>
> Hmm, that's a good point.
>
> On the other hand, it would be terribly confusing if the same syntax:
>
> @decorate
>
> had radically different meaning depending on whether it was followed by
> a class/function or a bare name.
>
>
> --
> Steve
>

and previously Steve also said:

On Tue, May 25, 2021 at 3:28 AM Steven D'Aprano  wrote:

> On Mon, May 24, 2021 at 06:36:47PM -0700, micro codery wrote:
>
> > Basically this would add syntax to python that would transform
> > @decorator("spam this") variable
> > into
> > variable = decorator("variable", "spam this")
>
> That is confusingly different from decorator syntax in other contexts
>
> @decorator("spam this")
> def func(): pass
>
> # transformed to:
>
> def func(): pass
> func = decorator("spam this")(func)
>
> ...the critical difference is that the argument "spam this" should be
> passed to the decorator *factory*, which then returns the actual
> decorator that gets applied to the variable. (Or function/ class in the
> case of regulator decorator syntax.)


Well, in actuality even if it were implemented the way you described, it is
still going to be very different--- I might even say radically different.

These two ideas of a decorator syntax result are not the same:

RESULT A: function decorator
# func = decorator("spam")(func)

RESULT B: variable decorator
# name = decorator("spam")("name")

...because func is passed as an object, but "name" a string representing
the name of the object. Two very different things.

For this reason I think I would agree even more so that the differences in
the decorator behavior would be an extremely significant point of confusion.

This got me to thinking: what if access to the variable name were provided
by another means, and ONLY when the decorator syntax is employed?

So then I started to write this big long email and it kind of got out of
hand. Hopefully it isn't a disaster.

FIRST LAYER: RICK'S (LIKELY HALF-BAKED) COUNTER PROPOSAL

Maybe employment of decorator syntax could OPTIONALLY trigger a new dunder
method-- here I'll just call it __decoration_call__-- with the signature:

def  __decoration_call__(self, obj: Any, by_name: str) -> Any: ...

Before I describe what I intend by this, first I will stipulated that what
I am proposing here should only be implemented so that the behavior of all
currently existing decorators (i.e., all callables) would remain exactly as
it does today.

So, for any existing callable with the name decorator, this:

@decorator("spam this")
def func(): ...

...continues to mean this, just as it does today:

def func(): ...
func = decorator("spam this")(func)

My idea is to optionally allow any callable object to write a
__decoration_call__ method that gets called in lieu of the __call__ method
when the callable object is employed using decorator syntax. When this
happens, the decorated named is supplied- not counting self- as the first
argument (e.g., by_name), which contains the str value of the name the
decorator was applied to.

Let's explain using code examples.

In actuality, unless I'm wrong (I might be; not an expert) current
decorator syntax is really sugar for:

def func(): ...
func = decorator.__call__("spam this").__call__(func)

My proposal is to make it such that:

@decorator
def func(): ...

...*can result* in this:

def func(): ...
func = decorator.__decoration_call__( func, "func")

And also so that this:

@decorator("spam this")
def func(): ...

...*can result* in this:

def func(): ...
func = decorator.__call__("spam this").__decoration_call__(func, "func")

I say "*can result*" because this has the following limitations:

   1. occurs only when the callable object is employed as a decorator
   2. occurs only when  __decoration_call__ exists (and if it doesn't, just
   revert back to the usual __call__(func_object, obj))

Here is an example to further illustrate the suggested behavior. It is not
intended to demonstrate a useful example. You could write a callable object
like this:

class Decorator:
def __call__(self, obj):
print("spam")
return obj
def __decoration_call__(self , obj, by_name):
print("eggs")
print(by_name)
return obj

decorator = Decorator()

And the behavior would be like this:

def func(): ...
func = decorator(func)
# Console output:
# 'spam'

@decorator
def func(): ...
# Console output:
# 'eggs'
# 'func'

In order to preserve current behavior, the built-in  type
would not grow its own new   __decoration_call__ method. So in the case of
existing normal functions, and also 

[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Well. How can I go beyond why constant was invented in the first place? As far 
as I can understand by my limited knowledge that *sometimes* constants can be 
useful, sometimes they are terrible. The main reason constant was invented was 
to provide an additional support to programmers so that they don't make a 
program unstable.  And there are code that really have this problem. Python can 
be "Consenting Adults" language but so are others they just don't claim it. 
Programming is programming, it depends on the user and author what they'll 
choose to do "enforcing" or "consenting adults". And I must confess I don't 
like type checking in this context because Python should itself help us point 
out these relatively small but extremely important bugs related to constants 
(or Final). And constants doesn't make code fast. To avoid decreasing current 
performance, I propose to add new OP code and new AST node for constants so 
that they don't mingle with variables. And all constant assignment check
 ing should be done at runtime not compile time. I hope this actually answers 
all of the questions coming up till now.
___
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/7ZLY3PBGBUC3RGIFWEK5ZZTFU573N3NH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Stephen J. Turnbull
Shreyan Avigyan writes:

 > I've already given one. Since Python is dynamically typed changing
 > a critical variable can cause huge instability. Want a
 > demonstration? Here we go,
 > 
 > import sys
 > sys.stdout = None
 > 
 > Now what?
 > Now how can we print anything?

With print().  Even in your code, it still works, for an appropriate
definition of "works".  See next comment.

 > Isn't this a bug?

Maybe, but if it is, it's a bug because you didn't sys.stdout.close()
before rebinding it.[1]  sys.stdout = None is useful; it has the
effect of

sys.stdout = open("/dev/null", "w")

ie, shutting up a chatty program.  (This surprised me; I thought print
would raise because None has no 'write' attribute.  It's an 'is None'
test, not a bool test; it does complain on sys.stdout = 0.  It really
doesn't like 0, it complains again -- about 'flush' -- on interpreter
exit. :-)

 > There are lots of code out there where we need to protect things
 > from being overwritten.

Perhaps you could give a more persuasive example.  The whole idea is
against the usual "consenting adults" approach of Python.  Or as that
famous Python programmer Barack Obama put it, "let's try not to do
stupid shit." :-)


Footnotes: 
[1]  I suspect there's a race condition in some environments.  At
least up to version 9, MacOS poll(2) and X.org were buggy together.
The event loop would poll(), and if you had an open file descriptor
that hadn't been closed before fork but was somehow unused in the
child, it would infloop on an OS error from poll().  So if you fork
before sys.stdout gets GC'd and therefore .close()'d, you could end up
with such a zombie fd.
___
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/QNRFTDB65VFJ6LWSJFGNIV2EZCFBM2DW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Add support for private variables, methods and functions in Python

2021-05-26 Thread Stephen J. Turnbull
Steven D'Aprano writes:
 > On Tue, May 25, 2021 at 04:24:39PM +0900, Stephen J. Turnbull wrote:

 > It's not really purely cooperative. API consumers always want more than 
 > the API designers are willing or able to give.

True enough as stated, but "purely cooperative" doesn't mean "if I
optimize, you get the best of all worlds".  It means if we
communicate, we can coordinate and get a good solution.  If we don't
communicate, generally we get a bad outcome.  The situations you
describe don't seem to have a lot of communication in the design of
the APIs.

There are situations where communication is difficult.  Developer A
provides an API tuned to Developer B's application, and later
Developer C wants A's functionality but wants a different API.  Or (as
is frequently the case with open source) Developer A is both producer
and the initial consumer of the API, and drops the producer on PyPI
with an "as-is" notice, frustrating Developer C.

Point is, you're right, and lack of communication between API
producers and API consumers is why you're right.  That is a problem
for management; you can't engineer it away, neither with "private,
protected, public", nor by avoiding them.

Steve
___
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/5V2MBESTK2T5CNU4D5IT6ZONOFJBBU6F/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Stephen J. Turnbull
Ricky Teachey writes:
 > Continuing on with Steven's counter proposal and the motivating example of
 > symbolic math, for multiple symbols it would be this:
 > 
 > #  x, y, z = symbols( 'x,y,z' )
 > x, y, z = symbols(@@)
 > 
 > However, even though it works for the symbols example, this meaning looks
 > odd to me:
 > 
 > #  x, y, z = symbols( 'x,y,z' )
 > 
 > ...it seems like this should in fact be *three separate assignment
 > operations*, not a single assignment operation.

I don't think so.  AFAIK, that syntax is not three separate assignment
statments, conceptually: it's a tuple construction followed by
destructuring assignment.  That is, it's the problem of symbols() to
return a compatible tuple.

 > This version also works for the symbols example, though it calls the
 > factory function 3 times rather than 1. Is that an important downside?

Even if we interpret it as three assignments, I don't think so.
Internally, it has to call Symbol() three times anyway, and you save a
@@.split() call.

The other possibility would be to interpret

x, y, z = symbols(@@)

as

x, y, z = symbols('x', 'y', 'z')

SymPy can change this API, or add a new one, to be compatible with the
googly eyes feature.  The hardest part would be coming up with a name
if a new API was the route chosen.  SymPy users would adopt by
acclamation, I think.  The problem with this is that this doesn't work
for anything but sequences, although I'm not sure how useful most
other expressions on the lhs are anyway.

 > I am on the fence for the better meaning of this:
 > 
 > x = y = z = symbols(@@)

I think this already has a meaning:

x = y = (z := symbols(@@))

You could change it, of course, but I'd WTF every time I'm afraid.
For the symbols() application, I'm much more sympathetic to the 

x, y, z = symbols(@@)

syntax, most likely with the str value of @@ constructed in a
canonical way from the AST as Chris suggests.  SymPy can adapt or not
as it chooses.

Bikeshed: we could put a nail in the coffin of "from __future__ import
barry_as_flufl" using "<>" as the RHS token instead of googly eyes.
(0.5 wink -- I realized the implication for barry_as_flufl only after
thinking of this alternative.)  I'd kinda like to save @@ for some
hypothetical matrix operation.

Steve

___
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/M7LT466BSABYC3XGWFFJD3GUGUMDBRGR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread MRAB

On 2021-05-26 13:53, Shreyan Avigyan wrote:

I've already given one. Since Python is dynamically typed changing a critical 
variable can cause huge instability. Want a demonstration? Here we go,

import sys
sys.stdout = None

Now what? Now how can we print anything? Isn't this a bug? There are lots of 
code out there where we need to protect things from being overwritten. Though 
I'm never telling to use constants in Python stdlib or else I could have never 
done this demonstration. :)


Actually, I've done something like that.

import codecs
import sys
sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach())

This was because I was running a script from an editor and it picked up 
the wrong output encoding, raising an error when I tried to print 
characters that were outside the ASCII range. Thankfully that problem is 
now solved, but it was a useful workaround.

___
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/JMOD4JJEZICZPMTCVWGYTXZMIXNOR2JS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Paul Moore
On Wed, 26 May 2021 at 14:33, Shreyan Avigyan  wrote:
>
> Reply to Paul Moore:
>
> > But you just said it was runtime, so it definitely *isn't* similar to
> > the syntax error "Can't assign to literal here". You're making
> > inconsistent statements again :-(
>
> That's exactly why I wrote SomeErrorType instead of SyntaxError. They are 
> never similar. I just said the behavior would seem similar.

Your precise comment was

> Constants should have a similar error -
>
> constant x = 10
> x = [2]
> SomeErrorType: Can't assign to constant here.

See above? You said "Constants should have a similar error" and then
in your response to my reply, you said "That's exactly why I wrote
SomeErrorType instead of SyntaxError. They are never similar. I just
said the behavior would seem similar." How am I to interpret that?
Your statements are directly contradictory ("similar error" vs "never
similar"). And for information, I personally don't find compile time
and runtime exceptions to "seem similar" at all, especially in the
context of this discussion where we've repeatedly tried to get you to
decide whether you're talking about compile time or runtime.

> I'm trying my best. But sometimes there are few questions coming up that 
> confuses and I'm not sure of the answer and I'm ending up making inconsistent 
> statements.

So stop replying instantly, read the feedback, think your proposal
through, and when you have an updated proposal that actually addresses
all of the flaws people have pointed out with your current proposal,
post that (with a clear explanation of what you changed and why).
Knee-jerk replies from you aren't respectful of the time people are
putting into trying to follow what you're proposing :-(

Paul

PS I know there's a tendency for people to reply very quickly on this
list, and I know that can leave people feeling under pressure to reply
quickly themselves. But it's a false pressure - some people simply
need time to digest feedback, others are having to handle a language
they are not a native speaker of, still others may have other reasons
for needing extra time. If you're in a situation like that, please
*do* take that time. We won't complain if you take time to compose
your answers.
___
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/DI6S7HTMNDAB7MK4BRWJ33UL3QWSHKTL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 11:20 PM Shreyan Avigyan
 wrote:
>
> Reply to Chris:
>
> Yes I know that. sys.stdout exists there for that reason only. But if we 
> can't print then it means we changed it somewhere. I just gave an example.

Yes, an example where you're trying to show... something. Which I
still don't understand, because you're advocating constants, and then
citing an example of something that is specifically there for the
purpose of being changed/replaced.

> I've seen code where constants can be really necessary. Python lets us use 
> these things because it's a programming language. But libraries are not 
> programming languages. They are there to enhance the programming. Suppose 
> we're testing out a library. Now maybe there's something really critical we 
> shouldn't change. We must access but mustn't change. And we mistakenly 
> changed it. Now we're not gonna deploy our application. So we don't run a 
> type checker. Now we run and the program crashes and yet we can't find where 
> is the bug. Why should tools be needed to solve such an obvious problem? Why 
> can't Python itself help us like it does when we add int and str?
>

So if you think you have a problem, your program crashes, and
you're having trouble finding the bug... then.. maybe that would
be a good time to use a type checker? I don't know. Your examples are
so extremely vague, and you're assuming that (a) the library author
can and does declare that something shouldn't ever be changed, (b) the
program author can and does attempt to change it, (c) the library
author was correct and the program author was wrong, and (d) the
program author couldn't figure this out by the fact that the name was
in ALL_CAPS. That is a lot of big assumptions, especially the third
one.

Plus, you're assuming that this constness will be detected if the
mutation happens in some other module, which is NOT part of several
iterations of the proposal.

Need a more specific example. Yaknow, an actual example, not just
"this might happen in some universe".

Figure out what you're actually proposing. Figure out what real
problems it is supposed to be able to solve. The problems you're
solving should govern the feature you're proposing.

ChrisA
___
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/UEUVY4HCNMHZT6BUV2FBEKO25XS3IU5P/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Paul Moore:

> But you just said it was runtime, so it definitely *isn't* similar to
> the syntax error "Can't assign to literal here". You're making
> inconsistent statements again :-(

That's exactly why I wrote SomeErrorType instead of SyntaxError. They are never 
similar. I just said the behavior would seem similar.

> I don't think you've thought this proposal through at all, to be
> honest. You seem to be making up answers as the questions arise, which
> is *not* what people are asking for here. We are asking that you
> *explain* your proposal, assuming that you already know the answers
> and are simply struggling to communicate the details.

I'm trying my best. But sometimes there are few questions coming up that 
confuses and I'm not sure of the answer and I'm ending up making inconsistent 
statements.
___
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/KK5EL5SSQWMVHKGLIGBBAHBLQIF5O47Q/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 12:53:32PM -, Shreyan Avigyan wrote:
> I've already given one. Since Python is dynamically typed changing a critical 
> variable can cause huge instability. Want a demonstration? Here we go,
> 
> import sys
> sys.stdout = None
> 
> Now what? Now how can we print anything? Isn't this a bug? 

Assigning to None is probably a TypeError, because None doesn't 
implement the file object interface. But assigning to a file is 
perfectly correct.

stdout, stdin and stderr are designed to be assigned to.

That's why the sys module defines `sys.__stdout__` etc, so you can 
easily restore them to the originals.

You should also note that there are many circumstances where sys.stdout 
etc are all set to None. See the documentation.

https://docs.python.org/3/library/sys.html#sys.__stdin__


-- 
Steve
___
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/2BNQFPWLNBF37XXCU6RYCA5Q7PWZQEXT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Chris:

Yes I know that. sys.stdout exists there for that reason only. But if we can't 
print then it means we changed it somewhere. I just gave an example. I've seen 
code where constants can be really necessary. Python lets us use these things 
because it's a programming language. But libraries are not programming 
languages. They are there to enhance the programming. Suppose we're testing out 
a library. Now maybe there's something really critical we shouldn't change. We 
must access but mustn't change. And we mistakenly changed it. Now we're not 
gonna deploy our application. So we don't run a type checker. Now we run and 
the program crashes and yet we can't find where is the bug. Why should tools be 
needed to solve such an obvious problem? Why can't Python itself help us like 
it does when we add int and str?
___
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/VWSRDEO4APJ2QFFRGYZXNDCWNEEEIZ7S/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 11:15 PM Steven D'Aprano  wrote:
>
> On Wed, May 26, 2021 at 10:37:34PM +1000, Chris Angelico wrote:
>
> > Also, what about this:
> >
> > constant x = 10
> > def f():
> > x = 20
> >
> > SyntaxError? Runtime error? Shadowing?
>
> The x inside the function is just a local variable. The x outside the
> function and the x inside it are in different namespaces and shouldn't
> clobber each other any more than variables in different namespaces do.

I'd kinda expect that too, but given the uncertainties in the rest of
this thread, I wasn't certain.

I'm fairly lost as to what the proposal even is, though. It seems to
morph every time it gets poked.

ChrisA
___
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/AQFQXG3INBUBBOY7FGJCQKODRWKZDL6A/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 10:37:34PM +1000, Chris Angelico wrote:

> Also, what about this:
> 
> constant x = 10
> def f():
> x = 20
> 
> SyntaxError? Runtime error? Shadowing?

The x inside the function is just a local variable. The x outside the 
function and the x inside it are in different namespaces and shouldn't 
clobber each other any more than variables in different namespaces do.


Constants in statically typed languages are easy, because the compiler 
knows which names are constant at compile-time and can disallow 
assignments to those names without any runtime cost.

Constants in dynamically typed languages like Python are hard, because 
we either have to severely restrict their use so that they can be 
determined at compile-time, which goes against the dynamic nature of the 
language, or else we have to slow down every assignment to check whether 
it is a constant or not. So the irony is that constants can speed up 
statically typed languages, but slow down dynamically typed ones.


-- 
Steve
___
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/OREZTG4ZKJS24DSU2Z2BAUOUICRYIQRH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread 2QdxY4RzWzUUiLuE
On 2021-05-26 at 12:53:32 -,
Shreyan Avigyan  wrote:

> I've already given one. Since Python is dynamically typed changing a
> critical variable can cause huge instability. Want a demonstration?
> Here we go,
> 
> import sys
> sys.stdout = None
> 
> Now what? Now how can we print anything? Isn't this a bug? There are
> lots of code out there where we need to protect things from being
> overwritten. Though I'm never telling to use constants in Python
> stdlib or else I could have never done this demonstration. :)

In C:

fclose(stdout);

Now what?  Now how can we print anything?

(I'm sure other languages allow programs to close stdout, but C has come
up in this thread before.)

There are a handful of real use cases for closing (or otherwise
changing) stdout; e.g., background/daemon processes, programs that
operate exclusively in a graphical environment.
___
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/WJP6SHVNHCX35T4M5VRR2FOFIKYHH2TG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Paul Moore
On Wed, 26 May 2021 at 13:13, Shreyan Avigyan  wrote:
>
> Reply to Paul Moore:
>
> In Python terms, a constant is a name that binds itself to a value in memory 
> and that name cannot bind itself to a different value now (unlike variables). 
> The value can be mutated (if mutable) but the name cannot bind to a different 
> value once it has bind itself to a value.

"value in memory" isn't Python terminology. Nor is "variable". Please
point me to the exact sections in the language reference if you feel
I'm wrong here. In particular, Python refers to "identifiers" and
"names" - see 
https://docs.python.org/3/reference/lexical_analysis.html#identifiers
("Identifiers (also referred to as names) are described by the
following lexical definitions.")

On Wed, 26 May 2021 at 13:31, Shreyan Avigyan  wrote:
>
> Reply to Paul Moore:
>
> if some_condition:
> constant a = 1
> else:
> a = 2
> a = 3
>
> Yes this is allowed. This is runtime.

OK, so a=3 may raise an exception at runtime (depending on the value
of some_condition). We need to decide exactly what exception would be
used but I'm OK with that. It's specifically *not* a syntax exception,
though, as that's a compile-time exception.

>
> for i in range(10):
> constant a = []
>
> Not sure. Though it's preferable to be runtime. Preferable is "not allowed".

I don't know what you mean here. Are you saying that you'd prefer it
not to be allowed? It's your proposal, the decision is up to you.

> And lists are also literals. Any Python Object that is not assigned to a 
> variable is a literal. Python claims that itself. A preview -

Read the language reference here:
https://docs.python.org/3/reference/lexical_analysis.html#literals

> [10] = [2]
> SyntaxError: Can't assign to literal here.

As Chris pointed out, this is flagging the assignment to the literal
10. Have you properly researched the existing semantics to make sure
you understand what you're proposing to change, or are you just
guessing?

> Constants should have a similar error -
>
> constant x = 10
> x = [2]
> SomeErrorType: Can't assign to constant here.

But you just said it was runtime, so it definitely *isn't* similar to
the syntax error "Can't assign to literal here". You're making
inconsistent statements again :-(

On Wed, 26 May 2021 at 13:53, Shreyan Avigyan  wrote:
>
> I've already given one. Since Python is dynamically typed changing a critical 
> variable can cause huge instability. Want a demonstration? Here we go,
>
> import sys
> sys.stdout = None

However, there's a *huge* amount of extremely useful code out there
that does assign to sys.stdout - pytest's mechanisms for capturing
test output use this, for example. Making sys.stdout constant would
break this.

I don't think you've thought this proposal through at all, to be
honest. You seem to be making up answers as the questions arise, which
is *not* what people are asking for here. We are asking that you
*explain* your proposal, assuming that you already know the answers
and are simply struggling to communicate the details.

Paul
___
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/DJSIL362DVSYXOLGZEM24NGAXJTOHGL3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 12:31:07PM -, Shreyan Avigyan wrote:
> Reply to Paul Moore:
> 
> if some_condition:
> constant a = 1
> else:
> a = 2
> a = 3
> 
> Yes this is allowed. This is runtime.

Do you have any suggestions for how this should be implemented, how the 
interpreter will know at runtime whether or not the name `a` is a 
constant?



> for i in range(10):
> constant a = []
> 
> Not sure. Though it's preferable to be runtime. Preferable is "not allowed".

That is equivalent to:

constant a = []
constant a = []
constant a = []
# seven more times


If you can't rebind constants, then that better be disallowed. Otherwise 
you have rebound the constant `a` nine times: initialised it to one list 
on the first loop, and then the next nine loops you bind the same name 
to nine different lists.


> And lists are also literals.

Lists are not literals. The documentation calls them *displays*. You 
won't find lists under "literals":

https://docs.python.org/3/reference/expressions.html#literals

but you will find them here:

https://docs.python.org/3/reference/expressions.html#list-displays

I admit that I too often wrongly refer to expressions like `[1, 2]` as a 
list literal, but that language is not technically correct for Python.



> Any Python Object that is not assigned to a variable is a literal. 

That's incorrect. When I write the expression:

print(a*x + b)

the object returned by `a*x + b` is not assigned to anything, but it's 
not a literal.


> Python claims that itself. A preview -
> 
> [10] = [2]
> SyntaxError: Can't assign to literal here.

You are misinterpreting the error. If you look at the pointer in the 
syntax error, it points at the 10, not the list:


>>> [10] = [2]
  File "", line 1
[10] = [2]
 ^
SyntaxError: cannot assign to literal

That statement is doing sequence unpacking: it unpacks the list [2], and 
the target list [10], and tries to assign 10 = 2 which is forbidden 
because 10 is a literal, *not* because `[10]` is a literal. (It isn't.)

You can see a better example here:

>>> [a, b, c, 10, d, e] = range(6)
  File "", line 1
[a, b, c, 10, d, e] = range(6)
  ^
SyntaxError: cannot assign to literal


-- 
Steve
___
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/K47EGJ63HIOHP7DDQWDP3FXX42L5ENVE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 10:53 PM Shreyan Avigyan
 wrote:
>
> I've already given one. Since Python is dynamically typed changing a critical 
> variable can cause huge instability. Want a demonstration? Here we go,
>
> import sys
> sys.stdout = None
>
> Now what? Now how can we print anything? Isn't this a bug? There are lots of 
> code out there where we need to protect things from being overwritten. Though 
> I'm never telling to use constants in Python stdlib or else I could have 
> never done this demonstration. :)
>

A bug? Python did exactly what it should (with the possible exception,
pun intended, that there could be an issue with None not being
writable). That module attribute exists specifically to be
overwritten. Are you saying that this should be a constant? This isn't
"instability". This is the interpreter doing exactly what you told it
to.

Plus - this wouldn't even apply to the proposal as given, which
doesn't affect module assignment, only assignment to globals.

If this is the best justification you can give, I don't think this
proposal is very strong.

ChrisA
___
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/ZTHNQH227I3PXB6HZCUGJJLCEIAJG5QF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
I've already given one. Since Python is dynamically typed changing a critical 
variable can cause huge instability. Want a demonstration? Here we go,

import sys
sys.stdout = None

Now what? Now how can we print anything? Isn't this a bug? There are lots of 
code out there where we need to protect things from being overwritten. Though 
I'm never telling to use constants in Python stdlib or else I could have never 
done this demonstration. :)
___
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/VIDMLLVPQBHCNJSM5ZYXRWH5EEOLNKYS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Stestagg
On Wed, May 26, 2021 at 1:38 PM Shreyan Avigyan 
wrote:

> Reply to Stestagg:
>
> That's annotation to make sure no one uses a name.


No.


> This is a proposal to implement constant name binding in Python.


Here are some excerpts from pep 591, specifically, how are they different
from what you are proposing?

[typing.Final purpose] "Declaring that a variable or attribute should not
be reassigned"

and

"

The two main rules for defining a final name are:

   - There can be *at most one* final declaration per module or class for a
   given attribute. There can't be separate class-level and instance-level
   constants with the same name.
   - There must be *exactly one* assignment to a final name.

"

and

[typing.Final is useful in...]"Allowing a name to be used in situations
where ordinarily a literal is expected (for example as a field name for
NamedTuple, a tuple of types passed to isinstance, or an argument to a
function with arguments of Literal type [3]
)."



> There are many applications of constants.
>

However many there may be, the cases discussed here all fall under this
definition



> ___
> 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/DDDMEDIXHMYLTZP7TJHWC5ECDJRF4CWU/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/CHCBATNCDZJ3QYS53I572XYS7U3PIQ4K/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 10:37 PM Shreyan Avigyan
 wrote:
>
> Reply to Stestagg:
>
> That's annotation to make sure no one uses a name. This is a proposal to 
> implement constant name binding in Python. There are many applications of 
> constants.
>

Yes, and you've given us zero of them. Can you show us how constants
would be beneficial as part of the language, where ALL_CAPS_NAMES and
typing.Final would not be beneficial?

ChrisA
___
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/QDO2U3OG2L6EGDUXOPHFP6UZCG3IFAE5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 10:31 PM Shreyan Avigyan
 wrote:
>
> Reply to Paul Moore:
>
> if some_condition:
> constant a = 1
> else:
> a = 2
> a = 3
>
> Yes this is allowed. This is runtime.
>
> for i in range(10):
> constant a = []
>
> Not sure. Though it's preferable to be runtime. Preferable is "not allowed".
>
> And lists are also literals. Any Python Object that is not assigned to a 
> variable is a literal. Python claims that itself. A preview -
>
> [10] = [2]
> SyntaxError: Can't assign to literal here.

The literal that you can't assign to here is "10". You're perfectly
allowed to assign to a list display:

[x, y, z] = range(3)

> Constants should have a similar error -
>
> constant x = 10
> x = [2]
> SomeErrorType: Can't assign to constant here.

Is it a syntax error? Be VERY specific here. It makes a huge difference.

Also, what about this:

constant x = 10
def f():
x = 20

SyntaxError? Runtime error? Shadowing?

This is important and cannot be brushed aside.

ChrisA
___
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/GN7X4QEFVZQUUUYCTJCRWD5IKX27RO6E/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Stestagg:

That's annotation to make sure no one uses a name. This is a proposal to 
implement constant name binding in Python. There are many applications of 
constants.
___
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/DDDMEDIXHMYLTZP7TJHWC5ECDJRF4CWU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Paul Moore:

if some_condition:
constant a = 1
else:
a = 2
a = 3

Yes this is allowed. This is runtime.

for i in range(10):
constant a = []

Not sure. Though it's preferable to be runtime. Preferable is "not allowed".

And lists are also literals. Any Python Object that is not assigned to a 
variable is a literal. Python claims that itself. A preview -

[10] = [2]
SyntaxError: Can't assign to literal here.

Constants should have a similar error -

constant x = 10
x = [2]
SomeErrorType: Can't assign to constant here.
___
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/4SOB5SQWPQVLSHLDNBZXO46Z2D7RUAGE/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Stestagg
On Wed, May 26, 2021 at 1:10 PM Shreyan Avigyan 
wrote:

> Reply to Paul Moore:
>
> In Python terms, a constant is a name that binds itself to a value in
> memory and that name cannot bind itself to a different value now (unlike
> variables). The value can be mutated (if mutable) but the name cannot bind
> to a different value once it has bind itself to a value.
>

Given Python already has a method for annotating a variable (name binding)
as 'constant', by using typing.Final,  I don't see any need for an
alternative syntax for this.

Wouldn't it be simpler to just propose making the compiler/runtime enforce
typing.Final annotations at compile and/or run-time?

PEP 591 has all of the definitions and explanation pre-written for you, so
that would avoid all the terminology wrangling too ;)



> ___
> 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/CVMLMQIQMKPKNGF2LKRYGRW4UO2CL2X4/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
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/7ZSPZ7CT7MD5XNK7DXEPMH3GJILTBA25/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Paul Moore
On Wed, 26 May 2021 at 12:59, Shreyan Avigyan  wrote:
> 4. constant pi = 3.14
> # later
> pi = 3.1415 # Error

Steven's already asked what error, and is it compile time or runtime. I'll add

foo.py:

constant x = 12

bar.py

import foo
foo.x = 19

You can only detect this at runtime.

baz.py

import foo
name = 'x'
setattr(foo, name, 22)

You can only detect this at runtime.

Also,

if some_condition:
constant a = 1
else:
a = 2
a = 3

Is this allowed? Is a constant?

What about

for i in range(10):
constant a = []

Is this allowed, or is it 10 rebindings of a?

for i in range(10):
constant a = [i]

What about this? What is a "literal" anyway? You've used lists in
examples (when discussing mutability) but list displays aren't
actually literals.

Lots of questions. I'm sure it's possible to answer them. But as the
proposer, *you* need to give the answers (or at least give a complete
and precise enough specification that people can deduce the answers).
At the moment, everyone is just guessing.

Paul
___
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/GJ6XAJMGXLWUYORFCFSADT2EBRORXFOI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Paul Moore:

In Python terms, a constant is a name that binds itself to a value in memory 
and that name cannot bind itself to a different value now (unlike variables). 
The value can be mutated (if mutable) but the name cannot bind to a different 
value once it has bind itself to a value.
___
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/CVMLMQIQMKPKNGF2LKRYGRW4UO2CL2X4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Paul Moore
On Wed, 26 May 2021 at 12:55, Shreyan Avigyan  wrote:
>
> > What's a const *ptr and a const *ptr const?
>
> In C, a const pointer means a pointer that can only point to one value while 
> const pointer const means a pointer that can only point to one constant value.

Python has names that bind to values. They are *not* equivalent to
pointers that point to variables. So I suspect that the communication
problem here is that you aren't thinking of what you're trying to
propose in Python terms, hence everyone else (who is!) is
misunderstanding you.

You need to make sure that you properly understand Python's name
binding mechanisms before proposing to change them... (Maybe you do,
in which case can you please express your ideas in terms of those
mechanisms, not in terms of C).

Paul
___
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/XMQR3BXRB5VBZIJZ5IKX2CFYJNTVD2A6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Richard Damon
On 5/26/21 7:40 AM, Steven D'Aprano wrote:
> On Wed, May 26, 2021 at 11:26:17AM -, Shreyan Avigyan wrote:
>> Reply to Richard Damon:
>>
>> The values can be changed. It can be mutated (if mutable). This idea 
>> suggests we can't reassign anything to the name. Suppose,
>>
>> constant x = ["List"]
>> x.append("something") # OK
>>
>> x = [] # Error

So we only have to check at runtime if name has been marked constant to
handle cases like:


if flag:

    constant foo = ["List"]

else:

    foo = ["Other"]


or

import mymodule

constant mymodule.foo = ["List"]

or are you going to restrict how constants are created?

>
> At last, a straight answer to the question of what this does. Thank you. 
> Your answer here crossed with my previous post.
>
> In the future, can you please try to use standard Python terminology 
> instead of ambiguous language?
>
> "The values can be changed" is ambiguous. That can mean mutating an 
> object:
>
> x.append(None)  # mutation changes the value of x
>
> and it can mean rebinding:
>
> x = None  # rebinding changes the value of x
>
>
> So now tell us, what sort of error do you get? Is it a compile-time 
> error or a run-time error?
>
>> Think of it as a const *ptr. Don't think of it as const *ptr const.
> What's a const *ptr and a const *ptr const?

He is assuming that people are familiar with C.

-- 
Richard Damon

___
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/ZACDDCGGNJ32KD3FTAEEFXR5727CZ2AK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
> What's a const *ptr and a const *ptr const?

In C, a const pointer means a pointer that can only point to one value while 
const pointer const means a pointer that can only point to one constant value.
___
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/M22PBZ4ODALXOXBGGG5HHN2UARX44E6I/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Steven -

Sorry for creating confusions. 

1. Leave debugging. As I said that's not a good argument for the existence of  
constants.

2. "Constants doesn't mean we can't reassign the name to a different value." 
was differently intended. I was trying to say that we should *treat* it like a 
*literal*. I never said constant will be a type of variable. I was a little bit 
unclear in that message.

3. Constant will be constant name binding. Value can be mutated (if mutable) 
but the name cannot be reassigned.

4. constant pi = 3.14
# later
pi = 3.1415 # Error
___
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/N3OEMQVQ5EZSNW4ZG223RMPP4VATF3F6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 01:33:07PM +0200, Stéfane Fermigier wrote:

> > I think that's a minor win in that you don't have to repeat the 
> > variable name.
> 
> 
> Repetition is not the main issue, in my own experience. The main issue is
> the risk of making a typo in the variable's name when passing it as a
> string (it happens to me all the time, specially when copy-pasting code and
> forgetting to change the variable's name in every place).

Right, that's the problem with having to repeat the name. The issue is 
minor when you only have to do it once or twice, especially if the name 
is only informative rather than functional:

Spam = namedtuple('Spam', *fieldnames)

Eggs = namedtuple('Egs', *otherfields)  # Oops

The second line, with it's typo, doesn't really matter. The class name 
is just informative, it's not functional.

But in your framework examples, it does matter:

personal_name = permissions('personnal_name', ...)  # Oops
family_name = permissions('family_name', ...)
address = permissions('family_name', ...)  # copy-paste error
# and many more examples

The repetition is an opportunity to slip in functional bugs, not just 
trivial typos.


> Last point that I like in the decorator syntax: it's
> 
> I can compose N different decorators and keep the intent obvious:
> 
> @acl(READ, WRITE)
> @constraint(10 < _ < 100)
> @not_null
> @indexed
> @depends_on(whatever)
> @inject
> @...
> first_name: str

Hmm, that's a good point.

On the other hand, it would be terribly confusing if the same syntax:

@decorate

had radically different meaning depending on whether it was followed by 
a class/function or a bare name.


-- 
Steve
___
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/5UX2JGDHPGXD4NKKCVHZ55ZSELN63WQD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 11:26:17AM -, Shreyan Avigyan wrote:
> Reply to Richard Damon:
> 
> The values can be changed. It can be mutated (if mutable). This idea suggests 
> we can't reassign anything to the name. Suppose,
> 
> constant x = ["List"]
> x.append("something") # OK
> 
> x = [] # Error


At last, a straight answer to the question of what this does. Thank you. 
Your answer here crossed with my previous post.

In the future, can you please try to use standard Python terminology 
instead of ambiguous language?

"The values can be changed" is ambiguous. That can mean mutating an 
object:

x.append(None)  # mutation changes the value of x

and it can mean rebinding:

x = None  # rebinding changes the value of x


So now tell us, what sort of error do you get? Is it a compile-time 
error or a run-time error?

> Think of it as a const *ptr. Don't think of it as const *ptr const.

What's a const *ptr and a const *ptr const?



-- 
Steve
___
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/LGIC5RTRWBCQWH2YE4LO4G6NXKSVLOFT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
Shreyan, you have probably spent hundreds, maybe thousands of words to 
avoid giving straightforward, direct, explicit answers to the questions, 
preferring to force us to guess what you mean from vague analogies.

Please stop. Please give an explicit description of the functional 
requirements of this proposed feature. Give code samples showing the 
exact behaviour. Stop expecting us to guess what you mean when your 
statements contradict themselves.

what happens when I try to rebind a constant?

constant pi = 3.14
# later
pi = 3.1415

For the record, this is not a rhetorical question. I do not know the 
answer, I have asked at least twice before what happens when we rebind a 
constant, *and you won't tell me*.


On Wed, May 26, 2021 at 09:55:41AM -, Shreyan Avigyan wrote:

> Literals mean 10 or 20. Can you assign something to literal? No.

Constants aren't literals, they are names. `10` is a literal, but `pi` 
is a constant. Can you assign to a name? Yes, otherwise we can't give 
the constant a value in the first place.  Can you rebind that name? You 
have said yes. You wrote:

"Constants doesn't mean we can't reassign the name to a different value."

https://mail.python.org/archives/list/python-ideas@python.org/message/NTDZ4EZGKCWRK7FX7WGKF3MOWQUIRT3U/

Actually, I think most people think that being a constant *does* mean 
that you can't reassign the name to a different value. Otherwise its not 
a constant, its just a variable.

But in the same post I linked to above you explicitly ruled out classic 
constants like found in C and Java (and Pascal, and other languages). So 
now I have *no idea* what your constants are, since apparently they 
behave exactly like variables: they are names that refer to values, and 
you can rebind them to new values.


> But 
> you can assign something to a variable to point to another value. 
> That's why I said constants should behave like literals. Point is 
> constants are names bind to a value. We can change the value but not 
> the name to point to a different value.

What do you mean by "change the value"? Are you talking about mutable 
objects?

Earlier you said that we can change the name to point to a different 
value, now you say that we can't.



> Simply think "const type *pointer" not "type *pointer const".

That means nothing to me. This is a proposal for a feature in Python, 
please describe it in terms of existing Python behaviour, not whatever 
language that is.


> And by debugging I meant it would immediately be detectable if someone 
> tries to change the constant or not. (Not a good argument in 
> constant's favor though)

How would it be detectable? Please stop expecting us to guess what will 
happen. **Tell us what will happen.**

It shouldn't be this hard to get information out of somebody proposing a 
new language feature :-(


-- 
Steve
___
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/FUDZVTOL4XFUFNHLQUSYND65SUG2D4RH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 9:20 PM Richard Damon  wrote:
>
> On 5/26/21 5:55 AM, Shreyan Avigyan wrote:
> > Reply to Steven -
> >
> > Literals mean 10 or 20. Can you assign something to literal? No. But you 
> > can assign something to a variable to point to another value. That's why I 
> > said constants should behave like literals. Point is constants are names 
> > bind to a value. We can change the value but not the name to point to a 
> > different value. Simply think "const type *pointer" not "type *pointer 
> > const".
> >
> > And by debugging I meant it would immediately be detectable if someone 
> > tries to change the constant or not. (Not a good argument in constant's 
> > favor though)
>
> I think the biggest problem is that basically, by definition, to
> actually enforce this requires a attribute lookup on EVERY rebinding or
> mutating operation.
>
> One stated goal was that
>
> constant mylist = [1, 2, 3]
>
> was to generate an error if you do
>
> mylist.append(4)
>
> but that also means we need to catch
>
> yourlist = mylist
>
> yourlist.append(4)
>
> and since that binding could happen on a cross module function call,
> every mutating operation needs a run-time check to see if this object
> has been bound to a constant.
>

That's basically going to be impossible, especially since the object
could reference OTHER objects which could change, too. Plus, it should
be perfectly valid to say mylist.index(4) even if you can't do
mylist.append(4), so you can't just guard against method calls.

Enforcing immutability externally is basically impossible. Don't even
bother trying.

A more viable proposal might be "this name represents this literal",
and should always be interpreted identically to that literal. So if
you have that constant declaration, then every use of mylist is
exactly equivalent to writing [1, 2, 3] at that exact point in the
code (constructing a new list every time). That'd be well-defined and
plausibly behaved, while still strongly recommending that immutables
be used (since the compiler can constant-fold
ints/floats/tuples/strings). The value would be that if you *edit* the
constant (not rebind it, actually edit the source code), it would
change in all places. I don't think it's of great value and I'm not
recommending it, but it would at least be a sane and plausible
proposal, without logical contradictions.

ChrisA
___
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/X7Z2QIWIXCDDUHKMZSTORO7RDRGDPTKJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Stéfane Fermigier
On Wed, May 26, 2021 at 12:13 PM Steven D'Aprano 
wrote:

> On Wed, May 26, 2021 at 08:58:51AM +0200, Stéfane Fermigier wrote:
>
> > For the use cases I have in mind, some kind of context information would
> > need to be passed too, like:
> >
> > class Customer:
> >
> > @permissions({"read": USER, "write": MANAGER})
> > first_name: str
> >
> > the function primary_key should be called with the class being
> constructed
> > for it to make sense.
>
> What function primary_key? Never mind, it probably doesn't matter.
>

Sorry, I re-wrote my example after a first draft. In this example
"primary_key" should be "permissions".

I think that's a minor win in that you don't have to repeat the variable
> name.


Repetition is not the main issue, in my own experience. The main issue is
the risk of making a typo in the variable's name when passing it as a
string (it happens to me all the time, specially when copy-pasting code and
forgetting to change the variable's name in every place).


> > 1) Set metadata directly on some magical attribute:
> >
> > class Customer:
> > __permissions__ = {
> > 'first_name': { READ: ..., WRITE: ... }
> > }
> >
> > first_name: str
> >
> > cons: risk of mispelling or forgetting some attributes; lack of locality;
> > how do we deal with inheritance ?
>
> The inheritance question applies equally to the decorator version.
>

What I meant is that if you set up the metadata registry by yourself, that
won't be enough to deal with inheritance.

If the decorator takes care of it, it can probably be made smart enough to
massage the provided metadata into the information needed at runtime.

But I agree that's mostly irrelevant for the discussion at hand.


> > class Customer:
> > first_name: str
> >
> > @acl({"read": USER, "write": MANAGER})
> > def meta_first_name(self): pass
> >
> > I.e. use a method decorator on a dummy function named similarly to the
> > variable (e.g. by prepending some magical prefix).
>
> Good lord. All that trouble to avoid typing the name of the variable as
> a function argument, and then you still end up typing it in the dummy
> function name :-(
>
>  first_name = acl('first_name', {"read": USER, "write": MANAGER})
>
> is *much* clearer and simpler than any of the hacks you have shown,
> especially the one with the dummy method. Seriously, you end up typing
> an extra 21 characters plus newlines and indents to avoid typing
> 'first_name' as a function argument. That's just sad.
>

Well that was just a straw man just to convey what I'd like to achieve,
i.e. a variable decorator should be, mostly equivalent to this
semantically. I've never implemented this idea.

Thank you for your examples. They suggest to me that:
> [...]



> - Decorators are a hammer, and some people think that every problem
>   is a nail.
>

Actually there is a bit more to it. If we go back to the name, "decorators"
are supposed to "decorate" things (i.e. add metadata). That's what they do,
and nothing more, in Java, for instance. (I know that in Python they do
more.) Now I want to add metadata to some variables, that's quite logical
that I would want to use some kind of "decorator" for that.

Another thing is that there are decorators for classes, methods, functions.
My humble opinion is that they would be also useful for class variables
(and probably for other variables too).

Last point that I like in the decorator syntax: it's

I can compose N different decorators and keep the intent obvious:

@acl(READ, WRITE)
@constraint(10 < _ < 100)
@not_null
@indexed
@depends_on(whatever)
@inject
@...
first_name: str

(Yes, it can become a bit heavy after some point, but imagine that all
these metadata are mandated by the business domain, what would be the
alternative syntaxes or approaches ?).

- There is good case for having a feature that gives the right-hand
>   side of assignment statements access to the assignment targets as
>   strings.
>

Yep.


> - But I still don't think that decorator syntax is the right solution.
>

Not usually fond of adding new stuff to the language, but as I wrote, this
is something that I was ready to argue about 8 years ago, I never did
because I was in a hurry delivering the features needed for my
customers, but I'm still fond of the idea of moving in this direction.

  S.

-- 
Stefane Fermigier - http://fermigier.com/ - http://twitter.com/sfermigier -
http://linkedin.com/in/sfermigier
Founder & CEO, Abilian - Enterprise Social Software -
http://www.abilian.com/
Chairman, National Council for Free & Open Source Software (CNLL) -
http://cnll.fr/
Founder & Organiser, PyParis & PyData Paris - http://pyparis.org/ &
http://pydata.fr/
___
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 

[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Richard Damon:

The values can be changed. It can be mutated (if mutable). This idea suggests 
we can't reassign anything to the name. Suppose,

constant x = ["List"]
x.append("something") # OK

x = [] # Error

Think of it as a const *ptr. Don't think of it as const *ptr const.
___
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/IGGDFIPNS3IQ5HRHMQGRGI6V7BB2VBXX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Richard Damon
On 5/26/21 5:55 AM, Shreyan Avigyan wrote:
> Reply to Steven -
>
> Literals mean 10 or 20. Can you assign something to literal? No. But you can 
> assign something to a variable to point to another value. That's why I said 
> constants should behave like literals. Point is constants are names bind to a 
> value. We can change the value but not the name to point to a different 
> value. Simply think "const type *pointer" not "type *pointer const".
>
> And by debugging I meant it would immediately be detectable if someone tries 
> to change the constant or not. (Not a good argument in constant's favor 
> though)

I think the biggest problem is that basically, by definition, to
actually enforce this requires a attribute lookup on EVERY rebinding or
mutating operation.

One stated goal was that

constant mylist = [1, 2, 3]

was to generate an error if you do

mylist.append(4)

but that also means we need to catch

yourlist = mylist

yourlist.append(4)

and since that binding could happen on a cross module function call,
every mutating operation needs a run-time check to see if this object
has been bound to a constant.

We also need to test everytime we bind/rebind a name, as the creation of
that constant binding might be hidden behind mechanisms that we can't
determine at compile time. Things like can another module inject a
constant into our module? If so, we need to check every name binding to
see if that name has been made a constant.

This can add up to a noticable run time cost.

Using the alternative of type hints says that the checker can warn us of
many of the violations, and you have the OPTION of turning on run time
checking if you think you have a problem (or you can just choose to
always turn it on and pay the cost).

-- 
Richard Damon

___
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/RSFAX56IETA4UZ7WOQGOFEHZZ6SRQWOZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 8:44 PM Steven D'Aprano  wrote:
>
> On Tue, May 25, 2021 at 10:10:12PM +1000, Chris Angelico wrote:
> > On Tue, May 25, 2021 at 5:29 PM Steven D'Aprano  wrote:
> > > Here's a counter-proposal: we have a special symbol which is transformed
> > > at compile-time to the left hand assignment target as a string. Let's
> > > say we make that special expression `@@` or the googly-eyes symbol.
>
> [...]
> > > Targets aren't limited to a single bare name.
> > >
> > > spam.eggs = @@
> > > # spam.eggs = 'spam.eggs'
> > >
> > > mylist[2] = @@
> > > # mylist[2] = 'mylist[2]'
> >
> > What about:
> >
> > mylist[ 2 ] = @@
> >
> > ? I'm inclined to say that the assignment target is reconstructed from
> > the AST, in order to make it consistent (so this would also assign the
> > string 'mylist[2]'). But, again, bikesheddable.
>
> Let the implementation decide whether it is easier to get the target
> from the source code or the AST. I don't care either way.

Fair enough. This sort of thing would need to be settled before a PEP
could be accepted, but by then, there'll want to be a reference
implementation.

> > > Chained assignments transform to a tuple of target names:
> > >
> > >spam = eggs = cheese = func(arg, @@)
> > ># spam = eggs = cheese = func(arg, ('spam', 'eggs', 'cheese'))
> >
> > Hmm. Everything else gives you a single string, this one doesn't. I'd
> > actually be inclined to switch around this one and the next one...
>
> A complication I just thought of is that you can have chained assignment
> within a
> sequence unpacking assignment:
>
> spam, eggs, aardvark = foo = bar, hovercraft = 'abcd'
>
> and the other way around:
>
> spam = eggs = (aardvark, foo, bar) = hovercraft = 'abc'
>
> That's going to make things tricky.

Very very good point. Ouch.

It'd probably be safest to define it to always be a single string, and
then have a fully-nestable and recursive system. So instead of simply
separating with comma or equals or whatever, it might be best to group
AND separate.

spam, eggs = "@@" # "[spam,eggs]"
spam = eggs = "@@" # "{spam,eggs}"
(spam, eggs) = (foo, bar) = "@@" # "{[spam,eggs],[foo,bar]}"

> > Questions:
> >
> > 1) Is this restricted to the "=" assignment operator, or will other
> > operators trigger this too?
> > x += f(@@) # ?
> > if x := f(@@): # ?
>
> I hadn't thought that far ahead. I did think that we ought to exclude
> the walrus operator because it would be ambiguous:
>
> spam = eggs * (cheese:=foo+bar(@@))
>
> Does @@ get the value 'cheese' or 'spam'? If we require an assignment
> statement, then it can only be 'spam' and the ambiguity is gone.

Yeah, I'd agree about :=. Less clear about +=, but as with some of the
others, it may be best to (a) leave it restricted with room for
expansion, and/or (b) let a reference implementation guide the
decision.

> > 2) What about other forms of assignment?
> > for spam in foo(@@): # ?
>
> YAGNI.

Absolutely agree, especially because of this case:

spam = [ord(x) for x in @@]

If for loops on their own don't define an @@ target, then for loops
inside comprehensions won't either, and this wouldn't be ambiguous.

> > 3) Is this a string literal, or a magic token that happens to evaluate
> > as a string?
>
> An actual string.

Either way, it would be a string. The difference is that string
literals can be placed adjacent to each other:

>>> "{1}" f' - {1+2=} - ' '{2}'
'{1} - 1+2=3 - {2}'

Which goes to show, btw, that an f-string is still a literal, even
though it's not a constant.

> > x = @@ ".json" # Legal if @@ is a string literal
>
> Heh, I wouldn't necessarily require that. (Nor would I object to it.)
> Implicit string concatenation is a nice feature, but I'm not sure we
> want to extend it. Its not hard to slot an explicit `+` in there.
>

True. Probably another thing best guided by the reference implementation.

I think all these open questions are minor details, but the core
proposal is strong enough to handle the uncertainty.

Might be worth starting a dedicated thread for it.

ChrisA
___
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/Z75ULT7M22PCCBLJLYR73PZEJBS7F4PI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 08:10:17PM +1000, Steven D'Aprano wrote:

> - Decorators are a hammer, and some people think that every problem
>   is a nail.

Sorry, on re-reading that statement, it comes across as less gracious 
than I intended.

So let me explicitly thank Jeremiah for raising this issue, hammer or 
not :-)


-- 
Steve
___
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/C2WVK623GAHJ5P2PISGOU26I6OK4XDHD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Steven D'Aprano
On Tue, May 25, 2021 at 10:10:12PM +1000, Chris Angelico wrote:
> On Tue, May 25, 2021 at 5:29 PM Steven D'Aprano  wrote:
> > Here's a counter-proposal: we have a special symbol which is transformed
> > at compile-time to the left hand assignment target as a string. Let's
> > say we make that special expression `@@` or the googly-eyes symbol.

[...]
> > Targets aren't limited to a single bare name.
> >
> > spam.eggs = @@
> > # spam.eggs = 'spam.eggs'
> >
> > mylist[2] = @@
> > # mylist[2] = 'mylist[2]'
> 
> What about:
> 
> mylist[ 2 ] = @@
> 
> ? I'm inclined to say that the assignment target is reconstructed from
> the AST, in order to make it consistent (so this would also assign the
> string 'mylist[2]'). But, again, bikesheddable.

Let the implementation decide whether it is easier to get the target 
from the source code or the AST. I don't care either way.


> > If the key or index is not known at compile-time, it is a syntax error:
> >
> > mylist[getindex()] = @@  # SyntaxError
> 
> Also bikesheddable; I'd actually say that this should assign the
> string 'mylist[getindex()]', regardless of the value returned by
> getindex.

My reasoning it that it is safer and more conservative to start with a 
restriction and relax it later, than to start with a less restrictive 
version and regret it.

But I could be persuaded otherwise :-)


> > Chained assignments transform to a tuple of target names:
> >
> >spam = eggs = cheese = func(arg, @@)
> ># spam = eggs = cheese = func(arg, ('spam', 'eggs', 'cheese'))
> 
> Hmm. Everything else gives you a single string, this one doesn't. I'd
> actually be inclined to switch around this one and the next one...

A complication I just thought of is that you can have chained assignment 
within a 
sequence unpacking assignment:

spam, eggs, aardvark = foo = bar, hovercraft = 'abcd'

and the other way around:

spam = eggs = (aardvark, foo, bar) = hovercraft = 'abc'

That's going to make things tricky.


> > Sequence unpacking assignment gets transformed as a single
> > comma-seperated string:
> >
> > spam.eggs, foo, *bar = func(arg, @@)
> > # spam.eggs, foo, *bar = func(arg, ('spam.eggs,foo,*bar'))
> 
> ... so that assigning the same thing to multiple names gives you a
> space-separated string (or equals-separated, "spam=eggs=cheese"), but
> unpacking gives you a tuple of targets, since it then nicely parallels
> the result it's expecting from the function. That would mean that:
> 
> # This assigns a single string to them all eg "spam eggs cheese"
> spam = eggs = cheese = @@
> # This assigns a string to each one:
> spam, eggs, cheese = @@
> # and is equivalent to:
> spam = @@; eggs = @@; cheese = @@

I have to think about that some more :-)


> This has the same sort of value as the C preprocessor stringification
> operator. It's incredibly handy in making self-referential statements.

Nice analogy.

> Python has places where that happens by magic (class and function
> definitions), but if you want to create your own function that gets
> the same benefit well there's __set_name__ if your thing gets
> put into a class, but otherwise you have to repeat the name.

Yes.

> Questions:
> 
> 1) Is this restricted to the "=" assignment operator, or will other
> operators trigger this too?
> x += f(@@) # ?
> if x := f(@@): # ?

I hadn't thought that far ahead. I did think that we ought to exclude 
the walrus operator because it would be ambiguous:

spam = eggs * (cheese:=foo+bar(@@))

Does @@ get the value 'cheese' or 'spam'? If we require an assignment 
statement, then it can only be 'spam' and the ambiguity is gone.


> 2) What about other forms of assignment?
> for spam in foo(@@): # ?

YAGNI.

We can always extend the functionality later. Let's keep it simple: it 
works for assignment statements, not every binding operation.


> 3) Is this a string literal, or a magic token that happens to evaluate
> as a string?

An actual string.


> x = @@ ".json" # Legal if @@ is a string literal

Heh, I wouldn't necessarily require that. (Nor would I object to it.) 
Implicit string concatenation is a nice feature, but I'm not sure we 
want to extend it. Its not hard to slot an explicit `+` in there.



-- 
Steve
___
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/73K5XH66TWPI4KTKYJPE2IHQXE3RUCFL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 08:58:51AM +0200, Stéfane Fermigier wrote:

> For the use cases I have in mind, some kind of context information would
> need to be passed too, like:
> 
> class Customer:
> 
> @permissions({"read": USER, "write": MANAGER})
> first_name: str
> 
> the function primary_key should be called with the class being constructed
> for it to make sense.

What function primary_key? Never mind, it probably doesn't matter.

According to this proposal, that example would be illegal. You have a 
decorator with no variable. You could write this instead:

 @permissions({"read": USER, "write": MANAGER}) first_name: str

which would be transformed to:

first_name:str = permissions('first_name', {"read": USER, "write": MANAGER})

I think that's a minor win in that you don't have to repeat the variable 
name. Using my counter-proposal for a googly-eyes symbol:

first_name:str = permissions(@@, {"read": USER, "write": MANAGER})

I think that's better as it is explicit that an assignment is happening.


> Here are some alternatives:
> 
> 1) Set metadata directly on some magical attribute:
> 
> class Customer:
> __permissions__ = {
> 'first_name': { READ: ..., WRITE: ... }
> }
> 
> first_name: str
> 
> cons: risk of mispelling or forgetting some attributes; lack of locality;
> how do we deal with inheritance ?

The inheritance question applies equally to the decorator version.


[...]
> class Customer:
> first_name: str
> 
> @acl({"read": USER, "write": MANAGER})
> def meta_first_name(self): pass
> 
> I.e. use a method decorator on a dummy function named similarly to the
> variable (e.g. by prepending some magical prefix).

Good lord. All that trouble to avoid typing the name of the variable as 
a function argument, and then you still end up typing it in the dummy 
function name :-(

 first_name = acl('first_name', {"read": USER, "write": MANAGER})

is *much* clearer and simpler than any of the hacks you have shown, 
especially the one with the dummy method. Seriously, you end up typing 
an extra 21 characters plus newlines and indents to avoid typing 
'first_name' as a function argument. That's just sad.

Thank you for your examples. They suggest to me that:

- There are more uses for knowing the assignment target than I
  expected.

- Frameworks go through a huge amount of (unnecessary?) work to avoid 
  writing the name of a varible -- and then end up writing it anyway.

- Decorators are a hammer, and some people think that every problem
  is a nail.

- There is good case for having a feature that gives the right-hand
  side of assignment statements access to the assignment targets as
  strings.

- But I still don't think that decorator syntax is the right solution.


-- 
Steve
___
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/3ZTRIU3BW4TCJTYZASQFQXJMWMMULLJ3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Steven -

Literals mean 10 or 20. Can you assign something to literal? No. But you can 
assign something to a variable to point to another value. That's why I said 
constants should behave like literals. Point is constants are names bind to a 
value. We can change the value but not the name to point to a different value. 
Simply think "const type *pointer" not "type *pointer const".

And by debugging I meant it would immediately be detectable if someone tries to 
change the constant or not. (Not a good argument in constant's favor though)
___
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/35ZKTEAQEUHJEXC7YZJSSG5FUWXAM2T5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 07:39:54AM -, Shreyan Avigyan wrote:
> Chris wrote:
> > There are many arguments in favour of constants, but this one strikes
> > me as particularly weak.
> 
> That's not exactly how I meant it. I was telling that while constant 
> should be there it should not be used as "Use constants everywhere". I 
> actually believe the main reason for constants should "Debugging".

I know how to use each of these things for debugging:

- print
- the interactive interpreter
- the Python debugger pdb
- the logging module

I have no idea how you think we can use `constant` for debugging.


-- 
Steve
___
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/FFR7GHTKKCELGOAOQK7IAXZ7OAXVO3KL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 07:14:41AM -, Shreyan Avigyan wrote:
> Reply to Steven D'Aprano:
> 
> > But you've said that you want constants to be capable of being rebound 
> > to a new value. So your constants are identical to variables.
> 
> No, not at all. Actually to be clear, constants are supposed to behave 
> like literals but in implementation they are nothing more than names 
> that are bind to a value.

I don't know how you think literals behave and you haven't told us!

"Nothing more" than a name bound to a value is a variable. Why do you 
call it a constant if it is nothing more than a variable?


-- 
Steve
___
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/4UXYDVE4LV3F4ZNUTN7B5LNLYEZ52TDZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Steven D'Aprano
On Wed, May 26, 2021 at 07:25:09AM -, Shreyan Avigyan wrote:

> 2) Class member constants - Constants should be used only for avoiding 
> from being overridden.

But you said that constants can be overriden and the name rebound.

Is your proposal only to add a keyword "constant" that does absolutely 
nothing? If that is not your proposal, please explain what you want the 
keyword to do. So far you have just confused me, and I don't think I'm 
the only one.

You have said that constants can be rebound to new values, but then you 
say they are used to stop them from being overridden.

You said that constants act just like literals, but you won't tell us 
how literals act.

Let me see if I can get some clarity:

If I define a constant:

constant pi = 3.14

what happens when I try to rebind it later?

# later
pi = 3.1415



> Sometimes if someone changes a critical value especially 
> in Python a dynamically typed language it can have bad effects. 
> Suppose we have a Windows and we go to registry editor and delete keys 
> and set different values and then Windows won't boot up the next time. 
> That's why class member constants is necessary. 

The Windows registry isn't a class. The Windows registry doesn't prevent 
you from changing values or deleting keys.

If the keys and values in the registry were constant, then you couldn't 
control the behaviour of Windows, or install new applications, drivers, 
printers, hardware, etc. So I don't think the registry is a good 
example.


-- 
Steve
___
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/PTSOKIP4NDQYVUQT5DHYZJBREEGKETRB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Chris wrote:
> There are many arguments in favour of constants, but this one strikes
> me as particularly weak.

That's not exactly how I meant it. I was telling that while constant should be 
there it should not be used as "Use constants everywhere". I actually believe 
the main reason for constants should "Debugging". Our program can become 
unstable if something really important changes. And yeah sometimes stopping 
people from doing dangerous things is a good idea and sometimes not.
___
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/WBTQCTBI5YDFD3LMBITLWTFOUXGBNBPH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 5:26 PM Shreyan Avigyan
 wrote:
>
> Reply to Chris:
>
> There are two things I want to say about constants :-
> 1) Global-Local Constants - The ALL_CAPS convention variables should become 
> constant.
> 2) Class member constants - Constants should be used only for avoiding from 
> being overridden. It should not be used as "We have a class. Use constants.". 
> Sometimes if someone changes a critical value especially in Python a 
> dynamically typed language it can have bad effects. Suppose we have a Windows 
> and we go to registry editor and delete keys and set different values and 
> then Windows won't boot up the next time. That's why class member constants 
> is necessary.
>

I don't understand this mentality. Firstly, Windows *does* have a
registry editor. You can indeed break things. Windows won't stop you.
Secondly, CPython comes with the ctypes module that allows you to
*change the values of literals*. I'm not kidding. You can actually
make it so that the integer 42 actually behaves as if it's 28. Do we
really need to stop people from doing things because they're
dangerous?

There are many arguments in favour of constants, but this one strikes
me as particularly weak.

ChrisA
___
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/2RTCGQBLXXT4EIUW34TU35Y2JBI44OOU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Chris:

There are two things I want to say about constants :-
1) Global-Local Constants - The ALL_CAPS convention variables should become 
constant.
2) Class member constants - Constants should be used only for avoiding from 
being overridden. It should not be used as "We have a class. Use constants.". 
Sometimes if someone changes a critical value especially in Python a 
dynamically typed language it can have bad effects. Suppose we have a Windows 
and we go to registry editor and delete keys and set different values and then 
Windows won't boot up the next time. That's why class member constants is 
necessary.
___
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/RX4LMZ3BIALTDBBYJMQBFMQN6MMYIZJW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Shreyan Avigyan
Reply to Steven D'Aprano:

> But you've said that you want constants to be capable of being rebound 
> to a new value. So your constants are identical to variables.

No, not at all. Actually to be clear, constants are supposed to behave like 
literals but in implementation they are nothing more than names that are bind 
to a value.
___
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/PAQVBP6UZKCNOA5WZK43FRQWLYGC5IQH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Decorators on variables

2021-05-26 Thread Stéfane Fermigier
On Tue, May 25, 2021 at 12:14 PM Steven D'Aprano 
wrote:

> On Tue, May 25, 2021 at 10:55:07AM +0200, Stéfane Fermigier wrote:
>
> > I had a similar idea ~8 years ago while working on a RAD (rapid
> application
> > development) framework [*] that had to manage business objects using a
> > variety of frameworks: an ORM (SQLAlchemy), a full-text engine (Whoosh),
> as
> > well as a specifically developed CRUD Web UI framework, permission
> system,
> > audit system, etc.
> >
> > In this context, variable decorators, in addition to type annotations,
> > could bring a whole new level of internal DSL expressivity, including for
> > instance:
>
> Could you explain exactly how this proposed feature would allow us to do
> all the things you say it would allow us to do? It's not clear to me how
> knowing the binding name on the left would allow us to "express data
> access constraints" etc.
>

I was thinking at the framework level, e.g. the decorator would be use to
register some metadata somewhere (either class-level or in a global
registry, say), and the framework would be to check permission against the
current user when accessing the object's field (e.g. at serialisation /
deserialisation time, and/or when rendering templates).

For all the things I have suggested, what I have in mind is just:

1) Register some metadata at decorator execution time
2) The framework uses these metadata when it needs them


> E.g. you say:
>
> > - Annotations to express full-text search indexability (e.g. @indexed)
>
> I don't even know how to begin interpreting how you get there from the
> proposed syntax:
>
> @function(args) name
> # -> `name = function('name', args)`
>

For the use cases I have in mind, some kind of context information would
need to be passed too, like:

class Customer:

@permissions({"read": USER, "write": MANAGER})
first_name: str

the function primary_key should be called with the class being constructed
for it to make sense.

Here are some alternatives:

1) Set metadata directly on some magical attribute:

class Customer:
__permissions__ = {
'first_name': { READ: ..., WRITE: ... }
}

first_name: str

cons: risk of mispelling or forgetting some attributes; lack of locality;
how do we deal with inheritance ?

1bis):

class Customer:
class Meta:
permissions__ = {
'first_name': { READ: ..., WRITE: ... }
}

first_name: str

This is similar to the previous one, so same issues.

2) Dexterity syntax (I'm not a user of Dexterity, so I might be wrong, this
is from:
https://www.stevemcmahon.com/classes/dexterity/dexterity%20class%202013.pdf
):

class Customer:
dexterity.read_permission(
first_name='cmf.ReviewPortalContent'
)
dexterity.write_permission(
first_name='cmf.ReviewPortalContent'
)
first_name: str

con: easy to misspell the field name (hopefully the rest of the issues is
taken care by the framework)

3) One possible idiom to use decorators as I think would be fit, without
changing the language, but at the price of an extra line and some
additional mental burden:

class Customer:
first_name: str

@acl({"read": USER, "write": MANAGER})
def meta_first_name(self): pass

I.e. use a method decorator on a dummy function named similarly to the
variable (e.g. by prepending some magical prefix).

The obvious con is that we still haven't prevented the risk of typo in the
function name.

[...] As I see it, objects should almost never know or care what names
> (note
> plural) they are known by, or even if they are bound to any names at
> all. There are a few exceptions, mostly classes and sympy symbols, but
> I expect that this functionality should be rather niche.
>

For the kind of applications I have been doing over the last 20 years
(enterprise content and information management applications), this is not
niche, this is where 50% of the work goes (i.e. defining object models,
permissions, workflows, forms, validation, etc.).

  S.

-- 
Stefane Fermigier - http://fermigier.com/ - http://twitter.com/sfermigier -
http://linkedin.com/in/sfermigier
Founder & CEO, Abilian - Enterprise Social Software -
http://www.abilian.com/
Chairman, National Council for Free & Open Source Software (CNLL) -
http://cnll.fr/
Founder & Organiser, PyParis & PyData Paris - http://pyparis.org/ &
http://pydata.fr/
___
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/27YQVQTFUA2P6XTMA5ICCPUXOFZSQJQB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Re: Introduce constants in Python (constant name binding)

2021-05-26 Thread Chris Angelico
On Wed, May 26, 2021 at 11:57 AM Steven D'Aprano  wrote:
>
> On Wed, May 26, 2021 at 02:09:58AM +1000, Chris Angelico wrote:
>
> > Remember: The thing that you declare Final will, some day, need to be
> > changed. Probably as part of your own test suite (you do have one of
> > those, right?). With MyPy, you could tell it not to validate that
> > line, or that file. With a naming convention, you can explain the need
> > for the change with a comment. How are you going to override the
> > language feature?
>
> That depends on how it is implemented. Here are some thoughts. Given:
>
> constant spam = "spam and eggs"
>
> we might be able to change it like this:
>
> # Rebinding a constant raises a warning. Just ignore the warning.
> try:
> spam = "spam spam spam spam"
> except Warning:
> pass
>
> # Write directly to the namespace.
> globals()['spam'] = "spam spam spam spam"
>
> # Command line switch or environment variable.
> python3.11 --no-constants testsuite.py
>
> # Context manager.
> with ConstantEnforcement(False):
> spam = "spam spam spam spam"
>
> # Special backdoor.
> sys.setconstant('spam', "spam spam spam spam")
>
>
> Enforcing constantness doesn't necessarily imply there is no way to
> disable or work around it. Especially in a consenting adults language
> like Python, I would expect that there will be.
>
> (Most likely just write directly to the namespace.)
>

And the very presence of such an option means that these things are
not constant, meaning that the interpreter and the programmer cannot
assume they are constant. Especially if there's a way to globally
disable constness. (My guess is that writing directly to the
namespace, or "import some_module; some_module.spam = 42", would
bypass it.)

So how long will it be before some library has a thing declared as a
constant, and some user of that library overrides it in production?

I give it a week, but only because I doubt that const would be heavily
used. If it were, I'd give it a day.

ChrisA
___
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/QTKU3VI5JQT22BLYQC7HWTTWA44Q6QGP/
Code of Conduct: http://python.org/psf/codeofconduct/