如何使python"构造函数""私有",以便只能通过调用静态方法创建其类的对象?我知道Python中没有类似C++/Java的私有方法,但我正在寻找另一种方法来阻止其他人调用我的构造函数(或其他方法).
我有类似的东西:
class Response(object):
@staticmethod
def from_xml(source):
ret = Response()
# parse xml into ret
return ret
@staticmethod
def from_json(source):
# parse json
pass
Run Code Online (Sandbox Code Playgroud)
并希望以下行为:
r = Response() # should fail
r = Response.from_json(source) # should be allowed
Run Code Online (Sandbox Code Playgroud)
使用静态方法的原因是我总是忘记构造函数采用的参数 - 比如JSON或已经解析过的对象.即便如此,我有时会忘记静态方法并直接调用构造函数(更不用说使用我的代码的其他人).记录这份合同对我的遗忘无益.我宁愿用断言强制执行它.
与一些评论者相反,我认为这不是单一的 - "显性比隐性更好","应该只有一种方法".
当我做错时怎么能得到温柔的提醒?我更喜欢一个解决方案,我不需要更改静态方法,只需一个装饰器或构造函数的单行插件就可以了.一个la:
class Response(object):
def __init__(self):
assert not called_from_outside()
Run Code Online (Sandbox Code Playgroud)
bru*_*ers 14
我认为这就是你要找的东西 - 但就我而言,这是一种无声的.
class Foo(object):
def __init__(self):
raise NotImplementedError()
def __new__(cls):
bare_instance = object.__new__(cls)
# you may want to have some common initialisation code here
return bare_instance
@classmethod
def from_whatever(cls, arg):
instance = cls.__new__(cls)
instance.arg = arg
return instance
Run Code Online (Sandbox Code Playgroud)
给出您的示例(from_json和from_xml),我假设您正在从json或xml源中检索属性值.在这种情况下,pythonic解决方案将有一个普通的初始化程序,并从您的备用构造函数调用它,即:
class Foo(object):
def __init__(self, arg):
self.arg = arg
@classmethod
def from_json(cls, source):
arg = get_arg_value_from_json_source(source)
return cls(arg)
@classmethod
def from_xml(cls, source):
arg = get_arg_value_from_xml_source(source)
return cls(arg)
Run Code Online (Sandbox Code Playgroud)
哦,是的,关于第一个例子:它将阻止你的类以通常的方式实例化(调用类),但客户端代码仍然可以调用Foo.__new__(Foo),所以这真的是浪费时间.如果你不能以最普通的方式实例化你的课程,那么它将使单元测试变得更难......而且我们中的很多人会因此而讨厌你.
use*_*ica 12
我建议将工厂方法转换为模块级工厂函数,然后将类本身隐藏在模块用户之外.
def one_constructor(source):
return _Response(...)
def another_constructor(source):
return _Response(...)
class _Response(object):
...
Run Code Online (Sandbox Code Playgroud)
你可以看到这种方法在像模块中使用re,其中匹配对象,只能通过类似功能构建match和search,和文档实际上并没有命名的匹配对象类型.(至少,3.4文档没有.2.7文档错误引用re.MatchObject,但不存在.)匹配对象类型也拒绝直接构造:
>>> type(re.match('',''))()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create '_sre.SRE_Match' instances
Run Code Online (Sandbox Code Playgroud)
但不幸的是,它的方式依赖于C API,因此它不适用于普通的Python代码.
这可能可以通过元类来实现,但在 Python 中是非常不鼓励的。Python 不是 Java。Python 中不存在公共与私有的一流概念;这个想法是,该语言的使用者是“同意的成年人”,可以使用他们喜欢的方法。一般来说,旨在“私有”的函数(不属于 API 的一部分)由一个前导下划线表示;然而,这主要只是约定,没有什么可以阻止用户使用这些功能。
在您的情况下,Pythonic 要做的事情是将构造函数默认为可用的 from_foo 方法之一,甚至创建一个“智能构造函数”,它可以在大多数情况下找到适当的解析器。或者,将可选关键字 arg 添加到__init__确定要使用哪个解析器的方法。