Update Jan 2020: E.M. Bray suggests a more elegant solution in the comments, see: https://ask.sagemath.org/question/7867/importing-sage-files/?answer=48947#post-id-48947

-

Let’s say that I have created a bunch of Sage code - Sage functions etc. - that I wish to reuse by importing into various Sage scripts. In straight Python, one would put these functions into their own separate file and import them using the usual from foo import funcname as localfuncname type procedure. It is unclear to me what the proper procedure for doing the same in Sage is - one can’t use the same syntax for a .sage file, and for example attach('functions.sage') and only works in interactive Sage and stomps local variables.

However after some Googling and experimentation, I have found one method that behaves in the way that I need: namely that local variables aren’t stomped, and Sage-style syntax, like expressing a rational as a fraction, is preserved. I don’t know if this is the best way to do it, but it seems to be working, so I thought I’d share it.

First write functions.sage as though it were a module file.

def myfunc(y):
    var('n, x')
    z1 = y
    z2 = 1/2

    return z1, z2

Then for the script where we want to use it (myscript.sage), we preparse the Sage functions file into a Python file and copy it to a name that can be handled before importing it.

import os
os.system('sage --preparse functions.sage')
os.system('mv functions.sage.py functions.py')
from functions import myfunc

x = 2
y = 3
z1,z2 = myfunc(y)

print(x)
print(z2)

When run, myscript.sage produces the following.

From the command-line

$ sage myscript.sage
2
1/2

From an interactive session:

sage: attach('myscript.sage')
2
1/2
sage: type(z2)
<type 'sage.rings.rational.Rational'>

The script produces functions.py, which looks like this:

# This file was *autogenerated* from the file functions.sage
from sage.all_cmdline import *   # import sage library
_sage_const_2 = Integer(2); _sage_const_1 = Integer(1)
def myfunc(y):
    var('n, x')
    z1 = y
    z2 = _sage_const_1 /_sage_const_2

    return z1, z2

It has been working out for me so far, but it seems a strange way to go about things. I’d welcome any commenters who know of a nicer way.