-4
$\begingroup$

What many other languages do

In many languages, I can have a function defined in a file called get_xyz.m (for example) and then other functions or scripts can use that function with a syntax like:

get_xyz(argument)

For example, if I want the argument to be the number "5", the I can do:

get_xyz(5)

What we have done in Python

Python doesn't allow "functions as files" unless we add lines like from get_xyz import get_xyz to the beginning, which seems like a waste of space and can make the file quite long if there's a lot of them to import. Instead it we can have a "module" file which can contain functions, but they can't be called in such a simple way like in other languages. The reason this question arose for me while working on a project with other team members, is because we had something like:

get_xyz.get_xyz(argument) 

in Python, which looked very redundant. One programmer changed it to something like:

go_db.get_xyz(argument) 

which I found to be a big more confusing and it seemed "forced", as if we didn't really want to come up with a second name, but it was done in order to make the "module" and "function" have different names.

What others have done in Python

Others have also run into this issue in their Python programs, and one example can be seen here for a Python program that currently has 898 stars and 475 forks on GitHub:

fci.FCI(argument)

Here the "module" name and the function name are distinguished by using lower case and capital letters.

Why can't we just call functions like in other languages?

I debated for a while with two hard-core Python enthusiasts about this, and the only answer that I eventually got at the very end was:

"This solves the issue of namespaces, so that no two things have the same name."

Is that the only reason why Python was designed this way?

$\endgroup$
13
  • 9
    $\begingroup$ Typically you would write from get_xyz import get_xyz, e.g. from timeit import timeit or from decimal import Decimal, when a module has just one "main" export. This still obviously duplicates the name, but the import statement is where that duplication belongs, not the call-site. So I dispute the premise ─ Python does allow you to call the function like get_xyz(5), it's just that the module is not the function. Perhaps the question should instead be e.g. why Python doesn't have a syntax for this kind of import, but really it's because it doesn't have a syntax for default exports. $\endgroup$
    – kaya3
    May 16, 2023 at 21:53
  • 2
    $\begingroup$ I said this in my answer as well, but can you name another language where files are functions? I've only ever seen this pattern in MATLAB and I've always found it, to be frank, incredibly silly (more so than forcing files to be classes). $\endgroup$ May 16, 2023 at 22:01
  • $\begingroup$ @SilvioMayolo There's tonnes of examples. Other than MATLAB/Octave, there's also Fortran, Julia and probably most programs used in scientific computing, which is my area. $\endgroup$ May 16, 2023 at 22:10
  • $\begingroup$ The example I'd give is in Javascript, you can export default a function from a module, such that when you import that module it binds the function to the imported name, rather than an object containing the module's exported names. $\endgroup$
    – kaya3
    May 16, 2023 at 22:49
  • $\begingroup$ @kaya3 I edited my question in response to your comment, but SE only allows us to "ping" one user at a time in comments, so I only replied to Silvio's comment the first time :) $\endgroup$ May 16, 2023 at 22:51

2 Answers 2

9
$\begingroup$

This pattern is not as common as you think

It looks like you're referencing MATLAB there. MATLAB is the only language I know that forces a file to be in one-to-one correspondence with the language's notion of a "function". In my experience, when a language ties an existing construct to the source files making up your program, it just limits what you can do.

  • MATLAB forces files to be public functions, and that forces me to split up several small but public functions into extremely tiny files.
  • Java forces files to be public classes. This results in several awkward patterns where I have so-called "classes" containing only static methods.

The languages that have the most success leveraging the file system do so by creating a new construct in the language itself specifically for the notion of a file. Python, and many languages, calls these construct a "module". A module is not an existing language feature. It's a new thing that can essentially be defined as "the reification of a file within Python". As such, its needs are exactly built to suit files and are not shoehorning the filesystem into an existing model of "functions" or "classes".

It's telling that the two most popular "better Java" languages removed the "one-class-per-file" restriction that Java put into place. Kotlin and Scala both allow any number of public declarations, even non-classes, to be placed in a single file, and they do the work of compiling that down to something the JVM acknowledges.

$\endgroup$
2
  • 4
    $\begingroup$ FWIW, this isn't uncommon in JavaScript -- you can just require('is-odd')(3) -- but JavaScript allows you to export whatever the heck you want. $\endgroup$
    – Bbrk24
    May 16, 2023 at 22:08
  • 1
    $\begingroup$ There's a few things I want to say about this answer. (1) There's tonnes of examples of languages that have this pattern. Other than MATLAB/Octave, there's also Fortran, Julia and probably most programs used in scientific computing, which is my area. (2) It's not true that MATLAB forces you to split up several small public functions into "extremely tiny files". I often have all my functions in one file, or at least, many functions per file. (3) You said "forces a file to be in one-to-one correspondence with the language's notion of a "function"" but I was not talking about "forcing". $\endgroup$ May 16, 2023 at 22:14
2
$\begingroup$

There are a few reasons:

  1. As you said, so no two namespaces have the same name
  2. Readability and clarity. The module.function() syntax provides clear information about where the function is defined making it more readable and clear, especially in big projects.
  3. Modularity and Encapsulation. This helps organize code and improves its maintainability
  4. Explicit importing. It is a documentation method to show what's in the code and prevents function name collision between different modules.
  5. Consistency and easy to use. It is also how you would go about getting attributes or object methods, making it more intuitive and easy to learn.
$\endgroup$
1
  • $\begingroup$ (2) I find module.function() unnecessarily verbose, rather than "more readable and clear" than function(). (3) How does it help here? (4) Is this not the same as (1)? (5) How is it more "intuitive" and "easy to learn" than allowing us to do function()? If you still think it's more intuitive and easy to learn, by how much? I picked up MATLAB way faster than I picked up Python. Within a week I could do more in MATLAB than I can do in Python after a few years (albeit not doing full-time Python programming during these years). $\endgroup$ May 16, 2023 at 22:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .