将模块内的所有函数和 classes 导入 class python
Import all functions and classes inside a module into a class python
我正在尝试将子文件夹中的所有对象导入 python 3.8 中的 class,并且正在努力寻找这样做的方法。我不想手动导入所有对象,因为要列出的文件太多了:
class Foo:
from bar import {
one,
two,
three,
# ...
}
当我使用星号导入所有函数和 classes(例如 from bar import *
)时,出现以下错误:
SyntaxError: import * only allowed at module level
此外,我不想将所有内容都放在子范围内(例如 import bar.package
并将所有文件放在 bar
的 package
子包中),因为函数在 bar
依赖于在 运行 时被传递 self
并且意味着必须将 self
的所有引用更改为 self.package
我只是创建另一个文件夹class 中的方法,因此没有一个非常长的文件。
所以我想我有三个问题:为什么不允许在 class 中导入所有内容,我该如何解决这个问题,是否有更好的方法将多个方法拆分到不同的文件中?
编辑:我已经看到 this post,这是我目前拥有的,但我不想手动导入所有内容,而是想使用 *
。
编辑 2:也许将 class 的子方法创建为一个包并将其作为 self 导入(例如 import bar.package as self
),但这可能会覆盖默认的 self。例如说我有两个文件 foo.py
和 bar.py
:
# foo.py
def print_bar(self):
print("bar")
# bar.py
class Test:
import foo as self
def __init__(self):
print("hi")
self.one = 1
def print_one(self):
print(self.one)
if __name__ == "__main__":
test_class = Test()
test_class.print_one()
test_class.self.print_bar(test_class)
请注意 bar.py
中 运行 的丑陋调用 test_class.self.print_bar(test_class)
。在这种情况下,python 不会自动将 class 作为方法传递。如果我去掉函数中传递的 test_class
参数,它不会 运行 并给出 TypeError
。我想不惜一切代价避免将 self
传递给该方法。
使用 getattr
和 setattr
对 bar
的属性进行 for 循环可以模拟导入所有结果,调用函数的 __get__
方法将return 相同的函数绑定到实例化实例 (see this answer):
# bar.py
def frog(self):
print(f"frog: {self}")
def horse(self):
print(f"horse: {self}")
# foo.py
class Foo:
def __init__(self):
import bar
for object_name in dir(bar):
if not object_name.startswith("__"):
bound_method = getattr(bar, object_name).__get__(
self,
self.__class__
)
setattr(self, object_name, bound_method)
>>> from foo import Foo
>>> f = Foo()
>>> f.frog
<bound method frog of <foo.Foo object at 0x10c961a50>>
>>> f.horse
<bound method horse of <foo.Foo object at 0x10c961a50>>
>>> f.frog()
frog: <foo.Foo object at 0x10c961a50>
>>> f.horse()
horse: <foo.Foo object at 0x10c961a50>
>>>
删除 if
语句以包括额外的、默认的、Python 对象(__package__
、__spec__
等),如果您有其他对象,则对其进行扩展记住过滤器。
请注意,这将需要 class 在通过它访问这些对象之前实例化。
首先:不要这样做。
可能有更好的方法来解决您的具体问题。如果你要为一个class定义大量的相关方法,并且想用模块来组织这些方法,那么给每个模块一个基class,在那些class上定义方法]es,然后使用 sub-classing 将模块中的 classes 合并为一个。见下文。
Why is importing all in a class not allowed
因为 class 语句是一个作用域命名空间,其中 Python、 在编译时 ,需要知道哪些名称被引用为全局变量并区分它们来自当地的名字。这在函数中尤为重要,在函数中,通过了解在编译时使用的名称,本地命名空间得到了高度优化。对于 class 语句,'local' 名称成为 class 属性。 class 语句在涉及动态局部名称时比函数更灵活,但是将任意动态名称列表导入 class 定义从未被视为值得支持的用例。
how can I get around this
您可以检查模块并获取所有与 Python 将导入的名称相同的名称,然后使用 setattr()
或分配给 [=15] 在 class 上动态设置这些名称=] 字典(class 语句是后者实际工作的唯一地方)。 import
statement documentation 列出导入的内容:
- 如果模块定义了
__all__
,则它被用作要导入的名称列表
- 否则将导入所有 public 名称(名称不以
_
开头的所有全局变量)。
因此,下面的代码将实现与在 Foo
的 class 语句中使用 from bar import *
完全相同的效果:
import bar
def _import_all(module, class):
namespace = vars(module)
public = (name for name in namespace if name[:1] != "_")
for name in getattr(module, "__all__", public):
setattr(class, name, namespace[name])
class Foo:
pass
_import_all(bar, Foo)
或者,这肯定更多 'hack-y' 并且取决于内部 Python 实现细节:
import bar
class Foo
locals().update(
(n, getattr(bar, n))
for n in getattr(
bar, "__all__",
(n for n in dir(bar) if n[:1] != "_")
)
)
is there a better way to split multiple methods up into different files?
是的,使用 classes。将所有这些方法放在单独的模块中,每个放在 class 中,然后只需从每个模块中导入那些 classes 并将其用作基础 class:
import bar, spam
class Foo(bar.Base, spam.Base):
pass
其中 bar.py
将定义 Base
class:
class Base:
def print_bar(self):
print("bar")
等 spam
等。您可以根据需要向这些基础混合 class 中添加和删除方法,以及 import
语句来组合基础 classes不会改变。
我正在尝试将子文件夹中的所有对象导入 python 3.8 中的 class,并且正在努力寻找这样做的方法。我不想手动导入所有对象,因为要列出的文件太多了:
class Foo:
from bar import {
one,
two,
three,
# ...
}
当我使用星号导入所有函数和 classes(例如 from bar import *
)时,出现以下错误:
SyntaxError: import * only allowed at module level
此外,我不想将所有内容都放在子范围内(例如 import bar.package
并将所有文件放在 bar
的 package
子包中),因为函数在 bar
依赖于在 运行 时被传递 self
并且意味着必须将 self
的所有引用更改为 self.package
我只是创建另一个文件夹class 中的方法,因此没有一个非常长的文件。
所以我想我有三个问题:为什么不允许在 class 中导入所有内容,我该如何解决这个问题,是否有更好的方法将多个方法拆分到不同的文件中?
编辑:我已经看到 this post,这是我目前拥有的,但我不想手动导入所有内容,而是想使用 *
。
编辑 2:也许将 class 的子方法创建为一个包并将其作为 self 导入(例如 import bar.package as self
),但这可能会覆盖默认的 self。例如说我有两个文件 foo.py
和 bar.py
:
# foo.py
def print_bar(self):
print("bar")
# bar.py
class Test:
import foo as self
def __init__(self):
print("hi")
self.one = 1
def print_one(self):
print(self.one)
if __name__ == "__main__":
test_class = Test()
test_class.print_one()
test_class.self.print_bar(test_class)
请注意 bar.py
中 运行 的丑陋调用 test_class.self.print_bar(test_class)
。在这种情况下,python 不会自动将 class 作为方法传递。如果我去掉函数中传递的 test_class
参数,它不会 运行 并给出 TypeError
。我想不惜一切代价避免将 self
传递给该方法。
使用 getattr
和 setattr
对 bar
的属性进行 for 循环可以模拟导入所有结果,调用函数的 __get__
方法将return 相同的函数绑定到实例化实例 (see this answer):
# bar.py
def frog(self):
print(f"frog: {self}")
def horse(self):
print(f"horse: {self}")
# foo.py
class Foo:
def __init__(self):
import bar
for object_name in dir(bar):
if not object_name.startswith("__"):
bound_method = getattr(bar, object_name).__get__(
self,
self.__class__
)
setattr(self, object_name, bound_method)
>>> from foo import Foo
>>> f = Foo()
>>> f.frog
<bound method frog of <foo.Foo object at 0x10c961a50>>
>>> f.horse
<bound method horse of <foo.Foo object at 0x10c961a50>>
>>> f.frog()
frog: <foo.Foo object at 0x10c961a50>
>>> f.horse()
horse: <foo.Foo object at 0x10c961a50>
>>>
删除 if
语句以包括额外的、默认的、Python 对象(__package__
、__spec__
等),如果您有其他对象,则对其进行扩展记住过滤器。
请注意,这将需要 class 在通过它访问这些对象之前实例化。
首先:不要这样做。
可能有更好的方法来解决您的具体问题。如果你要为一个class定义大量的相关方法,并且想用模块来组织这些方法,那么给每个模块一个基class,在那些class上定义方法]es,然后使用 sub-classing 将模块中的 classes 合并为一个。见下文。
Why is importing all in a class not allowed
因为 class 语句是一个作用域命名空间,其中 Python、 在编译时 ,需要知道哪些名称被引用为全局变量并区分它们来自当地的名字。这在函数中尤为重要,在函数中,通过了解在编译时使用的名称,本地命名空间得到了高度优化。对于 class 语句,'local' 名称成为 class 属性。 class 语句在涉及动态局部名称时比函数更灵活,但是将任意动态名称列表导入 class 定义从未被视为值得支持的用例。
how can I get around this
您可以检查模块并获取所有与 Python 将导入的名称相同的名称,然后使用 setattr()
或分配给 [=15] 在 class 上动态设置这些名称=] 字典(class 语句是后者实际工作的唯一地方)。 import
statement documentation 列出导入的内容:
- 如果模块定义了
__all__
,则它被用作要导入的名称列表 - 否则将导入所有 public 名称(名称不以
_
开头的所有全局变量)。
因此,下面的代码将实现与在 Foo
的 class 语句中使用 from bar import *
完全相同的效果:
import bar
def _import_all(module, class):
namespace = vars(module)
public = (name for name in namespace if name[:1] != "_")
for name in getattr(module, "__all__", public):
setattr(class, name, namespace[name])
class Foo:
pass
_import_all(bar, Foo)
或者,这肯定更多 'hack-y' 并且取决于内部 Python 实现细节:
import bar
class Foo
locals().update(
(n, getattr(bar, n))
for n in getattr(
bar, "__all__",
(n for n in dir(bar) if n[:1] != "_")
)
)
is there a better way to split multiple methods up into different files?
是的,使用 classes。将所有这些方法放在单独的模块中,每个放在 class 中,然后只需从每个模块中导入那些 classes 并将其用作基础 class:
import bar, spam
class Foo(bar.Base, spam.Base):
pass
其中 bar.py
将定义 Base
class:
class Base:
def print_bar(self):
print("bar")
等 spam
等。您可以根据需要向这些基础混合 class 中添加和删除方法,以及 import
语句来组合基础 classes不会改变。