在Python中使用module作为类实例

时间:2016-09-12 10:00:56

标签: python class module

TL; DR

基本上问题是向用户隐瞒我的模块具有类实现的事实,以便用户可以像使用my_module.func()

这样的直接函数定义一样使用模块

详细

假设我有一个模块my_module和一个类MyThing。例如:

# my_module.py

class MyThing(object):
    def say():
        print("Hello!")

在另一个模块中,我可能会这样做:

# another_module.py

from my_module import MyThing

thing = MyThing()
thing.say()

但是假设我不想做所有这些。我真正想要的是my_moduleimport上自动创建一个MyThing实例,以便我可以执行以下操作:

# yet_another_module.py

import my_module

my_module.say()

换句话说,无论我在模块上调用什么方法,我都希望它直接转发到包含在其中的类的默认实例。因此,对于模块的用户来说,似乎它中没有类,只是模块本身中的直接函数定义(其中函数实际上是包含在其中的类的方法)。那有意义吗?这样做有一个简短的方法吗?

我知道我可以在my_module中执行以下操作:

class MyThing(object):
    def say():
        print("Hello!")

default_thing = MyThing()

def say():
    default_thing.say()

但是假设MyThing有很多" public"我想要使​​用的方法,然后我必须明确定义"转发"我不想做的每种方法的功能。

作为上述问题的扩展,有没有办法实现上面我想要的,但也能够使用像from my_module import *这样的代码,并能够在另一个代码中直接使用MyThing的方法模块,如say()

3 个答案:

答案 0 :(得分:5)

在模块my_module中执行以下操作:

class MyThing(object):
    ...

_inst = MyThing()
say = _inst.say
move = _inst.move

完全 random module使用的模式

自动执行此操作有点人为。首先,需要找出哪个实例/类属性是要导出的方法...可能只导出不以_开头的名称,如

import inspect
for name, member in inspect.getmembers(Foo(), inspect.ismethod):
    if not name.startswith('_'):
        globals()[name] = member

然而,在这种情况下,我说明确比隐含更好。

答案 1 :(得分:2)

你可以直接替换:

def say():
    return default_thing.say()

使用:

say = default_thing.say

您仍然需要列出转发的所有内容,但样板文件非常简洁。

如果您想用更自动的东西替换该样板,请注意(详细信息取决于Python版本),MyThing.__dict__.keys()['__dict__', '__weakref__', '__module__', 'say', '__doc__']类似。所以原则上你可以迭代它,跳过__ Python内部,并在当前模块上调用setattr(可用作sys.modules[__name__])。您可能会后悔没有在代码中明确列出这些内容,但您当然可以这样做。

或者你可以完全摆脱类,因为使用模块作为封装单位。只要对象上有数据,就用全局变量替换它。 “但是”,你可能会说,“我被警告不要使用全局变量,因为它们会导致问题”。坏消息是你已经创建了一个全局变量default_thing,所以这艘船已经航行了。更糟糕的消息是,如果对象上有任何数据,那么你想要做的整个概念:改变共享全局状态的模块级函数,带有全局变量的大部分问题。

答案 2 :(得分:0)

不确定为什么这不起作用。

say = MyClass().say()
from my_module import *

say
>>Hello!