Python论坛  - 讨论区

标题:[python-chinese] What about a Python Tree container?

2007年11月06日 星期二 18:50

Roc Zhou chowroc.z+l在gmail.com
星期二 十一月 6 18:50:44 HKT 2007

Hello,

Recently I'm working on a new data structure written in python: Tree,
by operator overloading. I want it can act as a builtin type, such as
list and dict, but do something like a tree, to make those things need
trees can be more convenient.

For example,
1. to create a Tree, there are several ways:
(1) A empty Tree:
>>> root = Tree(None)
>>> print root
  ** Tree **
    () : None,

(2) A tree like this:
    root('zero')
      \--trunk('a')
      \--branch(1)
>>> root = Tree('zero', trunk='a', branch=1)
>>> print root
  ** Tree **
    ('trunk',) : 'a',
    () : 'zero',
    ('branch',) : 1,

(3) With items:
>>> root = Tree('zero', trunk='a', branch=1, _node_items={'try' : 'x'})
>>> print root
  ** Tree **
    ('trunk',) : 'a',
    () : 'zero',
    (('try',),) : 'x',
    ('branch',) : 1,
or like this:
>>> root = Tree('value', {'x' : 'v1', 'y' : 2}, trunk='v3', branch=4)
>>> print root
  ** Tree **
    ('trunk',) : 'v3',
    () : 'value',
    (('y',),) : 2,
    ('branch',) : 4,
    (('x',),) : 'v1',

The items can be considered as attributes of a Tree node, something like
XML attr? '')

(4) A more complicated one:
>>> root = Tree('value', {'x' : 'v1', 'y' : Tree(2, {'z' : 'v3'}, br=4)},
trunk='v5', branch=Tree(6, {'a' : 'v7'}, br=8))
>>> print root
  ** Tree **
    ('branch', ('a',)) : 'v7',
    (('y',),) : 2,
    ('branch',) : 6,
    ('branch', 'br') : 8,
    ('trunk',) : 'v5',
    (('x',),) : 'v1',
    (('y', 'z'),) : 'v3',
    () : 'value',
    (('y',), 'br') : 4,

2. Or create a Tree with setattr syntax :
>>> root = Tree(None)
>>> root = Tree('value')
>>> root['x'] = 'v1'
>>> root['y'] = 2
>>> root.trunk = 'v5'
>>> root.branch = 6
>>> root['x']['z'] = 'v3'
>>> root['x'].br = 4
>>> root.branch['a'] = 'v7'
>>> root.branch.br = 8
>>> print root
  ** Tree **
    ('branch', ('a',)) : 'v7',
    () : 'value',
    (('y',),) : 2,
    ('branch',) : 6,
    ('branch', 'br') : 8,
    ('trunk',) : 'v5',
    (('x', 'z'),) : 'v3',
    (('x',),) : 'v1',
    (('x',), 'br') : 4,

3. It's very simple to retrive the value of any given Tree node:
>>> print root
  ** Tree **
    (('x', 'y'),) : 'xy',
    (('y',),) : 3,
    ('branch',) : 7,
    ('trunk', ('a',)) : 5,
    ('trunk',) : 4,
    (('x',),) : 1,
    ('trunk', ('a', 'b'), 'data') : ['trunk', 'ab', 6],
    () : 0,
    (('x',), 'data') : ['x', 2],
    ('trunk', ('a', 'b')) : 'trunk ab',
    ('trunk', ('a',), 'data') : 'a data',
    ('branch', 'data') : 8,
>>> root()
0
>>> root.trunk()
4
>>> root.branch()
7
>>> root['x']

>>> root['x']()
1
>>> root['x'].data()
['x', 2]

4. As you have seen, the "print" operation of course have traversed the
Tree. Traverse return a path sequences to nodes map(dict) --
Tree<http://crablfs.sourceforge.net/tree.html#Tree>
 dict, every
item represents a single Tree<http://crablfs.sourceforge.net/tree.html#Tree>
 node. It't better to be called by
__call__ <http://crablfs.sourceforge.net/tree.html#Tree-__call__>
('traverse'), for example:
root('traverse') will return:
treedict = {
{
        () : Tree <http://crablfs.sourceforge.net/tree.html#Tree>(0),
        (('x',),) : Tree <http://crablfs.sourceforge.net/tree.html#Tree>(1),
        (('x',), 'data') : Tree<http://crablfs.sourceforge.net/tree.html#Tree>
(['x', 2]),
        (('x', 'y'),) : Tree <http://crablfs.sourceforge.net/tree.html#Tree>
('xy'),
        (('y',),) : Tree <http://crablfs.sourceforge.net/tree.html#Tree>(3),
        ('trunk',) : Tree <http://crablfs.sourceforge.net/tree.html#Tree>
(4),
        ('trunk', ('a',)) : Tree<http://crablfs.sourceforge.net/tree.html#Tree>
(5),
        ('trunk', ('a',), 'data') :
Tree<http://crablfs.sourceforge.net/tree.html#Tree>
("a data"),
        ('trunk', ('a', 'b')) :
Tree<http://crablfs.sourceforge.net/tree.html#Tree>
("trunk ab"),
        ('trunk', ('a', 'b'), 'data') :
Tree<http://crablfs.sourceforge.net/tree.html#Tree>
(['trunk', 'ab', 6]),
        ('branch',) : Tree <http://crablfs.sourceforge.net/tree.html#Tree>
(7),
        ('branch', 'data') : Tree<http://crablfs.sourceforge.net/tree.html#Tree>
(8)
}

5. Update a Tree with another one:
>>> def build_tree1():
        root['x'] = '1x'
...     root = Tree(0)
        root.trunk['a'] = 5
...     root['x'] = '1x'
        root.branch.data.extra = ['extra', 'info']
...     root['x'].data = 1
...     root['x']['y'] = '1xy'
...     root['x']['y'].data = 2
...     root['y'] = 3
...     root.trunk = 4
...     root.trunk['a'] = 5
...     root.trunk['a'].data = '5'
...     root.trunk['x'] = '2x'
...     root.trunk ['x'].data = 6
...     root.trunk['x']['y'] = '2xy'
...     root.trunk['x']['y'].data = 7
...     root.branch = 8
...     root.branch.data = 9
...     root.branch.data.extra = ['extra', 'info']
...     return root
...
>>> def build_tree2():
        root['x'] = '1.x'
...     root = Tree('0')
        root.trunk['x'] = ' two.x'
...     root['x'] = '1.x'
        root.branch.new = 'attr.new'
        return root...     root['x'].data = '1'
...     root['new'] = '1.new'
...     root.trunk = '4'
...     root.trunk['a'] = "a test"
...     root.trunk['x'] = None
...     root.trunk['b'] = 'b'
...     root.trunk['x'] = ' two.x'
...     root.trunk['x']['y'] = '2.xy'
...     root.trunk['x']['y'].data = '7'
...     root.trunk['new'] = '2.new'
...     root.trunk['new'].data = ' 2.new.data'
...     root.branch = '8'
...     root.branch.new = 'attr.new'
...     return root
...
>>> tree1 = build_tree1()
>>> tree2 = build_tree2()

Then you can update tree1 like these to build a new Tree:
>>> tree1('update', tree2)
>>> print tree1
  ** Tree **
    ('branch', 'data', 'extra') : ['extra', 'info'],
    ('branch', 'new') : 'attr.new',
    ('trunk', ('x', 'y')) : '2.xy',
    ('trunk', ('x',), 'data') : 6,
    ('branch',) : '8',
    ('trunk', ('x', 'y'), 'data') : '7',
    (('x',), 'data') : '1',
    ('trunk',) : '4',
    ('trunk', ('new',), 'data') : ' 2.new.data',
    ('trunk', ('new',)) : '2.new',
    ('trunk', ('x',)) : 'two.x',
    (('x',),) : '1.x',
    ('trunk', ('a',)) : 'a test',
    () : '0',
    (('y',),) : 3,
    (('x', 'y'),) : '1xy',
    ('trunk', ('a',), 'data') : '5',
    ('trunk', ('b',)) : 'b',
    ('branch', 'data') : 9,
    (('new',),) : '1.new',
    (('x', 'y'), 'data') : 2,

You can also use "+=" operator to do this:
>>> tree1 = build_tree1()
>>> tree1 += tree2
>>> print tree1
  ** Tree **
    ('branch', 'data', 'extra') : ['extra', 'info'],
    ('branch', 'new') : 'attr.new ',
    ('trunk', ('x', 'y')) : '2.xy',
    ('trunk', ('x',), 'data') : 6,
    ('branch',) : '8',
    ('trunk', ('x', 'y'), 'data') : '7',
    (('x',), 'data') : '1',
    ('trunk',) : '4',
    ('trunk', ('new',), 'data') : '2.new.data',
    ('trunk', ('new',)) : ' 2.new',
    ('trunk', ('x',)) : 'two.x',
    (('x',),) : '1.x',
    ('trunk', ('a',)) : 'a test',
    () : '0',
    (('y',),) : 3,
    (('x', 'y'),) : '1xy',
    ('trunk', ('a',), 'data') : '5',
    ('trunk', ('b',)) : 'b',
    ('branch', 'data') : 9,
    (('new',),) : '1.new',
    (('x', 'y'), 'data') : 2,

Or use "+" to build a new Tree:
>>> tree3 = tree1 + tree2

6. Compare 2 Trees:
Compare the root node value first, and if equal, compare their sub nodes,
attributes or items ...

7. Some other functions that have not been implemented ...

============
So far I use this Tree as a direct configuration method. For instance,
in my another project cutils which has a tool to do realtime file system
mirroring, the configuration file is like this:
sh# cat /etc/python/fs_mirror
"""
The configuration file for fs_mirror
"""

import tree
options = tree.Tree('fs_mirror')
o = options

#o.mode = 'daemon'
# There can be other mode, such as "run_once"

#o.host = 'localhost'
#o.port = 2123
# The server runs mirrord
#o.timeout = 60

#o.daemon = None
#o.daemon.datadir = "/var/fs_mirror"
# The mirrored dirs/files will be put into this directory

#o.fssync = 'Report'
# The synchronization mechanism you choose, it can be one of:
#    FTP, NFS, SMB/CIFS, SSH, RSYNC, ...
#    REPORT only reports the actions in wmLog,
#        does not do actual dirs creating or files transport
###o.fssync.host = 'localhost'
# Must be the same as o.host?
#o.fssync.port = 0
#o.fssync.user = 'root'
#o.fssync.passwd = ''
# Since it contains passord, you'd better keep this configuration file
secret.
# You can put the id/password pair to a secret file, such as
#    ~/.fs_mirror/secret
#    $host:$password
#    and use --password-from ~/.fs_mirror/secret:$host
#        option of fs_mirror script to appoint the password
# By this way, another user can not view the passwords by run "ps"
#        when you appointed the it from the command line option.
# The reason a command line options is used is for multi-mirroring

And the script read and analyze this configuration file can be written
like this:
...
CONFIG_MODULE_PATH = "/etc/python"
...
    options = tree.Tree('fs_mirror')
    options.mode = 'daemon'
    options.host = 'localhost'
    options.port = 2123
    options.timeout = 60
    options.daemon = None
    options.daemon.datadir = "/var/fs_mirror"
    options.fssync = 'Report'
    options.fssync.port = 0
    options.fssync.user = 'root'
    options.fssync.passwd = ''

    # Update options from a configuration file:
    try:
        sys.path.insert (0, CONFIG_MODULE_PATH)
        try:
            import fs_mirror_config as config
            options('update', config.options)
        except ImportError:
            pass
        sys.path.pop(0)
    except tree.TreeExc, trexc:
        strerr = "Invalid option because of: %s" % trexc.msg
        print >> sys.stderr, strerr
        syslog.syslog(syslog.LOG_ERR, strerr)
        sys.exit (1)

    # Update options from command line parameters:
    opts, args = getopt.gnu_getopt(sys.argv[1:], 'm:h:p:t:o:v',
        ['mode=', 'host=', 'port=', 'timeout=', 'option=', 'datadir=',
'help', 'verbose', 'password-from='])
    if args:
        options.identities = args
    ov = []
    for o, v in opts:
        if o == '-m' or o == '--mode':
            options.mode = v
        elif o == '-h' or o == '--host':
            options.host = v
        elif o == '-p' or o == '--port':
            options.port = int(v)
        elif o == '-t' or o == '--timeout':
            options.timeout = int(v)
        elif o == "--datadir":
            options.daemon.datadir = v
        elif o == '-o' or o == '--option':
            ov.append(v)
        elif o == '--help':
            print usage
            sys.exit(0)
        elif o == '-v' or o == '--verbose':
            fs_mirror.debug = 1
            fs_sync.debug = 1
        elif o == '--password-from':
            try:
                fname, hostid = v.split(':')
            except ValueError:
                raise ValueError, "Invalid secret-file:id pair for
--passwd-from"
            for line in open(fname, 'r'):
                line = line.strip()
                try:
                    id, passwd = line.split(':')
                    if id == hostid:
                        options.fssync.passwd = passwd
                        break
                except ValueError:
                    raise ValueError, "Invalid id:password pair record '%s'"
% line
    options('update', oparse(ov))

You can find the document of "cutils" project at:
http://crablfs.sourceforge.net <http://crablfs.sourceforge.net/tree.html>
/#ru_data_man
and download it from:
http://sourceforge.net/projects/crablfs
 <http://crablfs.sourceforge.net/tree.html>
But I think this Tree structure can also be used in other ways. For
example, I think it's possible to implement an API to read XML into such
structure ...

============
Luckily the basic definition has been finished now, you can also download
it from:
http://sourceforge.net/projects/crablfs
the document is in the code and unittest. And I have put the HTML at:
http://crablfs.sourceforge.net/tree.html

The source code is in SVN:
https://crablfs.svn.sourceforge.net/svnroot/crablfs/caxes/trunk/>
the files are tree.py and test_tree.py.

I hope this can be useful to you. Maybe I can write a PEP? Looking
forward to your suggestions and advices...

I'm not so expericenced, and this is only a partial finished work, since
I can only squash my limited spare time to do this and there is several
projects I have started. There are many things to learn, and now I'm
learning from you '')

Thank you.

-- 
------------------------------------------------------------------------
My Projects:
http://sourceforge.net/projects/crablfs
http://crablfs.sourceforge.net/
http://crablfs.sourceforge.net/#ru_data_man
http://crablfs.sourceforge.net/tree.html
http://cralbfs.sourceforge.net/sysadm_zh_CN.html
My Blog:
http://chowroc.blogspot.com/
http://hi.baidu.com/chowroc_z/
Looking for a space and platform to exert my originalities (for my
projects)...
-------------- 下一部分 --------------
??HTML?????...
URL: http://python.cn/pipermail/python-chinese/attachments/20071106/5706807f/attachment-0001.html 

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

2007年11月07日 星期三 08:47

swordsp sparas2006在gmail.com
星期三 十一月 7 08:47:07 HKT 2007

顺道去去sf上看了一下,最大的感想是文档真棒,难得看到国人做的开源项目能这么"专业":)

回到这个tree的模块,说几点我的想法:

第一印象,这大概不能算是一个"general
purpose"的tree,这一点和内置的list和dict感觉不一样。在我的理解中,从数据结构的视角来看,tree的核心概念只有节点及其父子关系(root和leaf都是由此而来的衍生概念),基本操作只有节点的CRUD、遍历以及对整颗子树的移动,其它的都不能算是基本语义。

这个模块中大量使用key-value的语义来处理节点,对于单纯的"tree"来说其实是增加了不必要的复杂性。尤其是有些地方为了api的使用便利,让接口的语义变得模糊(attribute和items两种"子节点"的概念,multi-key和nested-key的同时支持,节点赋值时value和subtree的处理,都是很容易带来混淆的地方),个人觉得可能是得不偿失的。

我个人比较喜欢的方式是把这些核心的概念以及基础的api抽离出来作为一个基类,保持其简洁和单纯(这里我觉得用显式的方法声明会比用隐式的action分派更清晰一些),然后在不同应用场景(比如这里是用于配置管理)中使用不同扩展实现来提供一些便利的附加方法。

其实仅仅是为了表达这种有层次的信息的话,嵌套list/dict或者python自己的class大多数时候已经够用了,真正需要tree的时候多半是用到某种特定的存储结构(比如平衡树、B树、红黑树等等)来实现高效的CRUD操作,如果要作为基础库设计的话,这方面最好留下扩展的余地。至少,traverse返回iterable会比直接返回一个dict要好些。

当然,模块本身其实写得很漂亮,作者应该有相当的经验,这里只是想表达一下个人对api设计方面的不同理念。

On 11/6/07, Roc Zhou <chowroc.z+l at gmail.com> wrote:
> Hello,
>
> Recently I'm working on a new data structure written in python: Tree,
> by operator overloading. I want it can act as a builtin type, such as
> list and dict, but do something like a tree, to make those things need
> trees can be more convenient.
>
> For example,
> 1. to create a Tree, there are several ways:
> (1) A empty Tree:
> >>> root = Tree(None)
> >>> print root
>   ** Tree **
>     () : None,
>
> (2) A tree like this:
>     root('zero')
>       \--trunk('a')
>       \--branch(1)
> >>> root = Tree('zero', trunk='a', branch=1)
>  >>> print root
>   ** Tree **
>     ('trunk',) : 'a',
>     () : 'zero',
>     ('branch',) : 1,
>
> (3) With items:
> >>> root = Tree('zero', trunk='a', branch=1, _node_items={'try' : 'x'})
> >>> print root
>   ** Tree **
>     ('trunk',) : 'a',
>     () : 'zero',
>     (('try',),) : 'x',
>     ('branch',) : 1,
> or like this:
> >>> root = Tree('value', {'x' : 'v1', 'y' : 2}, trunk='v3', branch=4)
> >>> print root
>   ** Tree **
>     ('trunk',) : 'v3',
>     () : 'value',
>     (('y',),) : 2,
>     ('branch',) : 4,
>     (('x',),) : 'v1',
>
> The items can be considered as attributes of a Tree node, something like
> XML attr? '')
>
> (4) A more complicated one:
> >>> root = Tree('value', {'x' : 'v1', 'y' : Tree(2, {'z' : 'v3'}, br=4)},
> trunk='v5', branch=Tree(6, {'a' : 'v7'}, br=8))
> >>> print root
>   ** Tree **
>     ('branch', ('a',)) : 'v7',
>     (('y',),) : 2,
>     ('branch',) : 6,
>     ('branch', 'br') : 8,
>     ('trunk',) : 'v5',
>     (('x',),) : 'v1',
>     (('y', 'z'),) : 'v3',
>     () : 'value',
>     (('y',), 'br') : 4,
>
> 2. Or create a Tree with setattr syntax :
> >>> root = Tree(None)
> >>> root = Tree('value')
> >>> root['x'] = 'v1'
> >>> root['y'] = 2
> >>> root.trunk = 'v5'
>  >>> root.branch = 6
> >>> root['x']['z'] = 'v3'
> >>> root['x'].br = 4
> >>> root.branch['a'] = 'v7'
> >>> root.branch.br = 8
> >>> print root
>   ** Tree **
>     ('branch', ('a',)) : 'v7',
>     () : 'value',
>     (('y',),) : 2,
>     ('branch',) : 6,
>     ('branch', 'br') : 8,
>     ('trunk',) : 'v5',
>     (('x', 'z'),) : 'v3',
>     (('x',),) : 'v1',
>     (('x',), 'br') : 4,
>
>  3. It's very simple to retrive the value of any given Tree node:
> >>> print root
>   ** Tree **
>     (('x', 'y'),) : 'xy',
>     (('y',),) : 3,
>     ('branch',) : 7,
>     ('trunk', ('a',)) : 5,
>     ('trunk',) : 4,
>     (('x',),) : 1,
>     ('trunk', ('a', 'b'), 'data') : ['trunk', 'ab', 6],
>     () : 0,
>     (('x',), 'data') : ['x', 2],
>     ('trunk', ('a', 'b')) : 'trunk ab',
>     ('trunk', ('a',), 'data') : 'a data',
>     ('branch', 'data') : 8,
> >>> root()
> 0
> >>> root.trunk()
> 4
> >>> root.branch()
> 7
> >>> root['x']
> 
> >>> root['x']()
> 1
> >>> root['x'].data()
> ['x', 2]
>
> 4. As you have seen, the "print" operation of course have traversed the
> Tree. Traverse
> return a path sequences to nodes map(dict) -- Tree
>  dict, every
> item represents a single Tree node. It't better to be called by
>  __call__('traverse'), for example:
> root('traverse') will return:
>  treedict = {
>  {
>          () : Tree(0),
>          (('x',),) : Tree(1),
>          (('x',), 'data') : Tree(['x', 2]),
>          (('x', 'y'),) : Tree('xy'),
>          (('y',),) : Tree(3),
>          ('trunk',) : Tree(4),
>          ('trunk', ('a',)) : Tree(5),
>          ('trunk', ('a',), 'data') : Tree("a data"),
>          ('trunk', ('a', 'b')) : Tree("trunk ab"),
>         ('trunk', ('a', 'b'), 'data') : Tree(['trunk', 'ab', 6]),
>          ('branch',) : Tree(7),
>          ('branch', 'data') : Tree(8)
>  }
>
> 5. Update a Tree with another one:
> >>> def build_tree1():
>         root['x'] = '1x'
> ...     root = Tree(0)
>         root.trunk['a'] = 5
> ...     root['x'] = '1x'
>         root.branch.data.extra = ['extra', 'info']
> ...     root['x'].data = 1
> ...     root['x']['y'] = '1xy'
> ...     root['x']['y'].data = 2
> ...     root['y'] = 3
> ...     root.trunk = 4
> ...     root.trunk['a'] = 5
> ...     root.trunk['a'].data = '5'
> ...     root.trunk['x'] = '2x'
> ...     root.trunk ['x'].data = 6
> ...     root.trunk['x']['y'] = '2xy'
> ...     root.trunk['x']['y'].data = 7
> ...     root.branch = 8
> ...     root.branch.data = 9
> ...     root.branch.data.extra = ['extra', 'info']
> ...     return root
> ...
> >>> def build_tree2():
>         root['x'] = '1.x'
> ...     root = Tree('0')
>         root.trunk['x'] = ' two.x'
> ...     root['x'] = '1.x'
>         root.branch.new = 'attr.new'
>         return root...     root['x'].data = '1'
> ...     root['new'] = '1.new'
>  ...     root.trunk = '4'
> ...     root.trunk['a'] = "a test"
> ...     root.trunk['x'] = None
> ...     root.trunk['b'] = 'b'
> ...     root.trunk['x'] = ' two.x'
> ...     root.trunk['x']['y'] = '2.xy'
> ...     root.trunk['x']['y'].data = '7'
> ...     root.trunk['new'] = '2.new'
> ...     root.trunk['new'].data = ' 2.new.data'
> ...     root.branch = '8'
> ...     root.branch.new = 'attr.new'
> ...     return root
> ...
>  >>> tree1 = build_tree1()
>  >>> tree2 = build_tree2()
>
> Then you can update tree1 like these to build a new Tree:
> >>> tree1('update', tree2)
> >>> print tree1
>   ** Tree **
>     ('branch', 'data', 'extra') : ['extra', 'info'],
>     ('branch', 'new') : 'attr.new',
>     ('trunk', ('x', 'y')) : '2.xy',
>     ('trunk', ('x',), 'data') : 6,
>     ('branch',) : '8',
>     ('trunk', ('x', 'y'), 'data') : '7',
>     (('x',), 'data') : '1',
>     ('trunk',) : '4',
>     ('trunk', ('new',), 'data') : ' 2.new.data',
>     ('trunk', ('new',)) : '2.new',
>     ('trunk', ('x',)) : 'two.x',
>     (('x',),) : '1.x',
>     ('trunk', ('a',)) : 'a test',
>     () : '0',
>     (('y',),) : 3,
>     (('x', 'y'),) : '1xy',
>     ('trunk', ('a',), 'data') : '5',
>     ('trunk', ('b',)) : 'b',
>     ('branch', 'data') : 9,
>     (('new',),) : '1.new',
>     (('x', 'y'), 'data') : 2,
>
> You can also use "+=" operator to do this:
> >>> tree1 = build_tree1()
> >>> tree1 += tree2
> >>> print tree1
>   ** Tree **
>     ('branch', 'data', 'extra') : ['extra', 'info'],
>     ('branch', 'new') : ' attr.new ',
>     ('trunk', ('x', 'y')) : '2.xy',
>     ('trunk', ('x',), 'data') : 6,
>     ('branch',) : '8',
>     ('trunk', ('x', 'y'), 'data') : '7',
>     (('x',), 'data') : '1',
>     ('trunk',) : '4',
>     ('trunk', ('new',), 'data') : '2.new.data',
>     ('trunk', ('new',)) : ' 2.new',
>     ('trunk', ('x',)) : 'two.x',
>     (('x',),) : '1.x',
>     ('trunk', ('a',)) : 'a test',
>     () : '0',
>     (('y',),) : 3,
>     (('x', 'y'),) : '1xy',
>     ('trunk', ('a',), 'data') : '5',
>     ('trunk', ('b',)) : 'b',
>     ('branch', 'data') : 9,
>     (('new',),) : '1.new',
>     (('x', 'y'), 'data') : 2,
>
> Or use "+" to build a new Tree:
> >>> tree3 = tree1 + tree2
>
>  6. Compare 2 Trees:
> Compare the root node value first, and if equal, compare their sub nodes,
> attributes or items ...
>
> 7. Some other functions that have not been implemented ...
>
> ============
> So far I use this Tree as a direct configuration method. For instance,
> in my another project cutils which has a tool to do realtime file system
> mirroring, the configuration file is like this:
> sh# cat /etc/python/fs_mirror
> """
> The configuration file for fs_mirror
> """
>
> import tree
> options = tree.Tree('fs_mirror')
> o = options
>
> #o.mode = 'daemon'
> # There can be other mode, such as "run_once"
>
> #o.host = 'localhost'
> #o.port = 2123
> # The server runs mirrord
> #o.timeout = 60
>
> #o.daemon = None
> #o.daemon.datadir = "/var/fs_mirror"
> # The mirrored dirs/files will be put into this directory
>
> #o.fssync = 'Report'
> # The synchronization mechanism you choose, it can be one of:
> #    FTP, NFS, SMB/CIFS, SSH, RSYNC, ...
> #    REPORT only reports the actions in wmLog,
> #        does not do actual dirs creating or files transport
> ###o.fssync.host = 'localhost'
> # Must be the same as o.host?
> #o.fssync.port = 0
> #o.fssync.user = 'root'
> #o.fssync.passwd = ''
> # Since it contains passord, you'd better keep this configuration file
> secret.
> # You can put the id/password pair to a secret file, such as
> #    ~/.fs_mirror/secret
> #    $host:$password
> #    and use --password-from ~/.fs_mirror/secret:$host
> #        option of fs_mirror script to appoint the password
> # By this way, another user can not view the passwords by run "ps"
> #        when you appointed the it from the command line option.
> # The reason a command line options is used is for multi-mirroring
>
> And the script read and analyze this configuration file can be written
> like this:
> ...
> CONFIG_MODULE_PATH = "/etc/python"
> ...
>     options = tree.Tree('fs_mirror')
>     options.mode = 'daemon'
>     options.host = 'localhost'
>     options.port = 2123
>     options.timeout = 60
>     options.daemon = None
>     options.daemon.datadir = "/var/fs_mirror"
>     options.fssync = 'Report'
>     options.fssync.port = 0
>     options.fssync.user = 'root'
>     options.fssync.passwd = ''
>
>     # Update options from a configuration file:
>     try:
>         sys.path.insert (0, CONFIG_MODULE_PATH)
>         try:
>             import fs_mirror_config as config
>             options('update', config.options)
>         except ImportError:
>             pass
>         sys.path.pop (0)
>     except tree.TreeExc, trexc:
>         strerr = "Invalid option because of: %s" % trexc.msg
>         print >> sys.stderr, strerr
>         syslog.syslog(syslog.LOG_ERR, strerr)
>         sys.exit (1)
>
>     # Update options from command line parameters:
>     opts, args = getopt.gnu_getopt(sys.argv[1:], 'm:h:p:t:o:v',
>         ['mode=', 'host=', 'port=', 'timeout=', 'option=', 'datadir=',
> 'help', 'verbose', 'password-from='])
>     if args:
>         options.identities = args
>     ov = []
>     for o, v in opts:
>         if o == '-m' or o == '--mode':
>             options.mode = v
>         elif o == '-h' or o == '--host':
>             options.host = v
>         elif o == '-p' or o == '--port':
>             options.port = int(v)
>         elif o == '-t' or o == '--timeout':
>             options.timeout = int(v)
>         elif o == "--datadir":
>             options.daemon.datadir = v
>         elif o == '-o' or o == '--option':
>             ov.append(v)
>         elif o == '--help':
>             print usage
>             sys.exit(0)
>         elif o == '-v' or o == '--verbose':
>             fs_mirror.debug = 1
>             fs_sync.debug = 1
>         elif o == '--password-from':
>             try:
>                 fname, hostid = v.split(':')
>             except ValueError:
>                 raise ValueError, "Invalid secret-file:id pair for
> --passwd-from"
>             for line in open(fname, 'r'):
>                 line = line.strip()
>                 try:
>                     id, passwd = line.split(':')
>                     if id == hostid:
>                         options.fssync.passwd = passwd
>                         break
>                 except ValueError:
>                     raise ValueError, "Invalid id:password pair record '%s'"
> % line
>     options('update', oparse(ov))
>
> You can find the document of "cutils" project at:
> http://crablfs.sourceforge.net /#ru_data_man
> and download it from:
> http://sourceforge.net/projects/crablfs
>
> But I think this Tree structure can also be used in other ways. For
> example, I think it's possible to implement an API to read XML into such
> structure ...
>
>  ============
> Luckily the basic definition has been finished now, you can also download
> it from:
>  http://sourceforge.net/projects/crablfs
> the document is in the code and unittest. And I have put the HTML at:
>  http://crablfs.sourceforge.net/tree.html
>
> The source code is in SVN:
> https://crablfs.svn.sourceforge.net/svnroot/crablfs/caxes/trunk/
> the files are tree.py and test_tree.py.
>
> I hope this can be useful to you. Maybe I can write a PEP? Looking
> forward to your suggestions and advices...
>
> I'm not so expericenced, and this is only a partial finished work, since
> I can only squash my limited spare time to do this and there is several
> projects I have started. There are many things to learn, and now I'm
> learning from you '')
>
> Thank you.
>
>  --
> ------------------------------------------------------------------------
> My Projects:
> http://sourceforge.net/projects/crablfs
>  http://crablfs.sourceforge.net/
>  http://crablfs.sourceforge.net/#ru_data_man
> http://crablfs.sourceforge.net/tree.html
>  http://cralbfs.sourceforge.net/sysadm_zh_CN.html
> My Blog:
> http://chowroc.blogspot.com/
>  http://hi.baidu.com/chowroc_z/
> Looking for a space and platform to exert my originalities (for my
> projects)...
> _______________________________________________
> python-chinese
> Post: send python-chinese at lists.python.cn
> Subscribe: send subscribe to
> python-chinese-request at lists.python.cn
> Unsubscribe: send unsubscribe to
>  python-chinese-request at lists.python.cn
> Detail Info:
> http://python.cn/mailman/listinfo/python-chinese
>

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

2007年11月09日 星期五 15:19

Roc Zhou chowroc.z+l在gmail.com
星期五 十一月 9 15:19:55 HKT 2007

·Ç³£¸ÐлÄãµÄ»Ø¸´ºÍ½¨Òé¡£

ÕâÁ½Ìì´òËãÖØÐÂдһϵ¥Ôª²âÊÔ£¬ÒÔǰдµÄµ¥Ôª²âÊÔʵÔÚÊDZȽÏÔã¸â -_-! ¶øÇÒ¹¤×÷ÉϵÄÊÂÇéÒ²±È½ÏÔÓ£¬ËùÒÔûÓм°Ê±»Ø¸´¡£

¹ØÓÚÄã˵µÄÕ⼸µã£¬ÎÒ¾õµÃÓм¸µãÎÒ¿ÉÒÔ½øÒ»²½ËµÃ÷µÄ¡£²»¹ýÕâÁ½Ìì±È½Ï棬ÎÒÓÐʱ¼äÕûÀíÒ»ÏÂ˼·°É¡£´óÌåÉÏ£¬ÕâµÄÈ·²»ÊÇÒ»¸öÊý¾Ý½á¹¹ÉϵÄ
Tree£¬»òÕß˵²»ÊÇÒ»¸ö´æ´¢µÄÊý¾Ý½á¹¹É쵀 Tree£¬¶ø¸üÏñÊÇÎļþϵͳÄÇÑùµÄ directory
Tree£¬ÃæÏò¸üÉϲãµÄʹÓÃÕß°É¡£´æ´¢ÉÏ£¬ÎÒ¾õµÃ¿ÉÒÔÔÙÏë±ðµÄ°ì·¨£¬±ÈÈç Berkeley DB£¬¶ÔÓÚʹÓÃËüµÄÈËÀ´Ëµ£¬Ëü¸üÏñÊÇÒ»¸ö Hash
Table£¬µ«Êµ¼ÊÉÏÈ´¿ÉÄÜʹÓÃÁË Hash, BTree »ò Queue À´½øÐÐʵ¼ÊµÄ´æ´¢¡£²»¹ýÈç¹ûÓà BTree
µÄ»°£¬Õ¼ÓõĴ洢¿Õ¼ä¾Í»á±È½Ï´ó£¬ÔÚÄÚ´æÖÐËƺõ²»Ì«ºÏÊÊ¡£

»»Ò»¸ö½Ç¶ÈÀ´¿¼ÂÇ£¬ÎÒ¾õµÃ¿ÉÄܸü½Ó½üÓÚ DOM »ò ElementTree ÕâÑùµÄ¶«Î÷£¬²»¹ýÎÒÏ£Íû¸ü¼òµ¥£¬²»Ï£ÍûÈ¥´¦Àí XML
µÄ¸´ÔÓÐÔ£¬²¢ÇÒÏ£ÍûÓиüºÃµÄ¿É¶ÁÐԵȵÈ... ¶øÇÒÎÒ¸öÈ˾õµÃ¸ü Pythonic£¬µ±È»Ã¿¸öÈË¶Ô Pythonic µÄÀí½â¿ÉÄܲ»Ò»Ñù£¬²»¹ýÎÒÏë¼ÈÈ»
Python ÌṩÁËÕâÑùµÄÄÜÁ¦£¬ÎªÊ²Ã´²»½«Ëü·¢»Óµ½¼«ÖÂÄØ£¿

Äã¶ÔÓÚ iterator µÄ½¨ÒéºÜÓеÀÀí¡£·Ç³£¸Ðл¡£'')

ÓÐʱ¼äÎÒÕûÀíÏÂ˼·Ïêϸ˵Ã÷°É¡£ÎÒ¿ÉÄÜÒ²ÐèҪдÎĵµÁË¡£

On Nov 7, 2007 8:47 AM, swordsp <sparas2006在gmail.com> wrote:

> ˳µÀȥȥsfÉÏ¿´ÁËһϣ¬×î´óµÄ¸ÐÏëÊÇÎĵµÕæ°ô£¬Äѵÿ´µ½¹úÈË×öµÄ¿ªÔ´ÏîÄ¿ÄÜÕâô"רҵ":)
>
> »Øµ½Õâ¸ötreeµÄÄ£¿é£¬Ëµ¼¸µãÎÒµÄÏë·¨£º
>
> µÚÒ»Ó¡Ïó£¬Õâ´ó¸Å²»ÄÜËãÊÇÒ»¸ö"general
>
> purpose"µÄtree£¬ÕâÒ»µãºÍÄÚÖõÄlistºÍdict¸Ð¾õ²»Ò»Ñù¡£ÔÚÎÒµÄÀí½âÖУ¬´ÓÊý¾Ý½á¹¹µÄÊÓ½ÇÀ´¿´£¬treeµÄºËÐĸÅÄîÖ»Óнڵ㼰Æ丸×Ó¹Øϵ£¨rootºÍleaf¶¼ÊÇÓɴ˶øÀ´µÄÑÜÉú¸ÅÄ£¬»ù±¾²Ù×÷Ö»ÓнڵãµÄCRUD¡¢±éÀúÒÔ¼°¶ÔÕû¿Å×ÓÊ÷µÄÒƶ¯£¬ÆäËüµÄ¶¼²»ÄÜËãÊÇ»ù±¾ÓïÒå¡£
>
>
> Õâ¸öÄ£¿éÖдóÁ¿Ê¹ÓÃkey-valueµÄÓïÒåÀ´´¦Àí½Úµã£¬¶ÔÓÚµ¥´¿µÄ"tree"À´ËµÆäʵÊÇÔö¼ÓÁ˲»±ØÒªµÄ¸´ÔÓÐÔ¡£ÓÈÆäÊÇÓÐЩµØ·½ÎªÁËapiµÄʹÓñãÀû£¬ÈýӿڵÄÓïÒå±äµÃÄ£ºý£¨attributeºÍitemsÁ½ÖÖ"×Ó½Úµã"µÄ¸ÅÄmulti-keyºÍnested-keyµÄͬʱ֧³Ö£¬½Úµã¸³ÖµÊ±valueºÍsubtreeµÄ´¦Àí£¬¶¼ÊǺÜÈÝÒ×´øÀ´»ìÏýµÄµØ·½£©£¬¸öÈ˾õµÃ¿ÉÄÜÊǵò»³¥Ê§µÄ¡£
>
>
> ÎÒ¸öÈ˱ȽÏϲ»¶µÄ·½Ê½ÊÇ°ÑÕâЩºËÐĵĸÅÄîÒÔ¼°»ù´¡µÄapi³éÀë³öÀ´×÷Ϊһ¸ö»ùÀ࣬±£³ÖÆä¼ò½àºÍµ¥´¿£¨ÕâÀïÎÒ¾õµÃÓÃÏÔʽµÄ·½·¨ÉùÃ÷»á±ÈÓÃÒþʽµÄaction·ÖÅɸüÇåÎúһЩ£©£¬È»ºóÔÚ²»Í¬Ó¦Óó¡¾°£¨±ÈÈçÕâÀïÊÇÓÃÓÚÅäÖùÜÀí£©ÖÐʹÓò»Í¬À©Õ¹ÊµÏÖÀ´ÌṩһЩ±ãÀûµÄ¸½¼Ó·½·¨¡£
>
>
> Æäʵ½ö½öÊÇΪÁ˱í´ïÕâÖÖÓвã´ÎµÄÐÅÏ¢µÄ»°£¬Ç¶Ì×list/dict»òÕßpython×Ô¼ºµÄclass´ó¶àÊýʱºòÒѾ­¹»ÓÃÁË£¬ÕæÕýÐèÒªtreeµÄʱºò¶à°ëÊÇÓõ½Ä³ÖÖÌض¨µÄ´æ´¢½á¹¹£¨±ÈÈçƽºâÊ÷¡¢BÊ÷¡¢ºìºÚÊ÷µÈµÈ£©À´ÊµÏÖ¸ßЧµÄCRUD²Ù×÷£¬Èç¹ûÒª×÷Ϊ»ù´¡¿âÉè¼ÆµÄ»°£¬Õâ·½Ãæ×îºÃÁôÏÂÀ©Õ¹µÄÓàµØ¡£ÖÁÉÙ£¬traverse·µ»Øiterable»á±ÈÖ±½Ó·µ»ØÒ»¸ödictÒªºÃЩ¡£
>
> µ±È»£¬Ä£¿é±¾ÉíÆäʵдµÃºÜƯÁÁ£¬×÷ÕßÓ¦¸ÃÓÐÏ൱µÄ¾­Ñ飬ÕâÀïÖ»ÊÇÏë±í´ïһϸöÈ˶ÔapiÉè¼Æ·½ÃæµÄ²»Í¬ÀíÄî¡£
>
> _______________________________________________
> python-chinese
> Post: send python-chinese在lists.python.cn
> Subscribe: send subscribe to python-chinese-request在lists.python.cn
> Unsubscribe: send unsubscribe to  python-chinese-request在lists.python.cn
> Detail Info: http://python.cn/mailman/listinfo/python-chinese




-- 
------------------------------------------------------------------------
My Projects:
http://sourceforge.net/projects/crablfs
http://crablfs.sourceforge.net/
http://crablfs.sourceforge.net/#ru_data_man
http://crablfs.sourceforge.net/tree.html
http://cralbfs.sourceforge.net/sysadm_zh_CN.html
My Blog:
http://chowroc.blogspot.com/
http://hi.baidu.com/chowroc_z/
Looking for a space and platform to exert my originalities (for my
projects)...
-------------- 下一部分 --------------
Ò»¸öHTML¸½¼þ±»ÒƳý...
URL: http://python.cn/pipermail/python-chinese/attachments/20071109/834a8114/attachment.html 

[导入自Mailman归档:http://www.zeuux.org/pipermail/zeuux-python]

如下红色区域有误,请重新填写。

    你的回复:

    请 登录 后回复。还没有在Zeuux哲思注册吗?现在 注册 !

    Zeuux © 2025

    京ICP备05028076号