Function to avoid a global variable

DL Neil PythonList at DancesWithMice.info
Fri May 1 20:50:11 EDT 2020


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 at 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


More information about the Python-list mailing list