如何编写一个行为与另一个动态确定的类完全相同的类?(Python)

2024-04-26 21:49:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我想创建一个'File'对象,当ReadLine()方法被调用时,它返回'Line'对象,而不仅仅是字符串。我还希望能够使用包含文本文档绝对路径的字符串或字符串列表初始化File对象,并使生成的实例在任何情况下都具有相同的行为。唯一的方法是根据输入类型,在FileDoc或FileList对象周围包装一个File对象。以下是我迄今为止所用解决方案的简略版本:

class Line(object):
    def __init__(self, line, count, fpath):
        self.text = line
        self.count = count
        self.fname = fpath.split('/')[-1]

class FileBase(object):
    def __init__(self):
        pass

    def Open(self):
        self.count = 0

    def Readline(self):
        pass

    def Get_count(self):
        return self.count

    def Set_count(self, val):
        self.count = val

class FileList(FileBase):
    def __init__(self, lines):
        self.lines = lines
        self.Open()

    def ReadLine(self):
        self.count += 1
        try:
            return Line(line=self.lines[self.count - 1], count=self.count - 1, fpath='list')
        except IndexError:
            raise StopIteration

class FileDoc(FileBase):
    def __init__(self, fpath):
        self.fpath = fpath
        self.Open()

    def Open(self):
        self.count = 0
        self.file = open(self.fpath, 'r')

    def ReadLine(self):
        self.count += 1
        return Line(line=self.file.next(), count=self.count - 1, fpath=self.fpath)

class File(FileBase):
    def __init__(self, input):
        if type(input) == type(''):
            self.actual = FileDoc(input)
        elif type(input) == type([]):
            self.actual = FileList(input)
        else:
            raise NonRecognizedInputError

    def Open(self):
        self.actual.Open()

    def ReadLine(self):
        return self.actual.ReadLine()

    def Get_count(self):
        return self.actual.count

    def Set_count(self, val):
        self.actual.count = val

但是,这看起来很笨拙,而且不是Pythonic,因为我必须使用Get\u count()和Set\u count()方法来访问File对象的.count成员,而不是直接使用实例计数. 有没有更优雅的解决方案,允许我将.count成员作为成员而不是使用getter和setter来访问?你知道吗

另外,为了加分,我还在努力搞清楚整个继承的事情。有没有更好的方法来构建类之间的关系?你知道吗


Tags: 对象方法selfinputreadlinereturninitdef
3条回答

就我个人而言,我认为你的等级制度太复杂了。我不知道你是如何在代码中使用它的,但是文件这个词似乎被过度使用了。字符串列表根本不是文件,因此我会创建一些类似LineReader的东西,以便能够从不同的源读取数据,然后使用文件或列表迭代器为其提供数据。你知道吗

考虑以下代码:

class Line(object):
    def __init__(self, line, count, fpath):
        self.text = line
        self.count = count
        self.fname = fpath

class LineReader(object):
    def __init__(self, iterator, fname):
        self.iterator = iterator
        self.fname = fname
        self.count = 0

    def ReadLine(self):
        line = Line(self.iterator.next(), self.count, self.fname)
        self.count += 1        
        return line

class LineSource(object):
    def __init__(self, input):
        if type(input) == type(''):
            self.reader = LineReader(open(input), input.split('/')[-1])
        elif type(input) == type([]):
            self.reader = LineReader(iter(input), 'list')
        else:
            raise NonRecognizedInputError

    def ReadLine(self):
        return self.reader.ReadLine()

对我来说没那么复杂了,我能胜任。我不知道为什么您需要访问计数器,因为它被写入了行对象。可以将属性用作@李大伟建议,但前提是您确实有理由在读取行时更改文件读取器的内部计数器。你知道吗

要简化count属性,请使用property修饰符:

@property
def count(self):
    return self._count  # or return self.actual.count

@count.setter
def count(self, value):
    self._count = value  # or self.actual.count = value

或者如果你不想让它成为一个装饰师:

count = property(Get_count, Set_count)

至于您的继承方案,我认为没关系;因为您正在使用File来隐藏大部分细节,如果需要的话,稍后更改应该不会太难。@MannyD的评论是一个重构的好主意;注意,例如,file对象是iterables,就像列表一样。你知道吗

作为旁注,FileLine作为collections.namedtuple可能更好(只是说:

Line = collections.namedtuple('Line', 'line count path')

除非有理由强制执行继承层次结构,否则我会考虑使用工厂模式并利用Python是动态类型化的这一事实:

def FileFactory(input):
    if isinstance(input, types.StringTypes):
        return FileDoc(input)
    if isinstance(input, (types.ListType, types.TupleType)):
        return FileList(input)
    raise NonRecognizedInputError()

不需要File()类,因为它不提供基类之上的任何内容,所以在本例中,它只是需要维护的额外代码。而且,通常使用isinstance(object, type)来处理派生类比比较特定类型更好。你知道吗

另一方面,我建议您遵循PEP 8样式指南,因为它将使您的代码更易于他人阅读。你知道吗

相关问题 更多 >