On Wed, Dec 02, 2020 at 10:52:30AM +0300, Paul Sokolovsky wrote: [Paul]
# Leads to a warning: replacing (monkey-patching) a constant slot (function) with a variable. mod.func1 = 1
[...]
That example explores the meaning of:
def func1(): pass
func1 = 1
Those two code snippets demonstrate different things. Your original example demonstrates assigning to an module attribute from outside of the module. Your new example demonstrates assigning to a global variable from inside the same module. These call different byte-codes in CPython (STORE_ATTR and STORE_NAME). There is, as far as I know, no way to hook into and prevent STORE_NAME as yet. But STORE_ATTR calls are easy to override: ```
class DemoModule(type(glob)): ... def __setattr__(self, name, value): ... print("You tried to change an module attribute, you naughty person!") ... glob.__class__ = DemoModule
glob.spam = 1 You tried to change an module attribute, you naughty person! glob.spam Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'glob' has no attribute 'spam'
> And from a PoV of a human programmer, it's like written in the comment
> - first, the symbol (name) "func1" is defined as a function, and then
> it's redefined as a variable.
It sounds like you are describing a programmer who doesn't understand
Python's execution model.
Do you understand that "func1" is already a variable? In the sense that
"variables" are name bindings, which is the only sense that applies to
Python. Just because it is bound to a function object doesn't make it
something different -- "func1" is still a name bound to a value, which
is the Python concept of a variable.
Paul, I would have more confidence in your proposal if you described
your proposal in terms of Python's existing execution model. Because so
far, the language you use to describe your proposal sounds like the
language used by somebody who doesn't understand Python's execution
model.
That does not give me confidence in your understanding of the
consequences of these changes, or that you are coming to this proposal
as somebody who loves Python. If you want to program in another language
with radically different semantics, there are hundreds of languages that
aren't Python. You don't have to turn Python into one of them.
> > Is monkey-patching disallowed because `mod.func1` is defined as a
> > constant?
>
> What "disallowed" do you mean? The example above clearly says "Leads to
> a warning". At "run-time" (i.e. eventually, after you've done the
> monkey-patching), it's disallowed, yes.
What disallowed do I mean? Exactly the same disallowed you just agreed
with.
> > Or are all functions automatically considered to be
> > constants?
>
> That's the case, right.
Okay, so all functions are automatically constants.
[regarding decorators]
> That's "conceptual model". How it's actually implemented is, "bu abuse
> of notation" is:
>
> def decorate(func):
> ...
>
> Works without hitch with the strict mode.
Okay, Chris made the same point.
Is that a language guarantee or a quirk of the implementation?
For this to be guarenteed to work requires the implementation of
decorators to be guaranteed by the language. If it is not already a
guarantee, it will have to be made one.
(For the record, that is not a point against your proposal, just an
observation.)
[...]
> > Occasionally I find that decorator syntax is not sufficient, and I've
> > used the explicit "define-decorate-replace" form. That won't work
> > either.
>
> You'll get a warning, and if you're smarter than the strict mode in
> that case, you can disable it (in the same sense that you can disable
> any warning in Python).
So "strict mode" isn't actually strict, it's just a built-in linter.
--
Steve