在类中使用导入

Posted

技术标签:

【中文标题】在类中使用导入【英文标题】:using import inside class 【发布时间】:2016-10-31 10:06:54 【问题描述】:

我对 python 类的概念完全陌生。在寻找了几天的解决方案后,我希望能在这里得到帮助:

我想要一个 python 类,我可以在其中导入一个函数并在那里使用它。主代码应该能够从类中调用函数。因为我在同一个文件夹中有两个文件。


感谢@cdarke、@DeepSpace 和@MosesKoledoye,我编辑了错误,但遗憾的是不是这样。

我仍然收到错误:

test 0
Traceback (most recent call last):
  File "run.py", line 3, in <module>
    foo.doit()
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 8, in doit
    self.timer(5)
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 6, in timer
    zeit.sleep(2)
NameError: global name 'zeit' is not defined


@wombatz 得到了正确的提示: 它必须是 self.zeit.sleep(2) 或 Test.zeit.sleep(2)。导入也可以在类声明之上完成。


Test.Py

class Test:
    import time as zeit
    def timer(self, count):
        for i in range(count):
            print("test "+str(i))
            self.zeit.sleep(2)      <-- self is importent, otherwise, move the import above the class declaration
    def doit(self):
        self.timer(5)

run.py

from test import Test
foo = Test()
foo.doit()

当我尝试python run.py 时出现此错误:

test 0
Traceback (most recent call last):
  File "run.py", line 3, in <module>
    foo.doit()
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 8, in doit
    self.timer(5)
  File "/Users/ls/Documents/Entwicklung/RaspberryPi/test/test.py", line 6, in timer
    sleep(2)
NameError: global name 'sleep' is not defined

我从错误中了解到,类中的导入无法识别。但是如何才能识别类中的导入?

【问题讨论】:

你的意思可能是zeit.sleep(2) @cdarke 实际上是 zeit.sleep,因为 OP 使用 as @DeepSpace:我的编辑跨越了你的评论。谢谢 谢谢,我纠正了错误,但我没有帮助 - 请参阅我的编辑。 python run.py 的第二个回溯中显示的sleep(2) 与您在test.py 中所说的不匹配——那一行有zeit.sleep(2) 【参考方案1】:

类的命名空间中定义的所有内容都必须从该类中访问。这适用于方法、变量、嵌套类以及包括模块在内的所有其他内容。

如果你真的想在一个类中导入一个模块,你必须从那个类中访问它:

class Test:
    import time as zeit
    def timer(self):
        self.zeit.sleep(2)
        # or Test.zeit.sleep(2)

但是你为什么要在类中导入模块呢?尽管希望将其放入该命名空间,但我想不出一个用例。

您确实应该将导入移动到模块的顶部。然后你可以在类中调用zeit.sleep(2),而不需要前缀selfTest

此外,您不应使用非英语标识符,例如 zeit。只会说英语的人应该能够阅读您的代码。

【讨论】:

@syntonym 对不起,我不太明白。你能给我举个例子吗? 对不起,我想我误解了你。我以为你的意思是你总是必须在课堂上使用self.attribute,这当然不是真的,因为你可以使用全局变量或内置函数(如打印)。但是你的意思是类的命名空间中定义的对象不能从类绑定函数自动访问。 @syntonym 是的,我应该澄清一下,谢谢你的提示。 我遇到的一个用例是将 TensorFlow 与多处理一起使用。它仅在每个工作人员导入自己的 TensorFlow 副本时才有效。 @Wombatz 我的用例是文件包含按主题分组的多个类,但其中只有一个需要机器学习。对于想要在不安装机器学习包的情况下导入其他类的用户(他们无论如何都不使用它们),将导入划分为确实使用它们的类是实用的。当然,将类存储在单独的文件中将是一种可行的替代解决方案。【参考方案2】:

sleep 不是 python 内置函数,并且名称原样,不引用任何对象。所以 Python 正确地提出了 NameEror

您打算:

import time as zeit

zeit.sleep(2)

然后将import time as zeit 移动到模块顶部。

别名为zeittime 模块可能不会出现在模块的全局符号表中,因为它是在class 中导入的。

【讨论】:

谢谢,我纠正了错误,但我没有帮助 - 请参阅我的编辑。 @ludwigschuster 查看我的更新:将import time as zeit 移至模块顶部。【参考方案3】:

你想要time.sleep。你也可以使用;

from time import sleep

编辑:在类范围内导入问题已解释 here。

【讨论】:

谢谢,我纠正了错误,但我没有帮助 - 请参阅我的编辑。 @ludwigschuster 您应该通读此处链接的答案。没有理由在您的班级中进行导入。它应该位于模块的顶部。 (注意 - 对于需要在导入之前进行特殊初始化的模块有例外,但这种情况很少见,time 模块绝对不是这种情况)【参考方案4】:

你快到了! sleeptime 模块中的一个函数。这意味着名称sleep 不存在,除非它在time 的上下文中被理解,除非您自己定义它。由于不是您自己定义的,您可以通过运行time.sleep(2) 来访问它。

在您的具体示例中,您使用了:

import time as zeit

你必须跑:

zeit.sleep(2) 

或者,您可以通过运行直接从时间导入睡眠:

from time import sleep
sleep(2)

祝你好运!

您可以在此处阅读有关时间模块的更多信息:https://docs.python.org/2/library/time.html

您可以在此处了解有关导入的更多信息:https://docs.python.org/3/reference/import.html

我强烈推荐在 python 中学习命名空间,这里:https://bytebaker.com/2008/07/30/python-namespaces/

【讨论】:

谢谢,我纠正了错误,但我没有帮助 - 请参阅我的编辑。 将 import 语句移到类定义之上。 import time as zeit 应该在 class Test: 行上方。 @ludwigschuster,你可以试试这个吗?【参考方案5】:

我同意@Wombatz 关于他的解决方案,但我没有足够的声誉来评论他的问题

我发现在类中导入模块的一个用例是我想从配置文件初始化一个类。

假设我的配置文件是

config.py

__all__ = ['logfile', ... ]
logfile = 'myevent.log'
...

在我的主模块中

do_something.py

class event():
    from config import *

    def __init__(self):
        try : self.logfile
        except NameError: self.logfile = './generic_event.log'

现在这种方案的好处是,如果不需要的话,我们不需要在全局命名空间中导入日志文件

然而,在 do_something.py 的开头导入,我将不得不在类中使用全局变量,这在我看来有点难看。

【讨论】:

【参考方案6】:

这可能有点晚了,但我同意不污染模块级命名空间的想法(当然,这可能可以通过更好的模块设计来解决,再加上“显式优于隐式”)。

这就是我要做的。基本思想是这样的:import 是一个隐式分配,其中整个模块对象被分配给一个名称。因此:

class Test:
    import time as zeit
    
    self.zeit = zeit # This line binds the module object to an attribute of an instance created from the class
    
    def timer(self, count):
        for i in range(count):
            print("test "+str(i))
            self.zeit.sleep(2) # This necessitates the `zeit` attribute within the instance created from the class
    
    def doit(self):
        self.timer(5)

【讨论】:

【参考方案7】:
 import importlib



class importery():
    def __init__(self, y,z):
        self.my_name = y
        self.pathy = z
        self.spec = importlib.util.spec_from_file_location(self.my_name, self.pathy)
        x = importlib.util.module_from_spec(self.spec)
        self.spec.loader.exec_module(x)
        print(dir(x))
    
        root = x.Tk()
        root.mainloop()
    
    

pathy = r'C:\Users\mine\Desktop\python310\Lib\tkinter\__init__.py'

importery('tk', pathy)

有一个'时间和地点'来做这种类型的黑魔法,谢天谢地非常罕见的时间和地点。在我发现的少数几个中,我通常能够使用 subprocess 来获得一些其他风格的 python 来完成我的肮脏工作,但这并不总是一种选择。

现在,当我需要同时加载模块的冲突版本时,我在搅拌机中“使用”了它。这不是做事的好方法,真的应该是最后的手段。

如果您是 blender 用户并且碰巧决定犯此罪,我建议在干净版本的 blender 中这样做,在它旁边安装类似版本的 python 以使用它来进行 pip 安装,并且请确保您已将您的配置文件夹添加到您的搅拌机文件夹中,否则这个黑魔法可能会在以后再次咬你。

【讨论】:

以上是关于在类中使用导入的主要内容,如果未能解决你的问题,请参考以下文章

如何在不显式导入的情况下使新的装饰器在类中可用?

在类中写reponse语句

在类中使用犰狳矩阵

如何在类中使用 Pyomo 装饰器

在类中使用联合

友元在类中的使用