Open jdupl123 opened 5 years ago
This is a PyCall issue https://github.com/JuliaPy/PyCall.jl/issues/11
jl = Julia(compiled_modules=False) M.costs = costs ctree=jl.eval('hclust(costs, linkage=:ward)')
If you need to call hclust
many times, a slightly better workaround than mutating the global variable in Main
is to create a (anonymous) function on the Julia side:
hclust = jl.eval("costs -> hclust(costs, linkage=:ward)")
hclust(costs)
Thanks for the quick reply.
I came across the same problem when writing a python wrapper for my Julia project.
In the project, I'm using several “configuration structs” written with Parameters.jl so that the constructors are quite flexible.
These struct have many fields, some of which require Symbol
values.
Wrapping them in a PyCall.pyfunction
or anonymous functions would have resulted in a loss flexibility and would have made matters somewhat complicated.
Instead, I Main.include
the following script right after initializing Julia in Python:
PC = PyCall;
PC.py"""
class SymStr():
def __init__(self, *args, **kwargs):
self.s = str(*args, **kwargs)
def __str__(self):
return self.s.__str__()
def __repr__(self):
return f'SymStr("{self.__str__()}")'
"""
sym_str_py_type = PC.py"SymStr";
PC.PyObject( s :: Symbol ) = PC.py"SymStr($(string(s)))"o
function PC.convert( ::Type{Symbol}, po :: PC.PyObject )
sym_str = PC.pyisinstance( po, sym_str_py_type ) ? po.s : po;
return Symbol(PC.convert(AbstractString, sym_str))
end
PC.pytype_mapping(sym_str_py_type, Symbol);
nothing
This basically follows the proposal in the corresponding PyCall issue (https://github.com/JuliaPy/PyCall.jl/issues/11) by defining a python class to wrap around strings that are meant to be Julia Symbols.
I can now do something like Main.MyJuliaConstructor( sym_field = Main.Symbol("sym_val") )
.
Within Python I can get the string value from a SymStr
from the field s
or by wrapping it in str()
.
I don't know whether to open a pull request over at PyCall. Are they still working on an alternative conversion routine?
Edit: Removed single quotes within PC.py"SymStr($(string(s)))"o
I came across the same problem when writing a python wrapper for my Julia project. In the project, I'm using several “configuration structs” written with Parameters.jl so that the constructors are quite flexible. These struct have many fields, some of which require
Symbol
values. Wrapping them in aPyCall.pyfunction
or anonymous functions would have resulted in a loss flexibility and would have made matters somewhat complicated.Instead, I
Main.include
the following script right after initializing Julia in Python:PC = PyCall; PC.py""" class SymStr(): def __init__(self, *args, **kwargs): self.s = str(*args, **kwargs) def __str__(self): return self.s.__str__() def __repr__(self): return f'SymStr("{self.__str__()}")' """ sym_str_py_type = PC.py"SymStr"; PC.PyObject( s :: Symbol ) = PC.py"SymStr($(string(s)))"o function PC.convert( ::Type{Symbol}, po :: PC.PyObject ) sym_str = PC.pyisinstance( po, sym_str_py_type ) ? po.s : po; return Symbol(PC.convert(AbstractString, sym_str)) end PC.pytype_mapping(sym_str_py_type, Symbol); nothing
This basically follows the proposal in the corresponding PyCall issue (JuliaPy/PyCall.jl#11) by defining a python class to wrap around strings that are meant to be Julia Symbols. I can now do something like
Main.MyJuliaConstructor( sym_field = Main.Symbol("sym_val") )
. Within Python I can get the string value from aSymStr
from the fields
or by wrapping it instr()
.I don't know whether to open a pull request over at PyCall. Are they still working on an alternative conversion routine?
Edit: Removed single quotes within
PC.py"SymStr($(string(s)))"o
Is there a way to pass a constructor that has symbols into another function?
For example, a = Main.MyJuliaConstructor( sym_field1 = Main.Symbol("sym_val1"), sym_field2 = Main.Symbol("sym_val2" )
and then do 'Main.MyFucntion(a)'?
I would have supposed that it should just work.
In fact, I guess I am doing something similar in my project (outdated atm):
Here I initilize a Julia AlgoConfig
with kwargs and reference it in the Python object cfg
as self.jlObj
.
In this line I then call the Julia function optimize
and pass the AlgoConfig
via cfg.jlObj
.
@jdupl123 Thank you for the solution. I think using the Main.eval is the best way to go.
I am trying to pass a symbol to the hclust function from http://juliastats.github.io/Clustering.jl/stable/hclust.html
I keep getting
TypeError: in #hclust, in typeassert, expected Symbol, got String
I also tried
but same error. I believe this is because PyCall is converting the symbol to a string before passing it through.
Current work around is: