2017-07-14 5 views
6

मेरे पास माइक्रोसॉफ्ट एक्सेस में एक वीबीए स्क्रिप्ट है। वीबीए स्क्रिप्ट कई लोगों के साथ एक बड़ी परियोजना का हिस्सा है, और इसलिए वीबीए पर्यावरण छोड़ना संभव नहीं है।वीबीए से पायथन तक numpy arrays को स्थानांतरित करना और पीछे

मेरी लिपि के एक खंड में, मुझे एक तालिका पर जटिल रैखिक बीजगणित करने की आवश्यकता है। इसलिए, मैं recordsets के रूप में लिखित वीबीए टेबल को लेयरॉन में रैखिक बीजगणित करने के लिए, और वापस वीबीए में ले जाता हूं। पायथन में मैट्रिस numpy सरणी के रूप में दर्शाए जाते हैं।

कुछ रैखिक बीजगणित स्वामित्व है और इसलिए हम pyinstaller के साथ मालिकाना स्क्रिप्ट को संकलित कर रहे हैं।

  1. VBA स्क्रिप्ट एक csv फ़ाइल तालिका input.csv का प्रतिनिधित्व बनाता है:

    प्रक्रिया का विवरण इस प्रकार हैं।

  2. VBA स्क्रिप्ट कमांड लाइन
  3. अजगर स्क्रिप्ट एक numpy मैट्रिक्स के रूप में csv फ़ाइल input.csv लोड करता है के माध्यम से अजगर स्क्रिप्ट चलाता है, उस पर रेखीय बीजगणित करता है, और एक आउटपुट csv फ़ाइल output.csv पैदा करता है।
  4. वीबीए पाइथन पूरा होने तक प्रतीक्षा करता है, फिर output.csv लोड करता है।
  5. वीबीए अब 0 -फ़ाइल और output.csv फ़ाइल को हटाए जाने की आवश्यकता नहीं है।

यह प्रक्रिया अक्षम है।

क्या सीएसवी अव्यवस्था के बिना पाइथन (और पीछे) में वीबीए मैट्रिस लोड करने का कोई तरीका है? क्या इन विधियों को संकुचित पायथन कोड के साथ pyinstaller के माध्यम से काम करते हैं?

मुझे प्रासंगिक उदाहरण हैं जो स्टैक ओवरफ्लो पर प्रासंगिक हैं। हालांकि, वे विशेष रूप से मेरी समस्या का समाधान नहीं करते हैं।

Return result from Python to Vba

How to pass Variable from Python to VBA Sub

+0

स्वामी होगा VBA स्क्रिप्ट अपने टेबल से सीएसवी बनाने के लिए, यह अजगर के पास, अजगर से वापस मिलता है, और हटाना बचा सिर्फ वहाँ है, तो ऐसा लगता है कि वहाँ की तरह वीबीए से अपना कोड चलाने की जरूरत नहीं है। क्या आप जानते हैं कि आप [पाइथन में एमएस एक्सेस डेटाबेस कनेक्ट कर सकते हैं] (https://stackoverflow.com/questions/853370/what-do-i-need-to-read-microsoft-access- डेटाबेस-using-python) [ पीओओडीबीसी] (https://pypi.python.org/pypi/pyodbc/)/[PYPYODBC] (https://pypi.python.org/pypi/pypyodbc)? यदि आपको अभी भी अपने लक्ष्य के लिए वीबीए की आवश्यकता है, तो कृपया समझाएं। – Tehscript

उत्तर

5

समाधान 1

या तो प्रवेश कॉम चल उदाहरण निकालते हैं और मिल/COM एपीआई के माध्यम से अजगर स्क्रिप्ट के साथ सीधे डेटा सेट:

VBA :

Private Cache 

Public Function GetData() 
    GetData = Cache 
    Cache = Empty 
End Function 

Public Sub SetData(data) 
    Cache = data 
End Sub 

Sub Usage() 
    Dim wshell 
    Set wshell = VBA.CreateObject("WScript.Shell") 

    ' Make the data available via GetData()' 
    Cache = Array(4, 6, 8, 9) 

    ' Launch the python script compiled with pylauncher ' 
    Debug.Assert 0 = wshell.Run("C:\dev\myapp.exe", 0, True) 

    ' Handle the returned data ' 
    Debug.Assert Cache(3) = 2 
End Sub 

अजगर (myapp.exe):

import win32com.client 

if __name__ == "__main__": 

    # get the running instance of Access 
    app = win32com.client.GetObject(Class="Access.Application") 

    # get some data from Access 
    data = app.run("GetData") 

    # return some data to Access 
    app.run("SetData", [1, 2, 3, 4]) 

समाधान 2

या उपयोग करने के लिए कुछ कार्यों का पर्दाफाश करने के एक COM सर्वर बनाएँ:

VBA:

Sub Usage() 
    Dim Py As Object 
    Set Py = CreateObject("Python.MyModule") 

    Dim result 
    result = Py.MyFunction(Array(5, 6, 7, 8)) 
End Sub 

अजगर (myserver.exe या myserver.py):

import sys, os, win32api, win32com.server.localserver, win32com.server.register 

class MyModule(object): 

    _reg_clsid_ = "{5B4A4174-EE23-4B70-99F9-E57958CFE3DF}" 
    _reg_desc_ = "My Python COM Server" 
    _reg_progid_ = "Python.MyModule" 
    _public_methods_ = ['MyFunction'] 

    def MyFunction(self, data) : 
    return [(1,2), (3, 4)] 


def register(*classes) : 
    regsz = lambda key, val: win32api.RegSetValue(-2147483647, key, 1, val) 
    isPy = not sys.argv[0].lower().endswith('.exe') 
    python_path = isPy and win32com.server.register._find_localserver_exe(1) 
    server_path = isPy and win32com.server.register._find_localserver_module() 

    for cls in classes : 
    if isPy : 
     file_path = sys.modules[cls.__module__].__file__ 
     class_name = '%s.%s' % (os.path.splitext(os.path.basename(file_path))[0], cls.__name__) 
     command = '"%s" "%s" %s' % (python_path, server_path, cls._reg_clsid_) 
    else : 
     file_path = sys.argv[0] 
     class_name = '%s.%s' % (cls.__module__, cls.__name__) 
     command = '"%s" %s' % (file_path, cls._reg_clsid_) 

    regsz("SOFTWARE\\Classes\\" + cls._reg_progid_ + '\\CLSID', cls._reg_clsid_) 
    regsz("SOFTWARE\\Classes\\AppID\\" + cls._reg_clsid_, cls._reg_progid_) 
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_, cls._reg_desc_) 
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\LocalServer32', command) 
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\ProgID', cls._reg_progid_) 
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOM', class_name) 
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\PythonCOMPath', os.path.dirname(file_path)) 
    regsz("SOFTWARE\\Classes\\CLSID\\" + cls._reg_clsid_ + '\\Debugging', "0") 

    print('Registered ' + cls._reg_progid_) 


if __name__ == "__main__": 
    if len(sys.argv) > 1 : 
    win32com.server.localserver.serve(set([v for v in sys.argv if v[0] == '{'])) 
    else : 
    register(MyModule) 

नोट आप वर्ग रजिस्टर करने के लिए और यह VBA.CreateObject के लिए उपलब्ध बनाने के लिए किसी भी तर्क के बिना एक बार स्क्रिप्ट चलाने के लिए करना होगा कि।

दोनों समाधान pylauncher के साथ काम करते हैं और पायथन में प्राप्त सरणी को numpy.array(data) के साथ परिवर्तित किया जा सकता है।

निर्भरता:

https://pypi.python.org/pypi/pywin32

+3

वाह, मैं पायथन का उपयोग नहीं करता लेकिन यह प्रभावशाली है कि ओएलई संस्करण पाइथन एरे के साथ इंटर-ऑपरेटिव है। –

+0

विकल्प 2 आपके द्वारा प्रदान किया गया सटीक (सटीक कोड) काम करता है, सिवाय इसके कि परिणाम किसी प्रकार का [variant] है (https://msdn.microsoft.com/VBA/Language-Reference-VBA/articles/variant-data-type) । मैं संस्करण को एक टेबल, रिकॉर्डसेट, या किसी अन्य ऑब्जेक्ट में कैसे बदलूं जिसका उपयोग मैं कर सकता हूं? या यह पहले से ही कुछ उपयोग करने योग्य रूप में है? मैं बस वीबीए से परिचित नहीं हूँ। –

+1

मार्शलर आपके द्वारा वापस लौटने के आधार पर पाइथन सरणी को 1 या 2 आयामों के सरणी में परिवर्तित करता है। 'GetRows' के साथ रिकॉर्डसेट से सीधे सरणी प्राप्त करना संभव है लेकिन मुझे नहीं लगता कि सीधे सरणी जोड़ना संभव है। इसलिए आपको प्रत्येक रिकॉर्ड को जोड़ने/अपडेट करने के लिए शायद सरणी पर लूप करना होगा। –

0

आप एक सरणी में सेट अपने रिकॉर्ड, पाशन द्वारा डबल

Dim arr(1 to 100, 1 to 100) as Double 

रूप dim'ed लोड करने का प्रयास कर सकते हैं, तो सूचक पहला तत्व ptr को पारित = VarPtr (arr (1, 1)) पायथन पर, जहां

arr = numpy.ctypeslib.as_array(ptr, (100 * 100,))?

लेकिन VBA अभी भी सरणी स्मृति

+0

रुको, वीबीए कॉलम-प्रमुख, numpy के रूप में सरणी स्टोर करता है - इसके विपरीत ... जब तक आपकी सरणी 1-dim नहीं है। – drgs

संबंधित मुद्दे