# Define Python function in Julia file with PythonCall?

**URL:** <https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593>\
**Category:** General Usage\
**Tags:** pycall, python, pythoncall\
**Created:** [May 10, 2023, 6:01am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593 "2023-05-10T06:01:25Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 10, 2023, 6:01am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/1 "2023-05-10T06:01:25Z")

</div>

Context: I have a Pluto notebook for teaching where I need to create a Python function. I want to use PythonCall for better portability, but I miss the `py"..."` syntax of PyCall which allows you to directly define Python functions inside Julia code. Is there a workaround to importing the function from a file? I looked at [`@py`](https://cjdoris.github.io/PythonCall.jl/stable/pythoncall-reference/#@py-and-@pyconst) but it doesn’t seem to work for my case.

---

<div class="post-metadata">

**Author:** ![stemann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stemann/32/4030_2.png) [@stemann](https://discourse.julialang.org/u/stemann)\
**Post date:** [May 10, 2023, 6:48am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/2 "2023-05-10T06:48:38Z")

</div>

Do you require the function to be defined _in_ Python, or could you use something like `pyfunc` as described in [Reference - PythonCall - Create classes](https://cjdoris.github.io/PythonCall.jl/stable/pythoncall-reference/#Create-classes) ?

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 10, 2023, 7:25am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/3 "2023-05-10T07:25:01Z")

</div>

Ideally I’d want the function to be defined _in Python_ to demonstrate the Julia speed up. Dumping on Python is my favorite pastime

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [May 10, 2023, 7:38am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/4 "2023-05-10T07:38:22Z")

</div>

```julia
julia> using PythonCall

julia> fib(x) = pyexec("""
       def fib(n):
            a, b = 0, 1
            while a < n:
                print(a, end=' ')
                a, b = b, a+b
            print()
       fib(y)
       """, Main, (y=x,))
fib (generic function with 1 method)

julia> fib(10)
0 1 1 2 3 5 8

```

[https://cjdoris.github.io/PythonCall.jl/stable/pythoncall-reference/#PythonCall.pyexec](https://cjdoris.github.io/PythonCall.jl/stable/pythoncall-reference/#PythonCall.pyexec)

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 10, 2023, 7:39am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/5 "2023-05-10T07:39:38Z")

</div>

Thanks a bunch!

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 10, 2023, 2:28pm UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/6 "2023-05-10T14:28:31Z")

</div>

For future reference, we don’t need to redefine the Python function every time we call the Julia one, we can also access local variables within it:

```julia
julia> fib(n) = pyexec(
           @NamedTuple{a::Int},
           """
           a, b = 0, 1
           for k in range(n):
               a, b = b, a + b
           """,
           Main,
           (n=n,)
       )
fib (generic function with 1 method)

julia> fib(10)
(a = 55,)

```

---

<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:** [May 17, 2023, 7:42am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/7 "2023-05-17T07:42:19Z")

</div>

Whenever you use `pyexec` you’re invoking the Python parser, which makes for an unfair comparison. It’s better to use it to create a Python function then call that:

```julia
@pyexec """
def fib(n):
   a, b = 0, 1
   while a < n:
       print(a, end=' ')
       a, b = b, a+b
   print()
""" => fib

fib(10)

```

This example uses `@pyexec`’s handy `=>` notation for getting variables into and out of Python.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 17, 2023, 7:47am UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/8 "2023-05-17T07:47:51Z")

</div>

Thanks, that’s exactly what I was looking for

---

<div class="post-metadata">

**Author:** ![hubert](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hubert/32/48028_2.png) [@hubert](https://discourse.julialang.org/u/hubert)\
**Post date:** [October 20, 2023, 7:40pm UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/9 "2023-10-20T19:40:03Z")

</div>

Thanks for the great extension to the PythonCall doc! What I can’t get to work yet is an import within the literal code, or some way to get an import (e.g. numpy) to work in or around your fibonacci. There must be a way?  
Thanks for any tips!

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [October 15, 2024, 4:29pm UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/10 "2024-10-15T16:29:40Z")

</div>

@cjdoris sorry for the necroposting but I find myself interested in this question again. Is there a way to achieve that?

---

<div class="post-metadata">

**Author:** ![JosephPollacco](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josephpollacco/32/51404_2.png) [@JosephPollacco](https://discourse.julialang.org/u/JosephPollacco)\
**Post date:** [April 9, 2025, 1:02pm UTC](https://discourse.julialang.org/t/define-python-function-in-julia-file-with-pythoncall/98593/12 "2025-04-09T13:02:22Z")

</div>

I found an alternative solution by using \*\* PythonCall.@pyexec\*\*

```julia
function PYTHON_2_JULIA(P_Int, P_Float, P_String, P_Vector)

    PythonCall.@pyexec """
        def PYTHON_2_JULIA(P_Int, P_Float, P_String, P_Vector):
            P_Int1 = P_Int + 1
            P_Float1 = P_Float * 2.0
            P_String1 = P_String + P_String 
            P_Vector1 = P_Vector + P_Vector
            return P_Int1, P_Float1, P_String1, P_Vector1
        """=> PYTHON_2_JULIA

    P_Int1, P_Float1, P_String1, P_Vector1 = PythonCall.pyconvert(Any, PYTHON_2_JULIA(P_Int, P_Float, P_String, P_Vector))

return P_Int1, P_Float1, P_String1, P_Vector1
end

```

To run it:

> P\_Int=1; P\_Float=2.0; P\_String=3; P\_Vector = [1.0, 2.0, 3.0, 4.0]  
> P\_Int1, P\_Float1, P\_String1, P\_Vector1 = .PYTHON\_2\_JULIA(P\_Int, P\_Float, P\_String, P\_Vector)
> 
> @show P\_Int1, P\_Float1, P\_String1, P\_Vector1
> 
> P\_Vector1[1]

_ **This gives as expected** _

```julia
(2, 4.0, 6, [2.0, 4.0, 6.0, 8.0])
2.0

```
