On 2/05/20 11:30 AM, Chris Angelico wrote:
On Sat, May 2, 2020 at 9:14 AM DL Neil via Python-list
<python-list@python.org> wrote:
On 28/04/20 7:36 PM, Chris Angelico wrote:
"Best"? Not sure about that. Functions are first-class objects in
Python, so a function *is* a callable object. You don't have to create
a custom class with a call method just to be able to attach attributes
to your function.
ChrisA
Using a mutable object as a function default parameter value
and changing it inside the function looks like a "trick"
according to me.
Sure. But you're contrasting this to a suggestion to literally just
attach attributes to a function. Python lets you actually do that. You
don't have to simulate the feature by creating a custom class and
making it callable - you just straight-up add attributes to a
function. Sure, what you suggested works, but there's no reason to.
Functions are objects too! I regularly point-out this powerful facility,
and its affordances, but...
Yes, it's perfectly reasonable and even sensible to attach an attribute;
BUT do many people expect to find such? If we were to collectively
survey our own application code, how many examples would we find - as a
percentage of such a corpus?
Expectation: it would be v.v.low. Accordingly, whilst
perfectly-implemented Python, and thus not a "trick", at least it is
something that is easy for 'an ordinary person' to 'miss' (or
misunderstand).
One of the problems with the use of function attributes is that
there's no way to say "this function". You have to use its name.
Otherwise, it would be easy to write self-contained idioms such as
static variables or omitted arg detection without the risk of
polluting the namespace:
def some_function(x, y, z=object()):
if z is me.__defaults__[0]:
z = x + y
...
def static(**kw):
def deco(f):
for name, initial in kw.items():
setattr(f, name, initial)
return f
return deco
@static(called=0)
def other_function():
me.called += 1
...
Obviously the name "me" can't be used, as it'd break a bunch of code,
but conceptually this would be incredibly helpful. It'd also be a
reliable idiom for recursion optimization - any "me()" is guaranteed
to be recursion and may potentially give info to an optimizer.
Perhaps, if Python had a way to identify the current function, it
would feel less odd to attach attributes to it.
The trouble is, functions seem to have an existential crisis: they know
their own __name__ but have no sense of self! However, all is not lost
because they are still very __func__-y.
(apologies to anyone reading this whilst drinking)
Unfortunately, Shakespeare is not the only one to ask: what's in a name,
Rosie?
>>> def double( x ):
... return x + x
...
>>> double( 2 )
4
>>> double.__name__
'double'
### so-far, so-good - but let's pick-up the pace:
>>> pasodoble = double
>>> pasodoble( 2 )
4
>>> pasodoble.__name__
'double'
### You're so tired (from working quickly, perhaps) that you can't even
remember your own __name__?
(by extrapolation, I estimate; but you (@Chris) will no doubt, educate)
I'm assuming this has something to do with "decorators"?
In relation to the wider part of the problem-mentioned, a class is
instantiated to become a second, and separate-but-linked, object.
Whereas the two function-names are merely multiple labels to the same
object (and id()):
>>> pasodoble
<function double at 0x7f57b5873a70>
>>> double
<function double at 0x7f57b5873a70>
### Whereas:-
>>> class C():
... '''Docstring that says nothing about a class that does just as
much.'''
...
>>> c = C()
>>> C.__name__
'C'
>>> c.__name__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__name__'
### Wait a minute! Have you forgotten your own name?
### What else don't you know?
>>> c.self
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'self'
>>> c.__doc__
'Docstring that says nothing about a class that does nothing.'
### (yes, I know, *I* caused the first of these two!)
### However, they are separate entities. Proof:
>>> id( C )
94619010560432
>>> id(c)
140014684436880
Hence, being empowered to accomplish a lot more with instantiated classes.
Although methods are merely functions, a method enjoys 'extra' by virtue
of being an attribute of a class's instance and being able to call-upon
further attributes within the same namespace.
--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list