384

假设我有一个类,它有一个名为 data 的成员,它是一个列表。

我希望能够使用例如文件名(其中包含用于初始化列表的数据)或实际列表来初始化类。

你这样做的技术是什么?

你只是通过查看来检查类型__class__吗?

我可能会错过一些技巧吗?

我习惯了 C++ 中的参数类型重载很容易。

4

10 回答 10

513

获得“备用构造函数”的一种更简洁的方法是使用类方法。例如:

>>> class MyData:
...     def __init__(self, data):
...         "Initialize MyData from a sequence"
...         self.data = data
...     
...     @classmethod
...     def fromfilename(cls, filename):
...         "Initialize MyData from a file"
...         data = open(filename).readlines()
...         return cls(data)
...     
...     @classmethod
...     def fromdict(cls, datadict):
...         "Initialize MyData from a dict's items"
...         return cls(datadict.items())
... 
>>> MyData([1, 2, 3]).data
[1, 2, 3]
>>> MyData.fromfilename("/tmp/foobar").data
['foo\n', 'bar\n', 'baz\n']
>>> MyData.fromdict({"spam": "ham"}).data
[('spam', 'ham')]

它更简洁的原因是毫无疑问预期的类型是什么,并且您不必猜测调用者打算如何处理它给您的数据类型。问题isinstance(x, basestring)在于,调用者无法告诉您,例如,即使类型不是基本字符串,您也应该将其视为字符串(而不是另一个序列)。也许调用者想要将同一类型用于不同目的,有时作为单个项目,有时作为项目序列。显式可以消除所有疑问,并导致更健壮和更清晰的代码。

于 2008-09-26T20:30:15.857 回答
41

很好的问题。我也解决了这个问题,虽然我同意“工厂”(类方法构造函数)是一个好方法,但我想建议另一种方法,我也发现它非常有用:

这是一个示例(这是一个read方法而不是构造函数,但想法是一样的):

def read(self, str=None, filename=None, addr=0):
    """ Read binary data and return a store object. The data
        store is also saved in the interal 'data' attribute.

        The data can either be taken from a string (str 
        argument) or a file (provide a filename, which will 
        be read in binary mode). If both are provided, the str 
        will be used. If neither is provided, an ArgumentError 
        is raised.
    """
    if str is None:
        if filename is None:
            raise ArgumentError('Please supply a string or a filename')

        file = open(filename, 'rb')
        str = file.read()
        file.close()
    ...
    ... # rest of code

这里的关键思想是使用 Python 对命名参数的出色支持来实现这一点。现在,如果我想从文件中读取数据,我会说:

obj.read(filename="blob.txt")

为了从字符串中读取它,我说:

obj.read(str="\x34\x55")

这样,用户只需调用一个方法。如您所见,在内部处理它并不太复杂

于 2008-10-17T13:34:31.393 回答
29

使用 python3,您可以使用实现具有函数注释的多个调度,如 Python Cookbook 所写:

import time


class Date(metaclass=MultipleMeta):
    def __init__(self, year:int, month:int, day:int):
        self.year = year
        self.month = month
        self.day = day

    def __init__(self):
        t = time.localtime()
        self.__init__(t.tm_year, t.tm_mon, t.tm_mday)

它的工作原理如下:

>>> d = Date(2012, 12, 21)
>>> d.year
2012
>>> e = Date()
>>> e.year
2018
于 2018-04-20T07:47:05.777 回答
14

快速而肮脏的修复

class MyData:
    def __init__(string=None,list=None):
        if string is not None:
            #do stuff
        elif list is not None:
            #do other stuff
        else:
            #make data empty

然后你可以调用它

MyData(astring)
MyData(None, alist)
MyData()
于 2012-04-18T21:38:33.850 回答
9

更好的方法是使用 isinstance 和类型转换。如果我理解你的正确,你想要这个:

def __init__ (self, filename):
    if isinstance (filename, basestring):
        # filename is a string
    else:
        # try to convert to a list
        self.path = list (filename)
于 2008-09-26T19:52:59.193 回答
4

你应该使用 isinstance

isinstance(...)
    isinstance(object, class-or-type-or-tuple) -> bool

    Return whether an object is an instance of a class or of a subclass thereof.
    With a type as second argument, return whether that is the object's type.
    The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
    isinstance(x, A) or isinstance(x, B) or ... (etc.).
于 2008-09-26T19:54:33.290 回答
2

您可能需要isinstance内置函数:

self.data = data if isinstance(data, list) else self.parse(data)
于 2008-09-26T19:54:30.843 回答
-1

好的,不错。我只是把这个例子和一个元组而不是一个文件名放在一起,但这很容易。谢谢大家。

class MyData:
    def __init__(self, data):
        self.myList = []
        if isinstance(data, tuple):
            for i in data:
                self.myList.append(i)
        else:
            self.myList = data

    def GetData(self):
        print self.myList

a = [1,2]

b = (2,3)

c = 我的数据(一)

d = 我的数据(b)

c.GetData()

d.GetData()

[1, 2]

[2, 3]

于 2008-09-26T20:18:19.397 回答
-1

你为什么不去更pythonic?

class AutoList:
def __init__(self, inp):
    try:                        ## Assume an opened-file...
        self.data = inp.read()
    except AttributeError:
        try:                    ## Assume an existent filename...
            with open(inp, 'r') as fd:
                self.data = fd.read()
        except:
            self.data = inp     ## Who cares what that might be?
于 2014-05-01T19:49:07.790 回答
-1

我首选的解决方案是:

class MyClass:
    _data = []
    __init__(self,data=None):
        # do init stuff
        if not data: return
        self._data = list(data) # list() copies the list, instead of pointing to it.

然后用MyClass()or调用它MyClass([1,2,3])

希望有帮助。快乐编码!

于 2014-09-24T13:55:57.867 回答