Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在类变量中创建对类的引用,并在_init中实例化它们___Python_Oop - Fatal编程技术网

Python 在类变量中创建对类的引用,并在_init中实例化它们__

Python 在类变量中创建对类的引用,并在_init中实例化它们__,python,oop,Python,Oop,我最近在Python中看到了很多以下模式: class Foo: pass class Bar: foo_class = Foo def __init__(self): self.foo = self.foo_class() 据我所知,Bar类首先创建一个对Foo类的引用,作为类变量Foo\u类,然后在\uu init\uu中创建Foo的实例。与其直接在中实例化Foo,它还有什么好处吗 class Foo: pass class Bar: def

我最近在Python中看到了很多以下模式:

class Foo: pass

class Bar:
    foo_class = Foo

    def __init__(self):
        self.foo = self.foo_class()
据我所知,
Bar
类首先创建一个对
Foo
类的引用,作为类变量
Foo\u类
,然后在
\uu init\uu
中创建
Foo
的实例。与其直接在
中实例化
Foo
,它还有什么好处吗

class Foo: pass

class Bar:
    def __init__(self):
        self.foo = Foo()

有一些小的好处,因为您不再在无法更改的地方硬编码对
Foo
的引用。在第一个示例中,如果希望
Bar
的后续实例使用
foo
以外的内容,可以更改
Bar.foo\u类的值。在第二个例子中,没有简单的方法可以做到这一点

然而,一个更好的方法是参数化
\uuuu init\uuu
本身,以接受一个类来代替它。class属性将只是一个默认值:

class Bar:
    foo_class = Foo

    def __init__(self, foo_class=None):
        if foo_class is None:
            foo_class = self.foo_class
        self.foo = foo_class()
如果
foo_class
仅由
\uuuu init\uuuu
使用,则可以完全取消class属性,并为参数设置默认值

class Bar:

    def __init__(self, foo_class=Foo):
        self.foo = foo_class()

(如果
Bar.foo\u类
\uu init\uuuu\ucode>之外使用,您可能需要确保使用可能不同的类创建的
self.foo
没有任何问题。)

我一直在理解设计模式方面有困难,但这是工厂模式的应用,不是吗?有人可以确认吗?通过将类ref分配给变量,我们可以轻松地更改所需的类。变化恰巧发生在其中place@Aran-可能是菲?我在看,似乎很清楚,
make_room
可能只是对类的引用,而不是抽象方法。@chepner是的,这也是我的思路。谢谢,解释清楚了。非常感谢。尽管这让我思考——如果你不打算在将来的某个地方更改
Bar.foo_类
,那么这样做真的没有意义吗?YAGNI@taurijuhkam在生产使用中,没有。不过,对于测试来说,它提供了一个方便的钩子,可以用纯值替换具有效果的内容(如数据库连接、I/O等)。例如,
self.foo
可能是生产中的一个文件句柄,但对于测试,您可能需要一个瞬间的
StringIO
。能够用提供静态数据的类替换打开文件的类将使测试更容易理解。感谢您提供了一个用例,使其清晰明了:想象一下在测试中您可能希望在哪里使用
mock.patch
,并设计成您不需要它:)