Jump to content

Hello Community!

This Saturday, April 11, from 9am – 1pm EDT we will be performing maintenance on the Vectorworks Community Board. During this time, the site will be unavailable.

MaxStudio

Global Variables with Imported Functions

Recommended Posts

I like to deconstruct my larger more complicated scripts into smaller files.  It helps me stay organized.

I'm trying to get imported functions to use global variables that I have created but, it's not working the way I like and I'm not sure why.

I have a main script that defines the global variables.  The main script also imports demo.py and calls the function draw.

The demo.py script is basically an if/else test.  I've imported another file named shapes.py which has functions to draw shapes.

-If the global variable 'w' is less than 6 call function myrectangle() from shapes.py

-If the global variable 'w' is greater than 6 call function myoval() from shapes.py

-if the global variable 'w' is equal to 6 print "Hello World" in a Alert Box.

When i try to run i get: NameError: global name 'x' is not defined.  I thought that if I had global variables defined in the main script i would be able to use them in the imported functions.  Am I doing something wrong?

main.py

import vs
import demo

w=vs.PLineLength
h=vs.PBoxWidth
x = 0
y = 0
y = y-h/2

demo.draw()

demo.py

import vs
import shapes

def draw():

	vs.PenSize(2);

	if w < 6:

		shapes.myrectangle()

	elif w > 6:

		shapes.myoval()

	elif w == 6:

		vs.AlrtDialog('Hello world.')

shapes.py

import vs

def myrectangle():

	vs.Rect(x,y, x+w,y+h)

def myoval():

	vs.Oval(x,y, x+w,y+h)

 

Edited by MaxStudio

Share this post


Link to post

You have your scope backwards. In main, you can call a variable defined in one of your imported modules, but not the other way around. In python, an imported module should be able to function as stand-alone scripts.

Your solution would be to design your functions so they accept X, y, w, and h as arguments. 

The only real reason to divide your code into separate files is if there are portions you want to reuse for other projects (and if that is the case, they shouldn't be dependent on global variables anyway). You can use classes and functions to organize your code within one file. 

HTH,

Josh

  • Like 1

Share this post


Link to post

The scope of each module (main/demo/shapes) are limited to its namespace.

Global variables defined in 'main' are still restricted to main even if its imported.

The x's and y's you're referring to in the shapes.py module are not getting to x and y in the main module because of this.

 

Also everything Josh mentioned, ie, the only reason you'd be separating files etc.

 

more here:

http://www.python-course.eu/python3_namespaces.php

 

Edited by twk
  • Like 1

Share this post


Link to post

Some tips:

- A file is a module, which is a unit with stuff that work together. You'll never split it up. Things that belong together in a module should stay together.

- Never use global variables, there are always better ways. Functions should almost always stand on their own, unless it's a function inside a class that needs the 'state' of the class.

- use good names for your vars, so it's clear what they are, if you revisit your code years later, you want to know how it works, good naming will help with that.

- use oop, so that the code is more clear and each thing is self-contained. It will make your code better, readable, etc....

Here is a better version of your code (at the top of my head, did not test it, depending on what you are trying to achieve, this could be made far better, some imports are missing, i'm not using my standard IDE right now.)

import vs

class Shape(object, metaclass=ABCMeta):
    
    def __init__(self, origin: tuple, width: float, height: float):
        """
        :type origin: (float, float)
        """
        self.__origin = {x: origin[0], y: origin[1]}
        self.__width = width
        self.__height = height
    
    @property
    def origin(self) -> dict:
        return self.__origin
        
    @property
    def width(self) -> float:
        return self.__width
        
    @property
    def height(self) -> float:
        return self.__height
    
    @abstractmethod
    def draw(self):
        pass
    
    
class Rectangle(Shape):
    
    def draw(self):
        vs.Rect(self.origin.x, self.origin.y, self.origin.x + self.width, self.origin.y + self.height)
        
        
class Oval(Shape):
    
    def draw(self):
        vs.Oval(self.origin.x, self.origin.y, self.origin.x + self.width, self.origin.y + self.height)


def run():
    
    plugin_length = vs.PLineLength
    plugin_height = vs.PBoxWidth
    
    x = 0
    y = 0 - plugin_height / 2
    
    vs.PenSize(2)
    
    if plugin_length == 6:
        vs.AlrtDialog('Hello world.')
        return
    
    my_shape_class = Rectangle if plugin_length < 6 else Oval
    my_shape = my_shape_class((x, y), plugin_length, plugin_height)
    my_shape.draw()


# This should not be needed here, you can call it in your plugin file itself.
run()

 

  • Like 1

Share this post


Link to post

In the past I have run into a problem where the scripting window limits the amount of code I can put in a plugin.  That lead me to start using 'Includes"  after which,  I was no longer limited.  The problem is that some of my codes end up being very long and I do not like scrolling through a ton of code just to find what I'm working on. 

 

For example, If I have a code that generates 10 types of doors.  In the past I would generate variables for door width/height/wall thickness.  (i would consider those to be global variables)  All of the door types would use those variables.  But not all of the doors would be the same.  Some would be solid, some would be glass and some would be paneled.   To create these individual door types I would have a set of Local Variables for each.   In the past i would create a main include file that sets global attributes and draws global objects.  When the user selected a door type the corresponding include file would load to draw the selected door.  Having the separate "include" file would allow me to work on a simple code to generate each individual door type.  I wouldn't need to work on one large file that includes all 10 doors.  When the code was complete I would lock it within vectorworks so that it would run as a single plugin file.

 

I'm having a little trouble understanding the best way to accomplish this with python.  I'm not a paid programmer and Im learning as I go.  I'm trying to get a better grip on python as we are moving from Vectorworks 2008 to 2016.  That being said, I find it much easier to comprehend looking at small pieces of code rather than a monster.

Share this post


Link to post

Organizing your code into functions can help you break down the parts into manageable pieces. I have found this with any programming language. Good commenting and visual dividers helps as well. 

 

You may want to invest in a good text editor. I've used BBEdit for years, but there are others like eclipse that are designed specifically for code development. They all recognize function definitions and let you quickly skip to a function via a menu. 

 

Includes in VS and Python work completely differently. In VS an include is a virtual cut and paste of code from an external file. In Python, you're including libraries of functions data structures, and constants that are available for use. Your included modules don't flow in any way with your code, and they should function as a contained object with its own namespace. You can, of course pass data either as attributes of an object instance or arguments of a function. 

 

-Josh 

Share this post


Link to post
11 hours ago, MaxStudio said:

 That being said, I find it much easier to comprehend looking at small pieces of code rather than a monster.

 

A monster? That was a minimal version. You'll have to think differently in Python then you did in VectorScript. Working OOP, you can split things up in very small pieces, and then let them work together. Every piece has it's own responsibility, and this makes your code more clear and better to read. You only have to read the main flow, and if you are interested in the details, you can look deeper. For example, if you look at the run in it, you can read was is going on, without needing to know the details, you know what will be drawn, not how. If you want to know how, you can look deeper.

Edited by Dieter @ DWorks
  • Like 1

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


 

7150 Riverwood Drive, Columbia, Maryland 21046, USA   |   Contact Us:   410-290-5114

 

© 2018 Vectorworks, Inc. All Rights Reserved. Vectorworks, Inc. is part of the Nemetschek Group.

×
×
  • Create New...