Not Quite Python (NQPy)


Not Quite Python (NQPy) is a subset of the Python computer language used to implement actions in RepastPy. This document is not intended as either a Python tutorial or reference, but as a quick overview of NQPy for those with some programming experience. If you have never programmed before, what follows may be less than clear. See the Python for Beginners page at the Python site for some help getting started. In addition to the various resources in the site above, Python also includes a tutorial. See this.

Working with NQPy

NQPy is a small subset of Python and thus lacks, at the moment, many of the features of Python. It is primarily intended as a relatively easy way to specify agent behavior and borrows Python's syntax in order to accomplish this. Consequently, you cannot define classes, or functions with NQPy as these are already defined by RepastPy. NQPy is used to implement the body of these defined methods. In addition to the above, python style lists, dictionaries, and tuples are not supported, although they may be in the future. Their Java equivalents can be used instead.

  • Variables.

    You work with variables as you do in Python. Variables are untyped (unlike Java), although the compilier will warn you if you attempt an unsupported operation on a variable.

    variable assignment:

    a = 3
    print a
    b = "hello"
    print b
    print "b =", b

    assigns the integer value 3 to a variable named a and prints the value of a to the console. Similarly, the String "hello" is assigned to the variable b and printed to the console. The last line prints, "b = hello" to the console. Note that Strings in NQPy are Java Strings and you can call String methods on them.

  • Objects and Methods.

    Most data in NQPy (and Python) are objects. Objects have methods and attributes (instance variables). In the case of NQPy, these methods are either RepastPy component actions defined by the user, or inherited from their Java parent object. Attributes may be parameters predefined by RepastPy, Java parent fields, or parameters defined by the user. For example, a Default Network Node has a predefined action called step, and a perdefined attribute called model (a reference to its associated model).

    Attributes and methods are referenced using the dot (".") operator. The object reference is on the left hand side and the attribute or method is on the right hand side. The object reference is always necessary. If you wish to reference an action / method or attribute from within the component that defines it, the object reference is self. For example if I want to call the getAgentList method on a Default Network Node component's model attribute from within that Default Network Node's step method, I would write

    list = self.model.getAgentList()

  • NQPy and Java.

    NQPy was designed to operate seemlessly with Java, and for the most part it does. Java objects are created and used just like any other RepastPy / NQPy object. For example,

    list = ArrayList()
    list.add("hello")
    print list.get(0)

    This creates an ArrayList (for those that know Java, note the lack of the new keyword), adds the String "hello" to it, retrieves that String and prints it out. You can treat getters and setters in Java as if they were true properties. For example, if an Object has getType() and setType(int) methods, then the following will work:

    val = obj.type
    obj.type = 3

    The first of these actually calls getType() and the second calls setType() and passes in the 3. In addition, python like list indexers are also available for class that extends java.util.List, ArrayList for example.

    list = ArrayList()
    list.add("hello")
    print list[0]

    Here, the list[0] is translated into a call to list.get(0). Python-like slicing is also available.

    list = ArrayList()
    list.add("first")
    list.add("second")
    list.add("third")
    list.add("fourth")

    print list[1:3]

    The last line here will result in "[second, third]" being printed to the console. In effect, the slicing produces a new ArrayList(). Casting a feature not found (and not necessary) in Python is available in NQPy. So,

    a = (String)list.get(0)

    casts the element retrieved from the list to String. Casting means the compiler will treat this element as whatever you cast it to, in this case a String.

  • Flow Control.

    Flow control in NQPy is, by and large, identical to that in Python. A conditional looks like:

    if _expression_:
      statements

    elif _expression_:
      statements

    else:
      statements

    Here _expression_ is some expression that evaluates to true or false. statments is a collection of 1 or more NQPy statements that are executed if _expression_ is true. The colon indicates the beginning of the conditional block of statements. The level of indentation indicates which statements are part of the block. So for example,

    if a:
      print a
      a = a + 1
    b = 3

    "print a" and "a = a + 1" will be executed if a is true, and "b = 3" will be executed in every case. Had "b = 3" been indented to the same level as "print a" then it too would only be executed if a was true.

    Like Python, 0 is equivalent to false, and any other number is true. Similarly, empty Strings are also considered false.

    Iterating through loops is also done in a Python like style and looks like:

    for x in list:
      statements

    This will iterate through every element in list, assigning each element in that list to the variable x and executing the statements in the code block.

    Assume we have a list s of Strings "fred", "sam", and "cormac", then

    s = ArrayList()
    s.add("fred")
    s.add("sam")
    s.add("cormac")

    for name in s:
      print name

    This will print "fred", "sam", and "cormac" out to the console. NQPy adds the ability for an embedded cast to the for loop. This looks like:

    for x as a in list:
      statements

    For example,

    s = ArrayList()
    s.add("fred")
    s.add("sam")
    s.add("cormac")

    for name as String in s:
      print name.length()

    This will print the length of each String in s. Without the cast, the compiler will treat each element in the list as a Java Object and report an error because it can't find the method length() in Object.

    The python range function is also supported. When used on its own range will produce a List of Integers. For example,

    a = range(10)

    will produce a java.util.List of Integers from 0 to 9. When used as part of a loop, it will produce an int value. For example,

    for x in range(list.size()):
      print list.get(x)

    where x here is an int value.

    The keywords continue, and break are also supported as are while loops, which look like:

    while _expression_:
      statements

    As long as _expression_ is true, then statements will be executed.

  • Comments.

    As in Python a comment is a line prefixed by "#"

    # this is a comment
    print "hello"

    Any line prefixed by "#" is ignored by the compiler.