In [0]:
// #@title Licensed under the Apache License, Version 2.0 (the "License"); { display-mode: "form" }
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
In [0]:
// comment so that Colab does not interpret `#if ...` as a comment
#if canImport(PythonKit)
import PythonKit
#else
import Python
#endif
print(Python.version)
By default, when you import Python
, Swift searches system library paths for the newest version of Python installed.
To use a specific Python installation, set the PYTHON_LIBRARY
environment variable to the libpython
shared library provided by the installation. For example:
export PYTHON_LIBRARY="~/anaconda3/lib/libpython3.7m.so"
The exact filename will differ across Python environments and platforms.
Alternatively, you can set the PYTHON_VERSION
environment variable, which instructs Swift to search system library paths for a matching Python version. Note that PYTHON_LIBRARY
takes precedence over PYTHON_VERSION
.
In code, you can also call the PythonLibrary.useVersion
function, which is equivalent to setting PYTHON_VERSION
.
In [0]:
// PythonLibrary.useVersion(2)
// PythonLibrary.useVersion(3, 7)
Note: you should run PythonLibrary.useVersion
right after import Python
, before calling any Python code. It cannot be used to dynamically switch Python versions.
Set PYTHON_LOADER_LOGGING=1
to see debug output for Python library loading.
In Swift, PythonObject
represents an object from Python.
All Python APIs use and return PythonObject
instances.
Basic types in Swift (like numbers and arrays) are convertible to PythonObject
. In some cases (for literals and functions taking PythonConvertible
arguments), conversion happens implicitly. To explicitly cast a Swift value to PythonObject
, use the PythonObject
initializer.
PythonObject
defines many standard operations, including numeric operations, indexing, and iteration.
In [0]:
// Convert standard Swift types to Python.
let pythonInt: PythonObject = 1
let pythonFloat: PythonObject = 3.0
let pythonString: PythonObject = "Hello Python!"
let pythonRange: PythonObject = PythonObject(5..<10)
let pythonArray: PythonObject = [1, 2, 3, 4]
let pythonDict: PythonObject = ["foo": [0], "bar": [1, 2, 3]]
// Perform standard operations on Python objects.
print(pythonInt + pythonFloat)
print(pythonString[0..<6])
print(pythonRange)
print(pythonArray[2])
print(pythonDict["bar"])
In [0]:
// Convert Python objects back to Swift.
let int = Int(pythonInt)!
let float = Float(pythonFloat)!
let string = String(pythonString)!
let range = Range<Int>(pythonRange)!
let array: [Int] = Array(pythonArray)!
let dict: [String: [Int]] = Dictionary(pythonDict)!
// Perform standard operations.
// Outputs are the same as Python!
print(Float(int) + float)
print(string.prefix(6))
print(range)
print(array[2])
print(dict["bar"]!)
PythonObject
defines conformances to many standard Swift protocols:
Equatable
Comparable
Hashable
SignedNumeric
Strideable
MutableCollection
ExpressibleBy_Literal
protocolsNote that these conformances are not type-safe: crashes will occur if you attempt to use protocol functionality from an incompatible PythonObject
instance.
In [0]:
let one: PythonObject = 1
print(one == one)
print(one < one)
print(one + one)
let array: PythonObject = [1, 2, 3]
for (i, x) in array.enumerated() {
print(i, x)
}
To convert tuples from Python to Swift, you must statically know the arity of the tuple.
Call one of the following instance methods:
PythonObject.tuple2
PythonObject.tuple3
PythonObject.tuple4
In [0]:
let pythonTuple = Python.tuple([1, 2, 3])
print(pythonTuple, Python.len(pythonTuple))
// Convert to Swift.
let tuple = pythonTuple.tuple3
print(tuple)
In [0]:
// `Python.builtins` is a dictionary of all Python builtins.
_ = Python.builtins
// Try some Python builtins.
print(Python.type(1))
print(Python.len([1, 2, 3]))
print(Python.sum([1, 2, 3]))
In [0]:
let np = Python.import("numpy")
print(np)
let zeros = np.ones([2, 3])
print(zeros)
Use the throwing function Python.attemptImport
to perform safe importing.
In [0]:
let maybeModule = try? Python.attemptImport("nonexistent_module")
print(maybeModule)
numpy.ndarray
The following Swift types can be converted to and from numpy.ndarray
:
Array<Element>
ShapedArray<Scalar>
Tensor<Scalar>
Conversion succeeds only if the dtype
of the numpy.ndarray
is compatible with the Element
or Scalar
generic parameter type.
For Array
, conversion from numpy
succeeds only if the numpy.ndarray
is 1-D.
In [0]:
import TensorFlow
let numpyArray = np.ones([4], dtype: np.float32)
print("Swift type:", type(of: numpyArray))
print("Python type:", Python.type(numpyArray))
print(numpyArray.shape)
In [0]:
// Examples of converting `numpy.ndarray` to Swift types.
let array: [Float] = Array(numpy: numpyArray)!
let shapedArray = ShapedArray<Float>(numpy: numpyArray)!
let tensor = Tensor<Float>(numpy: numpyArray)!
// Examples of converting Swift types to `numpy.ndarray`.
print(array.makeNumpyArray())
print(shapedArray.makeNumpyArray())
print(tensor.makeNumpyArray())
// Examples with different dtypes.
let doubleArray: [Double] = Array(numpy: np.ones([3], dtype: np.float))!
let intTensor = Tensor<Int32>(numpy: np.ones([2, 3], dtype: np.int32))!
In [0]:
// This cell is here to display plots inside a Jupyter Notebook.
// Do not copy it into another environment.
%include "EnableIPythonDisplay.swift"
IPythonDisplay.shell.enable_matplotlib("inline")
In [0]:
let np = Python.import("numpy")
let plt = Python.import("matplotlib.pyplot")
let time = np.arange(0, 10, 0.01)
let amplitude = np.exp(-0.1 * time)
let position = amplitude * np.sin(3 * time)
plt.figure(figsize: [15, 10])
plt.plot(time, position)
plt.plot(time, amplitude)
plt.plot(time, -amplitude)
plt.xlabel("Time (s)")
plt.ylabel("Position (m)")
plt.title("Oscillations")
plt.show()