What's the best way to minimize the need of run time checks?

Steven D'Aprano steve+python at pearwood.info
Sun Aug 14 00:13:38 EDT 2016


On Sun, 14 Aug 2016 06:59 am, BartC wrote:

> On 13/08/2016 17:06, Steven D'Aprano wrote:
>> On Sat, 13 Aug 2016 08:09 pm, BartC wrote:
> 
>>> record date=                # define the record
>>>     var day, month, year
>>> end
>>>
>>> d := date(25,12,2015)       # create an instance
> 
>> Sure. But you've put most of the work into the compiler.
> 
> Into the language so that it's always available and consistent rather
> than leaving it to individuals to somehow build something on top of
> existing language features.

Right. And there's little difference between that and making the feature
available from a standard library module, like namedtuple.

If the Python community rallies around this "record" functionality and takes
to it like they took too namedtuple, it could be added to the stdlib. In at
least one way that's better than making it part of the language: you can
backport the module to older versions of the interpreter.

[snip example of a Python "records" factory]
> That's pretty good actually. Although I noticed you used the __slots__
> feature that you were scathing about earlier on! (Also that you've
> thrown in examples of using decorators, and using exec(), free of
> charge..)

I wasn't scathing about __slots__. I said that it was not *added* to the
language in order to support enforcement of "these attributes, and no
others". It was added to the language as a memory optimization.

If you, or Lawrence, wish to (ab)use __slots__ to get a kind of poor mans
attribute declaration, that's your prerogative. I'm on the fence: I can see
that it is, perhaps, sometimes useful, but I wouldn't want to see it become
a widespread habit.


> There are a number of ways this approach differs from the native record
> example (but I acknowledge your example was put together as a quick demo):
> 
> * The fields in my record are known at compile time; using the wrong
> name will usually be picked immediately. As will using the wrong number
> of initialisers.

There's nothing like that in Python. But the difference between compile-time
and run-time is not that significant in practice (as opposed to theory,
where it is critical).


> * (My record fields have other features: aliases for any field; the
> ability to access by index, doing len() etc; fast conversions to and
> from a list; also the ability to create packed records that exactly
> match C structs, and so on.)

I'm not sure what you mean by aliases, or how you would use them. Got an
example?

As for the rest, if I were planning to make this a polished product, I'd
certainly go for access by index and support for len(). Given access by
index, that gives me list conversion and iteration for free.


> * Each defined record in my scheme ('date' and so on) is a distinct
> type. 

As is mine.

> If I use the Python record() to create two records R and S, then 
> type(R) and type(S) seem to give the same result (both 'type').

Of course: the type of a class is "type":

py> type(str), type(int), type(list), type(type)
(<class 'type'>, <class 'type'>, <class 'type'>, <class 'type'>)


This is called the metaclass; the class of a class. And yes, type is its own
type. What you should be doing is comparing the types of record *instances*
instead:

py> x = record('Spam', 'breakfast lunch dinner')('spam', 
...     'spam and eggs', 'spam and eggs and spam with a side-dish of spam')
py> y = record('Date', 'year month day')(1999, 'August', 14)
py> type(x), type(y)
(<class '__main__.record.<locals>.Inner'>,
<class '__main__.record.<locals>.Inner'>)


Hmmm. I didn't expect that. I expected to see the names of the classes:

py> type(x).__name__, type(y).__name__
('Spam', 'Date')


If I was publishing this as a polished product, I'd want to fix that.





-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list