What variable type is returned from Open()?
DL Neil
PythonList at DancesWithMice.info
Wed Apr 15 19:42:23 EDT 2020
On 16/04/20 1:55 AM, dcwhatthe at gmail.com wrote:
> As much as possible, I make use of optional type hints. So if I know a function returns an integer, then I use
> this_number_i : int = GetThisNumber()
> But there's no 'file' type, so I'm not sure what to use as the type for the return value of an Open() function.
> config_file : file = open(config_file_s, "r")
> What type of variable should config_file (above) be declared as?
First point (at the risk of teaching you/Grandma how to suck eggs) is
that Python is a "dynamically-typed" language. Thus we may write:
a = "abc"
in one place, and:
a = 123
in another.
Python won't complain. However, such code is a recipe for confusing
people - if not yourself, more 'simple' colleagues, such as me; because
we get used to the idea of "a" as a string of characters, only to be
presented with a number/int. What???
Thus the 'virtue' of typed languages, and adding data-typing features
into one's code!
It is important to remember that the Python docs (see refs, below) refer
to data-typing as "Hints". Indeed Python itself pays little/no attention:
>>> i:int=6
>>> j:int="str"
>>> i
6
>>> j
'str'
Since when has the string of characters: "str" been an integer???
To make good use of typing hints requires a bolt-on checker such as
"mypy". Quoting, the release notes for Python 3.5:
<<<
While these annotations are available at run-time through the usual
__annotations__ attribute, no automatic type checking happens at
run-time. Instead, it is assumed that a separate off-line type checker
(e.g. mypy) will be used for on-demand source code analysis.
>>>
(most IDEs will offer a mechanism to automatically run this, along with
linters, test-runners, etc, every time a source-file is saved)
Coming from other languages, there is a tendency to see typing as at
least helpful, even when it's not 'required'. Similarly, some
languages/conventions encourage the use of prefixes or suffixes in
naming variables, to help one remember the data-type. These are habits
that are difficult to break - and indeed, it is arguable whether
breaking them entirely would make one a 'better programmer'! (IMHO)
Python prefers to be descriptive, and in making a variable's name
meaningful, to imply or to 'carry' well-rounded and sufficient
information. Choosing names is an under-rated skill, and difficult to
master. (again, IMHO)
Now, because you (as above) "know a function returns an integer", Python
does too! However, if you (so kindly) save me hours of work by offering
this function to me, what do I know about it? The answer is that I look
at the function's "signature".
If we totally eschew data-typing it might be:
def find_sentence_length( sentence ):
etc
We can guess the data-type of "sentence" and that of the value to be
returned, but (a) it's a "guess", (b) we have to invest extra effort,
and (c) we might guess wrong[ly]! (although such might/should be
included in the function's docstring!)
You (as I) probably prefer:
def find_sentence_length( sentence:str )->int:
etc
This is readily-understood to describe the taking 'in' of a string of
characters, and the subsequent return of an integer. No muss, no fuss!
Subsequently:
sentence_length = find_sentence_length( my_sentence )
tells both Python and me (and any typing checker), that sentence_length
is an integer.
That said, there is still room for misunderstanding. Guessing again?
Even with such a contrived and simplistic example, there is room for
confusion: is that "length" measured in characters, inches/millimeters,
pixels, or what?
So, typing (or strongly-typed languages) is/are not the
be-all-and-end-all, nor does it offer a 'silver bullet'!
Before anyone asks: when I use "sentence_lengthPX" it produces howls of
complaint from certain ('pythonic') colleagues - notice though, that its
purpose is clear!
My opinion/coding-habits may differ from others (surely (and sadly) it
is 'they' who differ from me!). For each class I like to 'define'
most/all of its data-attributes in the __init__(), and to add typing
information to those definitions - with additional supportive comment,
as appropriate. This is mostly a bid to carry-forward as much
information as possible from the design-docs. (also, if the class
contains 'state' information, it seems to make it easier to write and
generalise __str__() and any other 'general' routines across states. YMMV!)
NB I'm not arguing with @Chris - I wouldn't dare!
I don't see this as an extension of the class's signature - it won't be
read because it's not needed if we treat the class as a 'black box'.
Conversely, it *is* a useful reminder/initiation to my/someone else's
comprehension of the inner-workings of the class itself!
Another thought, relating to the (above) specific example of
"config_file : file = open(config_file_s, "r")", is that once-again, the
'pythonic' approach leads one into a different way of thinking (if we
let ourselves 'go with the flow').
The preferred method of dealing with files, (somewhat newer than
illustrations in many text-books) is to use a "Context Manager", eg
with open(config_file_s, "r") as configurations:
for configuration in configurations:
# bend it to your will
Note the absence of any try...except structure, which we would normally
use to ensure the file is (eventually) closed and garbage-collection
assured! These offer a powerful implementation (actually, a "protocol").
Thus, "configurations" is (still) a "file descriptor" (fd), but its
definition now appears on the right of the open() (ie the open
function-call), because it is part of a "with" (compound) statement.
Auto-magically, "configurations" will only exist within the "context" of
the "with"!
The "with" opens a code-block ("wraps" is the docs' terminology). The
code block/compound[ed] statements (presumably) contain everything
needed to operate on that file's content, eg read a config setting,
update the app's environment class/dict/constant, log the specification,
etc. Hence the terms "context" and "encapsulation".
The fd only exists (its "scope") 'within' and for the 'life' of this
block. If this code-block is kept short - as it should be (fitting on
one screen is a popular definition for max-"short") then you/I/we can
easily track "configurations" during its short, but very-necessary, life
- and being a 'bear of little brain', if/when I forget, the reminder is
still right there on-screen if I but lift mine eyes! So, using
data-typing seems of little benefit (although it is still possible!)
NB clearly this is an argument from cognitive psychology rather than
computer science!
To generalise that point: if one practices 'modular coding', "separation
of concerns", and related philosophies (in recognition of how
encapsulation helps cognition); then considerately-thoughtful
function/method signatures combined with (short) single-objective
code-modules, enable one to comprehend and remember (all?most) data-type
information, as part of understanding the context and purpose of each
unit of code. ("chunking")
Speaking personally, it took me a long time to get used to such ideas as
"dynamic typing" and to focus on what I gained (cf what I 'lost'). Some
might argue that I'm still adapting! However, the 'golden rule' (whether
considering programming languages or human languages!) is not to try to
bend/fold/spindle/mutilate one language, to make it look/sound like
another! It's always worth asking the meta-level question: why am I
wanting to (try to) do this, this way? Aka: is there a better way?
Web-Refs:
PEP 483 -- The Theory of Type Hints:
https://www.python.org/dev/peps/pep-0483/
PEP 484 -- Type Hints: https://www.python.org/dev/peps/pep-0484/
New in Python 3.5: https://docs.python.org/3/whatsnew/3.5.html
Typing: https://docs.python.org/3/library/typing.html?highlight=pep%20typing
Using "with":
https://docs.python.org/3/reference/compound_stmts.html?highlight=context%20manager#the-with-statement
Typing context managers:
https://docs.python.org/3/library/typing.html?highlight=context%20manager#typing.ContextManager
Using context managers:
https://jeffknupp.com/blog/2016/03/07/python-with-context-managers/
--
Regards =dn
More information about the Python-list
mailing list