[Python-Dev] Updated PEP 362 (Function Signature Object)

Steven D'Aprano steve at pearwood.info
Fri Jun 8 04:08:09 CEST 2012


Nick Coghlan wrote:
> On Fri, Jun 8, 2012 at 4:34 AM, Larry Hastings <larry at hastings.org> wrote:
>> In other words: this is possible but extremely unlikely, and will only be
>> done knowingly and with deliberate intent by a skilled practitioner.
>>
>> I think it's reasonable to declare that, if you're monkeying around with
>> dunder attributes on a function, it's up to you to clear the f.__signature__
>> cache if it's set.  Like Spiderman's uncle Cliff Robertson said: with great
>> power comes great responsibility.
>>
>> I am now firmly in the "using __signature__ as a cache is fine, don't make
>> copies for no reason" camp.
> 
> I have a simpler rule: functions in the inspect module should not have
> side effects on the objects they're used to inspect.
> 
> When I call "inspect.signature(f)", I expect to get something I can
> modify without affecting the state of "f". That means, even if
> f.__signature__ is set, the signature function will need to return a
> copy rather than a direct reference to the original. If
> f.__signature__ is going to be copied *anyway*, then there's no reason
> to cache it, *unless* we want to say something other than what the
> inspect module would automatically derive from other attributes like
> __func__, __wrapped__, __call__, __code__, __closure__, etc.


There is still a potential reason to cache func.__signature__: it's a 
relatively large chunk of fields, which duplicates a lot of already existing 
data. Why make all function objects bigger when only a small minority will be 
inspected for their __signature__?

I think that lazy evaluation of __signature__ is desirable, and caching it is 
certainly desirable now that you have convinced me that there are use-cases 
for setting __signature__.

Perhaps func.__signature__ should be a computed the first time it is accessed? 
Something conceptually like this:

class FunctionWithSignature(types.FunctionType):
     @property
     def __signature__(self):
         if hasattr(self._sig):
             return self._sig
         sig = self._get_signature()  # Left as an exercise for the reader.
         self._sig = sig
         return sig
     @__signature__.setter
     def __signature__(self, sig):
         self._sig = sig
     @__signature__.deleter
     def __signature__(self):
         del self._sig



-- 
Steven



More information about the Python-Dev mailing list