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