Using Python modules in Swift and Pythonkit

2.6k Views Asked by At

I was looking to get some help or clarification of the limitations of using PythonKit in Swift. Well I say PythonKit, I actually installed the Tensorflow toolchain in Xcode as I couldn't get Pythonkit to work on its own as a single dependancy (MacBook would spin its wheels with fans blasting trying to import numpy).

Anyway I wanted to say its brilliant that I can use Python modules in Swift, makes it much easier to potentially start using swift for more than just iOS apps.

My issue is that I have imported Python modules fine but its not clear how much functionality they will have. I assume ones like numpy will be pretty much the same but as a scientist I use netcdf files a lot so have been trying to use netCDF4. This imports fine and I can load the data object and attributes etc fine but I can't get the actual array out.

Here is an example:

import PythonKit
PythonLibrary.useVersion(3, 7)

let nc = Python.import("netCDF4")

var Data = nc.Dataset("ncfile path")
var lat_z = Data.variables["lat_z"][:]

The [:] is causing an error that is picked up by Xcode, removing it allows the script to run but results in the variable object rather than the array. I can add stuff to the end to get the attributes etc e.g. lat_z.long_name but not sure of how to extract the array without using [:]

I am hoping this is just a syntax difference that I need to learn with swift (very much early days with using it) or is it a limitation of the PythonKit? I have not found anyone atcually using netcdf4 (examples are mostly numpy and Matplotlib) If so are there some general limitations with using python modules in swift?

I am also trying to get Matplotlib to work but am pretty sure thats due to using an commandline tool project in Xcode which hasn't got a view so makes sense it can't show me an image.

Any pointers and maybe links to upto date documentation would be great there seems to be some changes that have occurred e.g. import PythonKit rather than import Python.

Many Thanks

1

There are 1 best solutions below

1
On BEST ANSWER

You can use the count property on a python iterable, which is equivalent to len. You can index Numpy array in two ways: (i) with Swift range syntax and (ii) with Numpy range objects:

import Foundation
import PythonKit

let np = Python.import("numpy")
let array = np.array([1, 2, 3, 4, 5])

print(array)  // [1, 2, 3, 4, 5]

let subArray = array[0..<array.count] 
print(subArray)  // [1, 2, 3, 4, 5]

let subArray2 = array[np.arange(0, 2)]
print(subArray2)  // [1, 2]

// Swift equivalent of Python ":"
let subArray3 = array[...]

You can also convert numpy arrays to Swift arrays and use Swift methods and subscripts:

let swiftArray = Array(array)
let swiftSubArray = swiftArray[0..<3]

print(swiftSubArray)  // [1, 2, 3]

Note that you should prefer using Python.len(...) over the count property while working with PythonObjects because count will incur performance penalty because of the implementation of PythonKit that does not automatically conforms Python Object to RandomAccessCollection (thus count is O(n)).