473,777 Members | 1,732 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Weaver/Yarn Pattern in Python

Hello everybody,

I am using Python to prototype a compression algorithm for tree-shaped
data, e.g., XML data or abstract syntax trees. I use a variant of the
visitor design pattern--called weaver/yarn pattern--in order to
traverse the tree that is being compressed or decompressed. I do not
know of any other interesting application of the weaver/yarn pattern,
but it seems like a very suitable subject of study for different
implementation strategies. Essentially, I am asking for input on my
design decisions.

First, let me give you a simple example of the traditional visitor
pattern. The following diagram illustrates a depth-first traversal of
a mini tree by a visitor. The basic idea is that the tree accepts a
visitor and helps it to do a kind of type-dispatch based on the kind
of nodes.
Tree data structure (nodes a,b,c of types A,B,C)

a:A
/ \
/ \
b:B c:C

Nested calls
------------
Call location Call stack

main: a.accept(v)
A: v.visitA(a)
V: b.accept(v)
B: v.visitB(b)
V: c.accept(v)
C: v.visitC(c)
class A(Node):
def accept(self, visitor):
visitor.visitA( self)
class B(Node):
def accept(self, visitor):
visitor.visitB( self)
class C(Node):
def accept(self, visitor):
visitor.visitC( self)
class Visitor:
"Perform specific tasks while visiting certain nodes"
def visitA(self, a):
for k in a.kids:
k.accept(self)
def visitB(self, b):
pass
def visitC(self, c):
pass

The advantage of this ping-pong between the tree and visitor v is that
v encapsulates related processing instructions. Several different
visitors can be maintained independently of each other and without
forcing changes to the tree node classes. The tree nodes only need to
provide a node.accept(vis itor) method. Type-checking can ensure
the match between the visitor and the tree data structure.

Normally, visitors encapsulate different processing passes, which are
run one after the other, each time traversing the whole tree. I have
implemented the compression of trees as several (sub)visitors c1..cN
even though they could have been implemented as one big visitor.
Besides the easy recombinability of visitors this has the added
advantage that I can use the same visitors for compression and
decompression where this is appropriate.

But now I have a problem when decompressing. In order to run one
visitor after another the first one expects to traverse the whole
tree. But this is impossible in case of a decompressor. It lies in
the very nature of the application that the tree is being constructed
while the visitors work on it. Conceptually the solution is easy.
The decompression subvisitors d1..dM have to process the partially
available tree upto the point of traversal where it is available. At
each node execution has to iterate over the applicable code of d1..dM
in the given order. This necessitates a decomposition of visitors
into something that we call yarns and these yarns are weaved by one
visitor, which we call the weaver. Thus the name "Weaver/Yarn
Pattern" for this variation of the visitor pattern.

The following exemplifies my current implementation of the w/y pattern
for a recursive descent (ie depth-first traversal) visitor. For each
(sub)visitor d1..dM the former d<i>.visitX(x) method is divided into
several y.weaveX_...() methods. At entry and exit the weaver invokes
y.weaveX_First( ) and y.weaveX_Last() . Each descent into a child is
surrounded by y.weaveX_Before (kidno) and y.weaveX_After( kidno) method
calls.

class Yarn:
# methods replacing visitA(..)
def weaveA_First(se lf, a):
pass
def weaveA_Before(s elf, a, kidno):
pass
def weaveA_After(se lf, a, kidno):
pass
def weaveA_Last(sel f, a):
pass
# methods replacing visitB(..)
def weaveB_First(se lf, a):
pass
def weaveB_Last(sel f, a):
pass
# methods replacing visitC(..)
...
class Weaver:
"A special visitor which weaves yarns"
def __init__(self, yarns):
self.yarns = yarns
def visitA(self, a):
for y in self.yarns:
y.weaveA_First( a)
for i, k in enumerate(a.kid s):
for y in self.yarns:
y.weaveA_Before (a, i)
k.accept(self)
for y in self.yarns:
y.weaveA_After( a, i)
for y in self.yarns:
y.weaveA_First( a)
def visitB(self, b):
for y in self.yarns:
y.weaveA_First( b)
for y in self.yarns:
y.weaveA_First( b)
def visitC(self, b):
...

By now it should be obvious that the boilerplate for this approach
becomes quite extensive and it would be desirable to reduce it. To
mitigate the problem I did three things:

- Automatically generate templates for yarn classes. The actual code
can be filled in. Disadvantage: No convenient way to deal with
changes to the tree data structure.

- The node.accept(wea ver) methods are changed to call a "generic"
weaver.weave(no de) method (instead of weaver.visitX(n ode)), which
hackishly constructs all the calls to the yarns by assembling the
method names from the __class__.__nam e__ and one of "First", "Last",
"Before", and "After".

This solution does pretty much what I want:

- Writing selected yarn methods allows me to express with little
overhead /what/ code to execute /when/ in the weaving process.

- Once the weaver/yarn interaction machinery is set up correctly, the
debugger points me to real code in case of bugs. This is an
advantage over approaches that create classes at runtime, e.g., use
of metaclasses or the "new" module.

OTOH, I'm not perfectly happy with this solution since it's totally
"hackish". For example, I have to use a function, hand-written
specifially for this purpose, in order to "type-check" the
correspondence of the tree types and the yarns.

Maybe Python is not the right language for an elegant solution and I
should look at more rigorously or differently typed languages, but I
thought it's worth presenting my case here and asking what other
python hackers think. Maybe there is another more pythonic way to do
this?

I looked into several of python's features, but to no avail.
Iterators don't seem to play well with yarns (especially if you try to
thread objects thru the yarns to support synthesized/inherited
attributes a known from attribute grammars). I also looked at
metaclasses in order to reduce the boilerplate but that did pay off
either.

There are certainly other languages and language concepts, which offer
interesting implementation alternatives:

- Dylan's generic functions seems to be a a good match for my problem,
which allows me to get around the method name mangling in
weaver.weave(no de). Anybody an idea for a nice emulation of generic
functions in python? :)

- Lazy evaluation as provided by Haskell (or even Ocaml) seems to make
the traveral by several visitors unnecessary, but I'm not yet
convinced enough of this approach to start a full reimplementatio n.

- Systems for attribute grammar evaluation seem to address some of my
general concerns, but I am afraid that they might constrain me too
much.

If you're still reading this I'm impressed ;-) and I would be very
happy to hear what you think.

-Chris

--
Chris Stork <> Support eff.org! <> http://www.ics.uci.edu/~cstork/
OpenPGP fingerprint: B08B 602C C806 C492 D069 021E 41F3 8C8D 50F9 CA2F

Jul 18 '05 #1
1 2420
Christian Stork wrote:
Hello everybody,

I am using Python to prototype a compression algorithm for tree-shaped
data, e.g., XML data or abstract syntax trees. I use a variant of the
visitor design pattern--called weaver/yarn pattern--in order to
traverse the tree that is being compressed or decompressed. I do not
know of any other interesting application of the weaver/yarn pattern,
but it seems like a very suitable subject of study for different
implementation strategies. Essentially, I am asking for input on my
design decisions.

First, let me give you a simple example of the traditional visitor
pattern. The following diagram illustrates a depth-first traversal of
a mini tree by a visitor. The basic idea is that the tree accepts a
visitor and helps it to do a kind of type-dispatch based on the kind
of nodes.
....
The advantage of this ping-pong between the tree and visitor v is that
v encapsulates related processing instructions. Several different
visitors can be maintained independently of each other and without
forcing changes to the tree node classes. The tree nodes only need to
provide a node.accept(vis itor) method. Type-checking can ensure
the match between the visitor and the tree data structure.

Normally, visitors encapsulate different processing passes, which are
run one after the other, each time traversing the whole tree. I have
implemented the compression of trees as several (sub)visitors c1..cN
even though they could have been implemented as one big visitor.
Besides the easy recombinability of visitors this has the added
advantage that I can use the same visitors for compression and
decompression where this is appropriate.

But now I have a problem when decompressing. In order to run one
visitor after another the first one expects to traverse the whole
tree. But this is impossible in case of a decompressor. It lies in
the very nature of the application that the tree is being constructed
while the visitors work on it. Conceptually the solution is easy.
The decompression subvisitors d1..dM have to process the partially
available tree upto the point of traversal where it is available. At
each node execution has to iterate over the applicable code of d1..dM
in the given order. This necessitates a decomposition of visitors
into something that we call yarns and these yarns are weaved by one
visitor, which we call the weaver. Thus the name "Weaver/Yarn
Pattern" for this variation of the visitor pattern.

The following exemplifies my current implementation of the w/y pattern
for a recursive descent (ie depth-first traversal) visitor. For each
(sub)visitor d1..dM the former d<i>.visitX(x) method is divided into
several y.weaveX_...() methods. At entry and exit the weaver invokes
y.weaveX_First( ) and y.weaveX_Last() . Each descent into a child is
surrounded by y.weaveX_Before (kidno) and y.weaveX_After( kidno) method
calls.
....
By now it should be obvious that the boilerplate for this approach
becomes quite extensive and it would be desirable to reduce it. To
mitigate the problem I did three things:

- Automatically generate templates for yarn classes. The actual code
can be filled in. Disadvantage: No convenient way to deal with
changes to the tree data structure.

- The node.accept(wea ver) methods are changed to call a "generic"
weaver.weave(no de) method (instead of weaver.visitX(n ode)), which
hackishly constructs all the calls to the yarns by assembling the
method names from the __class__.__nam e__ and one of "First", "Last",
"Before", and "After".

This solution does pretty much what I want:

- Writing selected yarn methods allows me to express with little
overhead /what/ code to execute /when/ in the weaving process.

- Once the weaver/yarn interaction machinery is set up correctly, the
debugger points me to real code in case of bugs. This is an
advantage over approaches that create classes at runtime, e.g., use
of metaclasses or the "new" module.

OTOH, I'm not perfectly happy with this solution since it's totally
"hackish". For example, I have to use a function, hand-written
specifially for this purpose, in order to "type-check" the
correspondence of the tree types and the yarns.

....

Have a look at aspect oriented programming:

http://www.ccs.neu.edu/home/lieber/AOP.html

In theory it sounds like a good match for what you need.

I don't know how well Python supports this, perhaps you
can use a metaclass for this, but I'm not sure.
Have fun,
Ype
--
email at xs4all.nl
Jul 18 '05 #2

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
2573
by: BalyanM | last post by:
Hi, I am new to python.I am using it on redhat linux 9. I am interested to run python on a sun machine(SunE420R,os=solaris) with 4 cpu's for a pattern discovery/search program on biological sequence(genomic sequence).I want to write the python code so that it utilizes all the 4 cpu's.Moreover do i need some other libraries. Kindly advice. Thanks
176
8186
by: Thomas Reichelt | last post by:
Moin, short question: is there any language combining the syntax, flexibility and great programming experience of Python with static typing? Is there a project to add static typing to Python? Thank you, -- greetz tom
9
3217
by: Xah Lee | last post by:
# -*- coding: utf-8 -*- # Python # Matching string patterns # # Sometimes you want to know if a string is of # particular pattern. Let's say in your website # you have converted all images files from gif # format to png format. Now you need to change the # html code to use the .png files. So, essentially
4
1905
by: Xah Lee | last post by:
20050207 text pattern matching # -*- coding: utf-8 -*- # Python # suppose you want to replace all strings of the form # <img src="some.gif" width="30" height="20"> # to # <img src="some.png" width="30" height="20"> # in your html files.
6
4706
by: Daniel Santa Cruz | last post by:
Hello all, I've been trying to go over my OO Patterns book, and I decided to try to implement them in Python this time around. I figured this would help me learn the language better. Well, I've gotten stuck with my first go at OO patterns with Python. I guess it goes without say that some of the stuff that are taken for granted in most of the books (ie. Interfaces, Abstract classes) don't really apply to Python per say, but the idea...
5
2069
by: pythoncurious | last post by:
Hi python experts In C++ I can do something like this: class Base { public: void f() { this->f_(); } private: virtual void f_() = 0; };
4
2382
by: Anastasios Hatzis | last post by:
I'm looking for a pattern where different client implementations can use the same commands of some fictive tool ("foo") by accessing some kind of API. Actually I have the need for such pattern for my own tool (http://openswarm.sourceforge.net). I already started restructuring my code to separate the actual command implementations from the command-line scripts (which is optparser-based now) and have some ideas how to proceed. But probably...
4
1669
by: dustin | last post by:
I've been hacking away on this PEP for a while, and there has been some related discussion on python-dev that went into the PEP: http://mail.python.org/pipermail/python-dev/2007-February/070921.html http://mail.python.org/pipermail/python-dev/2007-February/071155.html http://mail.python.org/pipermail/python-dev/2007-February/071181.html I'd love to have feedback on this PEP: - from a user's perspective (would you want to write...
0
1179
by: rkmr.em | last post by:
the memory usage of a python app keeps growing in a x86 64 linux continuously, whereas in 32 bit linux this is not the case. Python version in both 32 bit and 64 bit linux - 2.6.24.4-64.fc8 Python 2.5.1 (r251:54863, Oct 30 2007, 13:45:26) i isolated the memory leak problem to a function that uses datetime module extensively. i use datetime.datetime.strptime, datetime.timedelta, datetime.datetime.now methods... i tried to get some info...
0
9628
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10292
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10122
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10061
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8954
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7471
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6722
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5497
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
3
2860
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.