建立用 Python 實作的 JSL 函數最近,我在 JMP 內部進行了一次有關 Python 提示和技巧的演講。有一個技巧我認為特別強大,因此我想與您分享:建立一個 JSL 函數來包裝 Python 函數的呼叫。換句話說,這是可以用 Python 編寫但給定 JSL 介面的實用程式程式碼。為了方便說明,我實作了一個簡單的 Python 函數,它接受兩個物件並將它們添加在一起,然後將該呼叫包裝在 JSL 函數中。我從三種不同類型的資料(數字、字串和列表)以及將兩個 Python 物件添加到一起的函數開始。
Names Default to Here(1);
one = 1;
two = 2;
author = "Paul Nelson";
devel = "Developer: ";
list1 = { 1, 3, 5, 7 };
list2 = { 2, 4, 6, 8 };
Python Submit("\[
def plus(a,b):
print(a, b)
return a+b
]\");
任何支援「+」運算子的 Python 物件都可以透過此 Python 函數處理。
// Python Execute is an underutilized gem. You can send a list
// of inputs and get a list of results and execute code all in one
// JSL statement.
Python Execute( {one, two}, {result}, "result = plus(one,two)" );
show(result);
結果:
result = plus(one,two)
/*:
1.0
2.0
result = 3;
這就是事情變得有趣的地方!特別是,包裝了 Python 定義的 plus() 函數的 JSL 函數。
// create a JSL function that wraps the the Python function
blow_mind = Function( {first, second}, // parameters
{pyresult}, // local variables
Python Execute( {first, second}, {pyresult}, "pyresult = plus(first,second)");
Return( pyresult ); // value to return
); // end of the definition
// Call the Python function through our JSL function. Good way to extend JSL
// using code written in Python. Could be useful for add-ins.
// Notice the same Python function handling different types of Python objects.
show( blow_mind(devel, author) );
show( blow_mind(list1, list2) );
給出結果:
//:*/
pyresult = plus(first,second)
/*:
Developer:
Paul Nelson
blow_mind(devel, author) = "Developer: Paul Nelson";
//:*/
pyresult = plus(first,second)
/*:
[1, 3, 5, 7]
[2, 4, 6, 8]
blow_mind(list1, list2) = {1, 3, 5, 7, 2, 4, 6, 8};
我們簡單的 plus() 函數處理數值求和以及字串和列表的串聯,這些都可以作為 JSL 函數呼叫。 JSL 程式碼的其餘部分完全沒有意識到實際呼叫的內容是在 Python 中發生的。
附完整文件。
您希望繼續使用 JSL 進行編碼,但對於特定的函數,您知道有一個簡單的方法可以使用 Python 編寫它。那麼如何建立一個 JSL 函數來在 Python 中實現其功能呢?
自動化和腳本編寫回覆:建立用 Python 實作的 JSL 函數感謝@Paul_Nelson改進的 Python 支援!
使用 Python Selenium 的瀏覽器腳本顯示了這一點
// 1: navigate to jmp.com
nav = Function( {url}, {rc},
Python Execute( {url}, {rc},
"\[
try:
driver.get(url)
rc = "ok"
except Exception as e:
rc = repr(e)
]\" );
return(rc);
);
rc = nav( "https://www.jmp.com/" );
if( rc != "ok", throw("nav: "||char(rc)));
最後兩行透過包裝器函數進行調用,以使 Web 瀏覽器導航到 JMP 網站。 JSL 函數的工作方式與 Paul 的範例完全相同。
回覆:建立用 Python 實作的 JSL 函數具有多個傳回值的全域、多行正規表示式搜尋
Add Custom Functions(
New Custom Function(
"hogi",
"Regex",
Function({input, pattern},
SubstituteInto(input,"\!n"," ","\!r", " ") ;
Python Send( input );
Python Send( pattern );
error = Python Submit( "\[
import re
print(input)
matches = re.findall(pattern,input)
]\" );
matches = Python Get( matches );
),
<<DESCRIPTION></DESCRIPTION>回覆:建立用 Python 實作的 JSL 函數請注意@hogi,我相信 Function() 應該有一個 return(matches);陳述。
另外,使用Python Execute() 就無需進行發送和獲取。
Add Custom Functions(
New Custom Function(
"hogi",
"Regex",
Function({input, pattern},
SubstituteInto(input,"\!n"," ","\!r", " ") ;
Python Execute( {input, pattern}, {matches}, "\[
import re
matches = re.findall(pattern,input)
]\" );
return( matches);
),
<回覆:建立用 Python 實作的 JSL 函數啊,對了。 Python 執行,好多了:)
在 JSL 函數中,最後一個表達式是傳回值 - 即使沒有包含return() 。
回覆:建立用 Python 實作的 JSL 函數我不擅長 Python,但我想使用一些 Python 函式庫(如 xxhash)。
我有一個關於記憶體使用的問題。如果我以這種方式JSL 函數包裝一些Python,並且在包裝的Python 程式碼中創建一個Python 對象,那麼每次調用該函數時,對我的JSL 包裝器函數的調用都會創建一個*新的* 持久性Python 物件(例如使用如果我調用該函數數千萬次會佔用記憶體)?
如果我在我的(例如)jmpstart.jsl 程式碼中建立一個命名的 Python 對象,並在我的過程中引用該對象,會怎麼樣?這樣會更好嗎?
以下是我想要使用 xxhash 執行的操作的範例。 (請注意,我在 jmpstart.jsl 腳本中將 xxhash 匯入到 Python 環境中。我無法從此函數中發出 JSL 浮點數,因為 JSL 不支援 8 位元組整數...)
Add Custom Functions(
New Custom Function(
"Global",
"xxhash64",
Function( {str},
{digest},
Python Execute( {str}, {digest}, "digest = xxhash.xxh64( str ).hexdigest()" );
Return( Hex To Number( digest ) );
)
)
)
回覆:建立用 Python 實作的 JSL 函數附言。我注意到這是糟糕的程式碼,因為十六進位摘要是無效 IEEE 浮點的機率約為 0.8%,導致該過程傳回 JSL 缺失值。也就是說,我仍然對所示的記憶體管理感到好奇。
回覆:建立用 Python 實作的 JSL 函數hashlib 和 base64 都是內建的 Python 函式庫。
我昨天就想專門調查這個案子。我可以告訴您,在最壞的情況下,它應該在 JMP 運行的整個過程中「洩漏」一個要摘要的引用。當 JMP 關閉時,變數將隨著 Python 關閉而釋放。 Python Set() 程式碼建立摘要變數並將其放置在 Python 環境的 globals() 字典中。這使得 Python Get() 能夠按名稱查找值並將該值傳回 JSL。 Python Execute() 基本上就是 Python Send/Set()、Python Submit()、Python Get() 的便利函數。所以字典有一個對digest的引用,但是一旦Python Execute()超出範圍,字典應該是唯一持有引用的字典。在第二個循環中,該值將被新值覆蓋,因此應釋放舊引用,從而允許垃圾收集返回該記憶體。
回覆:建立用 Python 實作的 JSL 函數謝謝保羅。關於記憶,這就是我所希望的。我會去看 hashlib 和 base64。
背景是:我想要一個8 位元組的雜湊值,我編寫了一個使用JSL 本機MD5 函數並將它們截斷為8 個位元組的雜湊值,但透過我的字串輸入,雜湊值似乎最終被聚集在一起。有人推薦我 xxhash64,因為它給出了非常隨機分佈的雜湊值。所以我使用了它,它似乎給出了分佈良好的哈希值。
如前所述,xxhash64 可以發出 longint,但我無法將其傳遞到 JSL 中。我可以將結果作為 JSL BLOB 進行傳遞,但 JMP 不允許我使用 BLOBS 作為 LINK ID – 這正是我想要使用雜湊值的目的。這有點偏離原來的問題,但如果您碰巧有任何想法,我們將不勝感激。
回覆:建立用 Python 實作的 JSL 函數附言。可以只使用十六進制的字串值作為我的連結 ID,但我渴望一些小而快速的東西。我正在處理大約 8000 萬行的表。
回覆:建立用 Python 實作的 JSL 函數@john_madden JMP 的 64 位元雙精確數字可以保存 -2^52 .. 2^52 之間的有符號整數。我認為您可以使用 hextonumber 保留 16 進制數字哈希值中的 13 十六進制數字,並避免任何有關無效浮點數的問題。但 52 位元可能還不夠。
我也在這附近玩過,發現這個生日攻擊表很有用。我正在使用文件的哈希來創建唯一密鑰,並想知道我需要多少位。從表中,我發現將 6,100,000 個項目新增至 64 位元雜湊表中發生衝突的可能性為 1/1,000,000。
對於我的用例,文件伺服器的磁碟是 1e11,典型檔案是 1e4,或限制為 1e7 個檔案。 64 位元哈希值太小,96 位元就可以了。我當然是選了256...

回覆:建立用 Python 實作的 JSL 函數嗨克雷格。這太棒了!您對 256 位元值使用什麼 JMP 類型?
順便說一句,如果開發人員能夠在某個時候為 JSL 添加比 MD5 更現代的雜湊函數,那就太好了。
回覆:建立用 Python 實作的 JSL 函數這是我最新的嘗試,看起來效果不錯:
"Accepts a string as input, and returns a JSL floating point number that encodes a 'nearly'-64-bit hash of the string. The hash is generated using the Python xxhash package with the default (0) seed.<BR />Python returns the 64-bit hash as a 16-character hexadecimal string. If the bits 2-12 are 11111111111, they are changed to 01111111111 before being processed further by JSL.<BR />This avoids generating an IEEE 754 floating point value of NaN or ∞, which JSL would interpret as Missing.<BR />This trick cuts the number of possible floating point exponent values<BR />from 2048 to 2046, resulting in a hash with 2^63 * 2046 possible values (= 1.89e22).<BR />For 10 million different inputs, this should yield a collision probability of roughly 1 in 380 milion<BR />according to Craige's reference if I calculcated right. On my M3 Max MacBook Pro, the routine takes around 26 μsec per iteration with random strings of length 11.
Names Default To Here( 1 );
Add Custom Functions(
New Custom Function(
"Global",
"xxhash64",
Function( {str},
{digest},
Python Execute( {str}, {digest}, "digest = xxhash.xxh64( str ).hexdigest()", echo( 0 ) );
startChars = Substr( digest, 1, 3 );
Hex To Number(
Match( startChars,
"7ff", "3ff" || Substr( digest, 4, 13 ),
"fff", "bff" || Substr( digest, 4, 13 ),
digest
)
);
)
) << Description(
"Accepts a string as input, and returns a JSL floating point number that encodes a 'nearly'-64-bit hash of the string.
Python must have already been initialized as follows:
Python Execute( {}, {},
\!"
import jmputils
jmputils.jpip('install', 'numpy pandas scikit-learn xxhash')
import jmp
import numpy
import pandas as pd
import xxhash
\!""
) //
<<PROTOTYPE></PROTOTYPE>回覆:建立用 Python 實作的 JSL 函數我的猜測是 Craige 使用的是十六進位數字字串或 Base64 編碼數字。
Python 整合的一大優點是您不需要 JMP 來「趕上」並提供更現代的雜湊函數。您可以透過 Python 獲得力量。我提到 hashlib 和 base64 的原因之一是它們是 Python 標準函式庫的一部分,因此所有 JMP 使用者都可以使用它們,而無需安裝外部套件。
回覆:建立用 Python 實作的 JSL 函數@約翰_馬登 - you want <SPAN class="token number">2</SPAN><SPAN class="token operator">^</SPAN><SPAN class="token number">52</SPAN> <SPAN class="token operator">*</SPAN> <SPAN class="token number">2046</SPAN> rather than <SPAN class="token number">2</SPAN><SPAN class="token operator">^</SPAN><SPAN class="token number">63</SPAN> <SPAN class="token operator">*</SPAN> <SPAN class="token number">2046</SPAN> . Or just use the 64 bit row.
很久以前我就知道JSL字串是如何保存在記憶體中的;我記得 24 個角色的表現發生了重大變化。您可能想要使用 96 位元版本並確保它保持在 24 個十六進位數字或以下。對於 10,000,000 個字串,16 GB 電腦上的空間為 1/4 GB...並且出現錯誤的機會從 1e-6 增加到 1e-15。如果不是運氣不好,我根本就沒有運氣 - https://quoteinvestigator.com/2020/09/02/bad-luck/ 。
I'm working with python/django/postgresql currently and I store the hex digits as a database key...a 64 character string gives me the 256 bits.
回覆:建立用 Python 實作的 JSL 函數再次感謝保羅和克雷奇。順便說一句,Python 整合讓我非常興奮,現在可以嘗試學習 Python,因為我的 IT 同事想要了解我的一些 JSL 程式碼,並且總是問我 Python 的等效項是什麼。非常感謝保羅所做的所有這些工作。
我還需要糾正上面腳本中哈希值數量的計算 - 我認為它更像是 2^64 - 2^63,比我說的少很多。
關於儲存哈希值,你說服我不要表現得那麼可愛。我認為你讓我相信最終只儲存十六進位字元會更好。我必須嘗試在巨大的表上進行一些連接,看看無論是連接十六進製字串列還是浮點數列,是否確實會產生任何速度差異;或者我是否使用字串或浮點數作為連結 ID。
如果我將大型 JMP 表匯出到 RDB,那麼我可以將它們轉換為 longint。
回覆:建立用 Python 實作的 JSL 函數克雷格關於哈希值的數量,你是絕對正確的,我再次感到困惑,沒有閱讀你的帖子。 2^52 * 2046 是正確的。