|
Source: ONLamp.com Another article of the series “Yet Another Perl 6 Operator” Binary '=' is no longer just a “fancy comma”. In Perl 6, it now constructs a Pair object that can, among other things, be used to pass named arguments to functions.
my $pair = (one = 1); $pair.isa(Pair) # Bool::True $pair.key # 'one' $pair.value # 1
Just like Perl 5, it autoquotes identifiers on its left. The operator provides item context to both sides. That explains
my @a = (1,2,3); my $p = @a = '123'; $p.isa(Pair) # Bool::True $p.key # (1,2,3) $p.value # '123'
because @a in item context coerces into the Array object itself, instead of the array size as Perl 5 did.
The fatarrow is right associative.
a = b = 'c' # a = (b = 'c')
Its precedence is now equivalent to assignment, although it does not actually do any assignment except in a notional sense. Unlike in Perl 5, '=' binds tighter than comma.
As expected (for consistency with how it worked in Perl 5), when a pair is flattened into a list context, it produces a list with its key and value.
my @kv = @(one = 1); $kv[0] # 'one' $kv[1] # 1
The fat arrow construct is accompanied by a lot of syntax to build pairs known as the adverbial forms of Pair notation.
Fat arrow Adverbial pair
a = 1 :a a = 0 :!a a = 'foo' :a
These are meant to provide handy forms to typical cases like expressing pairs with literal key and value. All adverbial forms are listed in Synopsis 02 .) That adverbial notation has a lot of ramifications in other parts of Perl 6 syntax, which favours them over the explicit fatarrow notation.
In the end, that means that this operator will not be so common in Perl 6 as it was in Perl 5, being available as the unsugared version to build pairs.
DISCLAIMERS
These articles are not intented as a deep presentation of Perl 6 features, but only as a quick demonstration. If you want more, get involved.
Some of the code here is unimplemented in current Perl 6 implementations.
The flaws of these articles is sole responsibility of the author.
Next article is due tomorrow (Dec 28, 2007).
LINKS
Synopsis S03, the official source
The introduction of this series
Official Perl 6 Documentation
Perl 6 in your browser
Source: ONLamp.com Another article of the series “Yet Another Perl 6 Operator” We already have seen two Perl 6 meta-operators in articles of this series: namely, the negate and the reduction operators. These are two of the five standard meta-operators of the language. What makes meta-operators interesting is how Perl automatically generates new operators from others (user-defined or builtins) with some straightforward semantics derived from the transformation of the base operators.
This time, we approach mutating operators, which are a shortcut for typical assignments where the assignment target and the first operand are the same variable.
my $s = 'foo'; $s x= 3; # $a = 'foofoofoo'
my $x; $x //= 'default'; # $x = 'default'
This is probably the most unexciting of Perl 6 meta-operators as this is well known to many programming languages since C. However as we told above, given appropriate conditions, Perl autogenerates such operators from existing ones (including user-defined), without the need for extra coding.
Infix operators may be turned into their corresponding assignment operators by suffixing with '='. The newly created operators work according to the usual correspondence
A op= B; equiv to A = A op B;
which limits the application of the meta-operator based on whether the left side (A) can function both as an rvalue and an lvalue simultaneously. That discards, for instance, mutating versions of relational operators.
The precedence of any assignment operator is forced to be the same as that of ordinary assignment, regardless of the precedence of the base operator.
Existing forms ending in '=' may not be modified with this meta-operator.
Note: Spaces are never allowed betwen any meta-operator and the operator being modified. Thus
$x x ='foo' # $x x (='foo') $a! == $b # probably a syntax error [ * ] # not the reduce operator for *
won’t probably do what you want. The relevant lexical rule here is that operators (including modified ones) are tokens which have to be recognized by the Longest-Token rule.
Next article is due tomorrow (Dec 27, 2007).
LINKS
The negate meta-operator
Reduction operators
Synopsis S03, the official source
The introduction of this series
Official Perl 6 Documentation
Perl 6 in your browser
Source: ONLamp.com Another article of the series “Yet Another Perl 6 Operator” And that’s time to take a look at another of the Perl 6 meta-operators: the reduction operator.
By surrounding with square brackets an (associative) infix operator, a new list operator is created.
[*] 1..10 # that's 1*2* *10 = 10! [~] # 'moose' - [~] is basically Perl 5 join [,] 'a'..'e' # - [,] is a list builder
The derived list operator produces an operation which reduces a list into a single item by repeatedly applying the original operator. Thus,
[+] 1, 2, 3 is (1 + 2) + 3 [~] is ('a' ~ 'b') ~ 'c' [**] 4, 3, 2 is 4 ** (3 ** 2)
where the last example emphasizes that the reduction operator associates the same way as the operator used.
The implementation of reduction operators brings some interesting issues to the semantics of Perl 6 operators. The obvious solution is to derive an operator like '[+]' from '+' by autogenerating code such as
proto prefix: (*@args) { my $accum = =@args; for =@args { $accum += $_; } return $accum; }
But that’s not the only alternative. Instead, the reduce operator [foo] can define the list operator and, at the same time, the foo infix operator. In this case, some expressions could be rewritten by the optimizer from their original form to another using the list operator.
# Original # Optimized $a foo $b [foo] $a, $b $a foo $b foo $c [foo] $a, $b, $c
Another case where the implementation of reduce operations bring extra knowledge to the interpretation of the original operator is defining the proper result of applying the reduction into an empty list. The result must be the identity property of the infix operator.
[*]() # 1 [+]() # 0 [~]() # '' [min]() # +Inf [X]() # []
The power of reduction operators will also allow to write an expression such as
[
to check that the elements of list @a are ordered under '. And that example takes us to the definition of reduce operators in the single-argument case. By default, if there is one argument, the built-in reduce operators return that one argument (which works for '+', '*', '~'). But that’s not good enough for operators like ' (and other relational operators) that don’t return the same type as they take. That means
[+] 42 # 42 [*] -1 # -1 # but [==] 'a' # True [
Then comparison operators return a boolean for either 1 or 0 arguments. Negated operators return Bool::False, while all the rest return Bool::True.
To get more glimpses on how Perl 6 will achieve all of this, you might like to read section “Reduction Operators” on Synopsis 03 .
Next article is due tomorrow (Dec 26, 2007).
LINKS
The negate meta-operator
Chained comparisons
Synopsis S03, the official source
The introduction of this series
Official Perl 6 Documentation
Perl 6 in your browser
Source: ONLamp.com Another article of the series “Yet Another Perl 6 Operator” If you are wondering how processing the lines of a file will look in Perl 6, the answer is something like this:
my $h = open '
(Yes, we need error handling yet. I just ommitted the details for brevity.) Things changed. In Perl 5, we usually did:
open my $h, ' ) { }
The IO API is more object-oriented and the open turned into a function which returns the open IO handle if successful. The magical while () (that was really a shortcut for while ( defined ($_ = ) ) ) is gone and the for construction with the iterate '=' operator is now recommended.
The iterate operator, which is prefix '=', does not get confused with the infix operator '=' for assignment (at least, not by the compiler). They are syntactically distinct based on what the Perl parser expects at every instant: if waiting a term, '=' would be taken to be prefix; if waiting an operator, '=' would mean assignment.
The IO objects happen to implement an “Iterable” role. So they act as iterators which are objects to run through the objects of a collection, keeping their current position (or state). Their basic operation is defined by providing a sensible behavior via a 'prefix:' implementation. So, iterators work as well for lists and other data structures which represent collections of items.
.say for =@list;
for =%hash.iterator - $p { $p.say; }
The examples above illustrate how invoking '=' in scalar context, produces each element of the iterated collection one at a time. If used in list context, the result of '=' turns into a lazy list, so they flatten to a list under demand. If needed, the eager list operator may be used to force immediate iteration to completion.
my $range = 1..1000; # ranges are iterators my @list = eager =$range; # immediately computed
my $indices = 1..*; my @list = eager =$indices; # blows up, expanding the infinite list
Notes for Perl 5 programmers: (1) The circumfix operator '' does not exist anymore. That syntax is now reserved as a handy synonym for the quoting construct qw and is part of a consistent set of quoting constructs for Perl 6.
# ('a', 'b', 'c')
(2) Also there is no fancy syntax for globs anymore. Use the builtin glob.
Next article is due Tuesday (Dec 25, 2007).
LINKS
Synopsis S03, the official source
The introduction of this series
Official Perl 6 Documentation
Perl 6 in your browser
Source: ONLamp.com Let’s say you customized your Zsh prompt by editing ~/.zshenv
#customize prompt: PROMPT=$'[%n@%m][H:%B%!%b][J:%B%j%b] '
You should see something like this: [root@bigbadunixbox][H:2487][J:0] If you want to see all 2487 lines of your Zsh history buffer do this:
history 1 | less
Source: ONLamp.com A modern, well-maintained web site should be valid, well-formed XML. If you want to rely on XML tools (XQuery, XSLT, etc.) for all your documentation and database access, you can now implement web sites with a new MVC framework named Flower. It hasn’t reached the 1.0 stage yet, and developer Thomas Lord warns that you’ll need help installing and building the system, but once you’ve got it going you can apply your XML tools to dynamic document creation.
Flower includes templates to create web pages that you can fill in by issuing XQuery calls and formatting results through XSLT. Another XML-based language called Flower Programming Language allows further processing. Flower uses Apache’s Xerces-C++ XML parser and passes results to the web server through Fast CGI. The underlying XML database engine is dbXML.
Because Flower incorporates a virtual machine that interprets XML, it can be seen as more than an MVC framework for web sites–perhaps a platform for very powerful distributed applications that use XML for data exchange, both client-server and server-server.
Lord promotes Flower’s minimalist approach, contrasting the interpreter’s 2,000 line with Ruby’s 92,000; it’s unclear to me whether the size of the interpreter matters on a web server. Flower’s scalability won’t be known until it sees some serious implementations. So it seems to me that it will be most attractive to developers who have pre-existing XML-heavy systems:
Publishers who have made the large investment of converting large, complex documents to XML and want to republish them in a variety of formats and venues
Sites exchanging data and using XML as their glue
Scientific environments with large datasets they are used to manipulating in XML (Lord mentions biology as an example)
I happen to like procedural languages, for the same reason I handle simple tasks at work myself rather than make formal requests to staff with official responsibilities for such tasks. Functional programming strikes me like the round-about process of filling out formal requests, and I know it can lead to powerful systems, but at several removes from my natural way of thinking. And a number of XML tools–notably XSLT–are functional in their set-up. But Flower looks like a way for the kinds of people who go to XML conferences (such as one I blogged earlier this month) can leverage their existing knowledge to produce functional web sites.
Source: ONLamp.com If you haven’t already seen it, check out Michael Trier’s new podcast “This Week in Django“. The first episode was good, so I’m looking forward to listening to the second. Subscribed!
Source: ONLamp.com The zipimport module can be used to import and run Python code found inside ZIP archives. Module: zipimport Purpose: Load Python code from inside ZIP archives. Python Version: 2.3 and later Description: The zipimport module implements the zipimporter class, which can be used to find and load Python modules inside ZIP archives. The zipimporter supports the “import hooks” API specified in PEP 302; this is how Python Eggs work. You probably won’t need to use the zipimport module directly, since it is possible to import directly from a ZIP archive as long as that archive appears in your sys.path. However, it is interesting to see the features available. Example: For the examples this week, I’ll reuse some of the code from last week’s discussion of zipfile to create an example ZIP archive containing some Python modules. If you are experimenting with the sample code on your system, run zipimport_make_example.zip before any of the rest of the examples. It will create a ZIP archive containing all of the modules in the zipimport example directory, along with some test data needed for the code below. Finding a Module: Given the full name of a module, find_module() will try to locate that module inside the ZIP archive.
import zipimport
importer = zipimport.zipimporter('zipimport_example.zip')
for module_name in [ 'zipimport_find_module', 'not_there' ]: print module_name, ':', importer.find_module(module_name)
If the module is found, the zipimporter instance is returned. Otherwise, None is returned.
$ python zipimport_find_module.py zipimport_find_module : not_there : None
Accessing Code: The get_code() method loads the code object for a module from the archive.
importer = zipimport.zipimporter('zipimport_example.zip') code = importer.get_code('zipimport_get_code') print code
The code object is not the same as a module object.
$ python zipimport_get_code.py at 0x57530, file "./zipimport_get_code.py", line 28
To load the code as a usable module, use load_module() instead.
importer = zipimport.zipimporter('zipimport_example.zip') module = importer.load_module('zipimport_get_code') print 'Name :', module.__name__ print 'Loader :', module.__loader__ print 'Code :', module.code
The result is a module object as though the code had been loaded from a regular import:
$ python zipimport_load_module.py at 0x57968, file "./zipimport_get_code.py", line 28 Name : zipimport_get_code Loader : Code : at 0x57968, file "./zipimport_get_code.py", line 28
Source: As with the inspect module, it is possible to retrieve the source code for a module from the ZIP archive, if the archive includes the source. In the case of the example, only zipimport_get_source.py is added to zipimport_example.zip (the rest of the modules are just the .pyc files).
importer = zipimport.zipimporter('zipimport_example.zip') for module_name in ['zipimport_get_code', 'zipimport_get_source']: source = importer.get_source(module_name) print '=' * 80 print module_name print '=' * 80 print source print
If the source for a module is not available, get_source() returns None.
$ python zipimport_get_source.py ================================================================================ zipimport_get_code ================================================================================ None
================================================================================ zipimport_get_source ================================================================================ #!/usr/bin/env python # # some lines omitted for brevity # import zipimport
importer = zipimport.zipimporter('zipimport_example.zip') source = importer.get_source('zipimport_get_code') print source
Packages: To determine if a name refers to a package instead of a regular module, use is_package().
importer = zipimport.zipimporter('zipimport_example.zip') for name in ['zipimport_is_package', 'example_package']: print name, importer.is_package(name)
In this case, zipimport_is_package came from a module and the example_package is, well, a package.
$ python zipimport_is_package.py zipimport_is_package False example_package True
Data: There are times when source modules or packages need to be distributed with non-code data. Images, configuration files, default data, and test fixtures are just a few examples of this. Frequently, the module __path__ is used to find these data files relative to where the code is installed. For example, with a normal module you might do something like:
import os import example_package data_filename = os.path.join(os.path.dirname(example_package.__file__), 'README.txt') print data_filename, ':' print open(data_filename, 'rt').read()
The output will look something like this, with the path changed based on where the PyMOTW sample code is on your filesystem.
$ python zipimport_get_data_nozip.py /Users/dhellmann/Documents/PyMOTW/in_progress/zipimport/example_package/README.txt : This file represents sample data which could be embedded in the ZIP archive. You could include a configuration file, images, or any other sort of non-code data.
If the example_package is imported from the ZIP archive instead of the filesystem, that method does not work:
import sys sys.path.insert(0, 'zipimport_example.zip')
import os import example_package print example_package.__file__ data_filename = os.path.join(os.path.dirname(example_package.__file__), 'README.txt') print data_filename, ':' print open(data_filename, 'rt').read()
The __file__ of the package refers to the ZIP archive, and not a directory. So we cannot just build up the path to the README.txt file.
$ python zipimport_get_data_zip.pyzipimport_example.zip/example_package/__init__.pyc zipimport_example.zip/example_package/README.txt : Traceback (most recent call last): File "zipimport_get_data_zip.py", line 41, in print open(data_filename, 'rt').read() IOError: [Errno 20] Not a directory: 'zipimport_example.zip/example_package/README.txt'
Instead, we need to use the get_data() method. We can access zipimporter instance which loaded the module through the __loader__ attribute of the imported module:
import sys sys.path.insert(0, 'zipimport_example.zip')
import os import example_package print example_package.__file__ print example_package.__loader__.get_data('example_package/README.txt')
$ python zipimport_get_data.py zipimport_example.zip/example_package/__init__.pyc This file represents sample data which could be embedded in the ZIP archive. You could include a configuration file, images, or any other sort of non-code data.
Although __loader__ is not set for modules not imported via zipimport. References: PEP 273 - Import Modules from ZIP Archives PEP 302 - New Import Hooks Python Eggs inspect module PyMOTW: inspect Python Module of the Week Home Download Sample Code
Technorati Tags: python, PyMOTW
|