# PythonCall.jl style regarding type conversion

**URL:** <https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626>\
**Category:** General Usage\
**Tags:** type, python, pythoncall\
**Created:** [July 30, 2024, 8:40am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626 "2024-07-30T08:40:11Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![JordiBolibar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jordibolibar/32/24307_2.png) [@JordiBolibar](https://discourse.julialang.org/u/JordiBolibar)\
**Post date:** [July 30, 2024, 8:40am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626/1 "2024-07-30T08:40:11Z")

</div>

I’m migrating some code from PyCall.jl to PythonCall.jl. While so far I’m loving the integration with CondaPkg.jl to handle the Python environment, I’m finding the lack of automatic type conversion quite cumbersome. I understand that it has some performance advantages, but previous lines of code that looked almost like pure Julia code when it fact it was Python, now they are flooded with `pyconverts` and other convoluted expressions to match the types.

I’m heavily relying on xarray, and for example this is a clear example of how much the code needs to be changed for this to work. It might be that I’m doing something wrong or being too naive, so please point me to a better solution if that’s the case:

Previous version using PyCall.jl

```julia
# `climate` is an xarray Dataset
# `period` is a Julia Date
if any(climate.time[1].dt.date.data[1] > period[1])
     # do something
end

```

Current version using PythonCall.jl

```julia
# `climate` is an xarray Dataset
# `period` is a Julia Date
if any(pyconvert(Date, (pd[].to_datetime(climate.time.data[0]).date())) > period[1])
     # do something
end

```

It is obvious that the version using PyCall reads much much better, virtually acting like Julia code. Is there a better way to write this type of code using PythonCall? Thanks in advance!

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [July 30, 2024, 9:44am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626/2 "2024-07-30T09:44:43Z")

</div>

Can you post a MWE please (i.e. include code to construct `climate` and `period`)?

---

<div class="post-metadata">

**Author:** ![JordiBolibar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jordibolibar/32/24307_2.png) [@JordiBolibar](https://discourse.julialang.org/u/JordiBolibar)\
**Post date:** [July 30, 2024, 10:34am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626/3 "2024-07-30T10:34:44Z")

</div>

I managed to reduce it even more in this MWE. It looks better, but I guess there’s no way to avoid having to manually convert every Python object I use.

MWE:

```julia
using PythonCall
using Dates

np = pyimport("numpy")
xr = pyimport("xarray")
pd = pyimport("pandas")

# Run the Python code block
@py begin

np.random.seed(123)

times = pd.date_range("2000-01-01", "2001-12-31", name="time")
annual_cycle = np.sin(2 * np.pi * (times.dayofyear / 365.25 - 0.28))

base = 10 + 15 * np.reshape(annual_cycle, (-1, 1))
tmin_values = base + 3 * np.random.randn(annual_cycle.size, 3)
tmax_values = base + 10 + 3 * np.random.randn(annual_cycle.size, 3)

ds = xr.Dataset({"tmin": (("time", "location"), tmin_values),
                 "tmax": (("time", "location"), tmax_values)},
                {"time": times, "location": ["IA", "IN", "IL"]})
end

# Create a dummy date for January 1, 2020
period = Date(2020, 1, 1)

# MWE
any(pyconvert(Date, ds.time.dt.date.data[1]) > period)

```

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [July 31, 2024, 7:51am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626/4 "2024-07-31T07:51:59Z")

</div>

That latest code looks like good PythonCall style to me.

The reason why you need to do the conversion yourself (and why PythonCall doesn’t do automatic conversion) is not for performance (although the resulting type stability is nice), it’s because Python objects are just fundamentally different things to Julia ones.

For example if you do `some_python_object.some_list.append(3)` then it is annoying if the Python list gets converted to a Julia vector, which doesn’t have the `append` property.

So the current design makes the boundary between Python and Julia explicit. Indeed in your original post, I don’t know which of the intermediate objects in `climate.time[1].dt.date.data[1]` are Python or not.

The same logic is why we have `pyconvert` instead of adding methods to `convert` - we don’t consider a Python list to be “the same” as a Julia vector.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 31, 2024, 8:02am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626/5 "2024-07-31T08:02:10Z")

</div>

> [@JordiBolibar](#):
>
> previous lines of code that looked almost like pure Julia code when it fact it was Python, now they are flooded with `pyconverts` and other convoluted expressions to match the types.

> [@cjdoris](#):
>
> it’s because Python objects are just fundamentally different things to Julia ones.
> 
> For example if you do `some_python_object.some_list.append(3)` then it is annoying if the Python list gets converted to a Julia vector, which doesn’t have the `append` property.

To reword this a little, PyCall makes Julian code work on (some) autoconverted Python objects and lets you opt into simply wrapped Python objects, while PythonCall instead makes Pythonic code work on wrapped Python objects and lets you convert them for Julian code.

> [@cjdoris](#):
>
> we have `pyconvert` instead of adding methods to `convert` - we don’t consider a Python list to be “the same” as a Julia vector.

But the instances before and after a `convert` aren’t usually the same in pure Julia either, and it does seem possible from the surface to move the `pyconvert` code to `convert` for the same calls and bonus auto-conversions in some circumstances. Could you elaborate on the semantic separation?

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [July 31, 2024, 8:19am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626/6 "2024-07-31T08:19:38Z")

</div>

Tongue-in-cheek reply: if you want a more magical and surprising mashup of Julia and Python syntax maybe Python.jl is for you:

> **[Jokes/Python at main · LilithHafner/Jokes](https://github.com/LilithHafner/Jokes/tree/main/Python)**
>
> Jokes. Contribute to LilithHafner/Jokes development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![JordiBolibar](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jordibolibar/32/24307_2.png) [@JordiBolibar](https://discourse.julialang.org/u/JordiBolibar)\
**Post date:** [July 31, 2024, 8:48am UTC](https://discourse.julialang.org/t/pythoncall-jl-style-regarding-type-conversion/117626/7 "2024-07-31T08:48:40Z")

</div>

Yes, this makes sense. I was not aware of this different philosophy before starting the move. I mainly did it due to the implicit use of CondaPkg.jl.

My workflow has a lot of mixed Julia and Python code, and using PyCall.jl enabled me to use xarray in a really transparent way. I was acting on xarray objects but I could treat the matrices and everything using Julia syntax and performance, which is really convenient.
