User:Orso.b.schmid: Difference between revisions

From Vectorworks Developer
Jump to navigation Jump to search
(add link to reddit)
(add documentation about python caching)
Line 6: Line 6:
Open the terminal on your Mac and write
Open the terminal on your Mac and write
  python
  python
try snippets there or in an editor of your choice
try snippets there (or in an editor of your choice if you prefer)


== Lists ==
== Lists ==
Line 14: Line 14:
months = "Jan Feb Mar Apr May Jun Jul"
months = "Jan Feb Mar Apr May Jun Jul"
months = months.split() # no splitter defined and it will use the empty space --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul']
months = months.split() # no splitter defined and it will use the empty space --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul']
months[2] # note that the index is 0-based --> 'Mar'
months[2] # --> 'Mar' note that the index is 0-based
months2 = "Jan, Feb, Mar, Apr, May, Jun, Jul" # overwrite a copy
months2 = "Jan, Feb, Mar, Apr, May, Jun, Jul"
months2.split(', ') # use comma and empty space as splitter --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul']
months2.split(', ') # --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] use comma and empty space as splitter
months.append('Jul') # append adds an item to a list --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul']
months.append('Jul') # --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] append adds an item to a list
months.pop() # pop fetches the last item of a list --> 'Jul'
months.pop() #- -> 'Jul' pop fetches the last item of a list
', delirious '.join(months) # --> 'Jan, delirious Feb, delirious Mar, delirious Apr, delirious May, delirious Jun, delirious Sep'
', sunny '.join(months) # --> ', sunny Jan, sunny Feb, sunny Mar, sunny Apr, sunny May, sunny Jun, sunny Sep'
'-'.join(months[1:3]) # --> 'Feb-Mar'
'-'.join(months[1:3]) # --> 'Feb-Mar'
del months[2] # --> ['Jan', 'Feb', 'Apr', 'May', 'Jun', 'Jul']
del months[2] # --> ['Jan', 'Feb', 'Apr', 'May', 'Jun', 'Jul']
Line 26: Line 26:


== Increment a var ==
== Increment a var ==
So far I have spent a really inordinate amount of time trying to increment a counter. In VS one does it like this:
So far I have spent a really inordinate amount of time trying to increment a counter from within a calllback routine. In VS one does it like this:
 
<code lang="pas">cnt := cnt +1; { variable cnt is incremented }</code>
<code lang="pas">cnt := cnt +1; { variable cnt is incremented }</code>


Line 34: Line 35:
PROCEDURE Test;
PROCEDURE Test;
VAR
VAR
     cnt : INTEGER; { variable scope here is global }
     cnt : INTEGER; { variable scope here is global for this script }


    { subroutine fitting ForEachObject }
    { callback subroutine fitting ForEachObject }
     PROCEDURE DoSomething(h: HANDLE);
     PROCEDURE DoSomething(h: HANDLE);
         BEGIN
         BEGIN
             { ... do something }
             { ... do something }
             cnt := cnt +1; { variable is incremented }
             cnt := cnt +1; { global variable is incremented }
         END;
         END;
BEGIN
BEGIN
Line 50: Line 51:
</code>
</code>


How do I get this done in Python? It's not as easy as it looks like. I thought that one did it like this:
How do I get this done in Python? It's not as easy as it looks like. I thought that this would work:
 
<code lang="py">cnt += 1</code>
<code lang="py">cnt += 1</code>


Line 56: Line 58:


<code lang="py">
<code lang="py">
DoSomething(h):
import vs;
  # ... do something
cnt = 0 # explicit is better than implicit :)
  cnt += 1 # variable is incremented
 
def DoSomething(h):
    # ... do something
    cnt += 1 # variable should be incremented


cnt = 0 # explicit is better than implicit :)
vs.ForEachObject(DoSomething, '(ALL)')  # pick objects by criteria, there the variable cnt will increment
vs.ForEachObject(DoSomething, ("ALL"))  # pick objects by criteria, there the variable cnt will increment
vs.AlrtDialog(vs.Concat('Did something ', cnt, ' times.'))
vs.AlrtDialog(vs.Concat('Did something ', cnt, ' times.'))
</code>
</code>


but this doesn't work when the variable is not local where it runs. In my particular case it doesn't work if I try to increment it in '''DoSomething'''. It rises some error (UnboundLocalError: local variable can't be referenced before assignment). Obviously the variable can't be modified from a subroutine, but I can't turn DoSomething into a function outputting an integer, otherwise it won't fit the required callback syntax expected by [[VS:ForEachObject| ForEachObject]]
Error: UnboundLocalError: local variable can't be referenced before assignment
 
But it doesn't work from within '''DoSomething''' and I can't turn DoSomething into a function outputting an integer, otherwise it won't fit the required callback syntax expected by [[VS:ForEachObject| ForEachObject]]
 
Searching the web I found out that I am not alone in this misery. See [http://www.reddit.com/r/Python/comments/wbs1o/best_way_to_increment_of_1_in_python this], LOL. This comment wins, on my opinion: "We can make Python ask Perl to ask C."
 
Now I'll try this mysterious approach treating the variable as a list (http://bytes.com/topic/python/answers/46419-how-does-one-write-function-increments-number source):
<code lang="py">
def incr(counters): counters[0] += 1
 
counters =[100]
incr(counters)
print counters [101]
</code>
 
== Python caching ==


Searching the web I found [http://www.reddit.com/r/Python/comments/wbs1o/best_way_to_increment_of_1_in_python this]. LOL. This comment wins, on my opinion: "We can make Python ask Perl to ask C."
From the SDK, introduced by VW 2014:
varPersistentPythonEngine = 412 { Boolean }
''When True the Python engine is the same for the execution of all scripts, this solves some issues with Py_Initialize and Py_Finalize. For example, when debugging externally python leaves threas that cause crash if Py_Initialize and Py_Finalize is used for each script call. So, this allows the engine to be preserved between calls, however Vectorworks will delete all custom modules and objects defined in the engine prior each execution.''

Revision as of 07:46, 18 May 2015

Ciao,

I am Orso, an Italian Vectorscripter since many years. I feel very comfortable with Vectorscript (from now on: VS) but will now switch over to Python for even more power. I will try to share here comments, problems -and solutions- from the point of view of a non-programmer. --Orso.b.schmid (talk) 08:13, 17 May 2015 (EDT)

Open the terminal on your Mac and write

python

try snippets there (or in an editor of your choice if you prefer)

Lists

Lists are powerful in Python, below some fascinating lists manipulations. They remind me of Applescript:

months = "Jan Feb Mar Apr May Jun Jul"
months = months.split() # no splitter defined and it will use the empty space --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul']
months[2] # --> 'Mar' note that the index is 0-based
months2 = "Jan, Feb, Mar, Apr, May, Jun, Jul"
months2.split(', ') # --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] use comma and empty space as splitter 
months.append('Jul') # --> ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] append adds an item to a list 
months.pop() #- -> 'Jul' pop fetches the last item of a list
', sunny '.join(months) # --> ', sunny Jan, sunny Feb, sunny Mar, sunny Apr, sunny May, sunny Jun, sunny Sep'
'-'.join(months[1:3]) # --> 'Feb-Mar'
del months[2] # --> ['Jan', 'Feb', 'Apr', 'May', 'Jun', 'Jul']
months = {1: 'Jan', 2: 'Feb', 3: 'Mar'} # --> {1: 'Jan', 2: 'Feb', 3: 'Mar'}

Increment a var

So far I have spent a really inordinate amount of time trying to increment a counter from within a calllback routine. In VS one does it like this:

cnt := cnt +1; { variable cnt is incremented }

For example:

PROCEDURE Test;
VAR
    cnt : INTEGER; { variable scope here is global for this script }

    { callback subroutine fitting ForEachObject }
    PROCEDURE DoSomething(h: HANDLE);
        BEGIN
            { ... do something }
            cnt := cnt +1; { global variable is incremented }
        END;
BEGIN
    cnt := 0; { explicit is better than implicit :) }
    ForEachObject(DoSomething, (ALL)); { pick objects by criteria, there the variable cnt will increment }
    AlrtDialog(Concat('Did something ', cnt, ' times.'));
END;
Run(Test);

How do I get this done in Python? It's not as easy as it looks like. I thought that this would work:

cnt += 1

For example:

import vs;
cnt = 0 # explicit is better than implicit :)

def DoSomething(h):
    # ... do something
    cnt += 1 # variable should be incremented

vs.ForEachObject(DoSomething, '(ALL)')  # pick objects by criteria, there the variable cnt will increment
vs.AlrtDialog(vs.Concat('Did something ', cnt, ' times.'))
Error: UnboundLocalError: local variable can't be referenced before assignment

But it doesn't work from within DoSomething and I can't turn DoSomething into a function outputting an integer, otherwise it won't fit the required callback syntax expected by ForEachObject

Searching the web I found out that I am not alone in this misery. See this, LOL. This comment wins, on my opinion: "We can make Python ask Perl to ask C."

Now I'll try this mysterious approach treating the variable as a list (http://bytes.com/topic/python/answers/46419-how-does-one-write-function-increments-number source):

def incr(counters): counters[0] += 1

counters =[100]
incr(counters)
print counters [101]

Python caching

From the SDK, introduced by VW 2014:

varPersistentPythonEngine = 412 { Boolean }

When True the Python engine is the same for the execution of all scripts, this solves some issues with Py_Initialize and Py_Finalize. For example, when debugging externally python leaves threas that cause crash if Py_Initialize and Py_Finalize is used for each script call. So, this allows the engine to be preserved between calls, however Vectorworks will delete all custom modules and objects defined in the engine prior each execution.