__new__
Python 类的方法是否可以引用 的子类的A
(常量)实例?A
为了说明(激励?)这个问题,下面是 Perl 中类似 Lisp 的列表的玩具实现。Lisp 列表通常被递归定义为一对(又名cons
),其第一个元素是某个任意 Lisp 对象,其第二个元素是一个列表。为了避免无限递归,Lisp 有一个称为哨兵常量nil
,它被定义为一个列表。因此,nil
is a list、(cons 3 nil)
is a list、(cons 3 (cons 1 nil))
is a list 等(尽管最后两个示例更常见地分别写为(3)
和(3 1)
)。
我在下面给出的这个定义的 Perl 实现解释nil
为list
. 然而,list
类的定义引用了这个nil
常量。
# list.pm
use strict;
BEGIN {
sub list::nil ();
}
package _nil;
{
my $nil = bless \ do { my $x }, '_nil';
sub nil () { $nil; }
}
*car = *cdr = sub { shift };
our @ISA = ( 'list' );
package list;
*nil = *_nil::nil;
sub new {
my $cls = shift;
@_ ? bless [ shift, $cls->new( @_ ) ], $cls : nil;
}
sub car () { shift->[ 0 ] }
sub cdr () { shift->[ 1 ] }
use Exporter 'import';
our @EXPORT = qw( list nil );
1;
% perl -Mlist -e 'printf "nil->isa(\047list\047) = %s\n", \
nil->isa(q(list)) ? q(t) : q(f)'
nil->isa('list') = t
(car
并且cdr
对于对象的第一个和第二个元素是 Lisp-ish cons
。)
这个例子的重点是表明,在 Perl 中(即使是我过时的 Perl,在专家水平上也很差),实现一个引用子类实例的类是微不足道的。这是因为,在 Perl 中,一个类甚至可以在定义之前B
声明为子类。(这是行A
A
our @ISA = ( 'list' );
做。)
我正在寻找某种方法来在 Python 中近似这种效果。
编辑/澄清:
在我尝试过的许多事情中,有一个接近目标。
from collections import namedtuple
from itertools import chain
class List(namedtuple('pair', 'car cdr')):
def __new__(cls, *args):
if len(args) > 0:
return super(List, cls).__new__(cls, args[0], cls(*args[1:]))
else:
return nil
def __str__(self):
return '(%s)' % ' '.join(map(str, self))
def __iter__(self):
return chain((self.car,), iter(self.cdr))
class Nil(object):
car = cdr = property(lambda s: s)
__str__ = lambda s: 'nil'
def __iter__(self):
if False: yield
nil = Nil()
print List(3, 4, 5)
print nil, nil.car, nil.cdr
print 'isinstance(nil, List) -> %s' % isinstance(nil, List)
输出是:
(3 4 5)
nil nil nil
isinstance(nil, List) -> False
...这很好,除了最后一行。
如果改为更改Nil
to start with的定义class Nil(List)
,则会出现错误:
Traceback (most recent call last):
File "list.py", line 38, in <module>
nil = Nil()
File "list.py", line 25, in __new__
return nil
NameError: global name 'nil' is not defined