我有一个名为1
的函数,它返回完整的模块限定类名get_full_class_name(instance)
。
示例my_utils.py:
instance
不幸的是,当给定一个在当前运行的脚本中定义的类时,此函数会失败。
示例my_module.py:
def get_full_class_name(instance):
return '.'.join([instance.__class__.__module__,
instance.__class__.__name__])
当我运行上述脚本时,它会打印#! /usr/bin/env python
from my_utils import get_full_class_name
class MyClass(object):
pass
def main():
print get_full_class_name(MyClass())
if __name__ == '__main__':
main()
而不是打印my_module.MyClass
:
__main__.MyClass
如果我从另一个脚本运行上面的$ ./my_module.py
__main__.MyClass
,我会得到所需的行为。
示例run_my_module.py:
main()
运行上面的脚本得到:
#! /usr/bin/env python
from my_module import main
if __name__ == '__main__':
main()
我是否可以编写$ ./run_my_module.py
my_module.MyClass
函数,以便无论get_full_class_name()
是否作为脚本运行,它始终返回my_module.MyClass
?
答案 0 :(得分:0)
我建议使用Find Path to File Being Run中讨论的技术处理案例__name__ == '__main__'
。这导致了这个新的my_utils:
import sys
import os.path
def get_full_class_name(instance):
if instance.__class__.__module__ == '__main__':
return '.'.join([os.path.basename(sys.argv[0]),
instance.__class__.__name__])
else:
return '.'.join([instance.__class__.__module__,
instance.__class__.__name__])
这不处理交互式会话和其他特殊情况(例如从stdin读取)。为此,您可能需要包含detect python running interactively中讨论的技术。
答案 1 :(得分:0)
根据mkiever的回答,我最终将get_full_class_name()
更改为您在下面看到的内容。
如果instance.__class__.__module__
为__main__
,则不会将其用作模块路径。相反,它使用从sys.argv[0]
到sys.path
中最近的目录的相对路径。
一个问题是sys.path
始终包含sys.argv[0]
本身的目录,因此该相对路径最终只是sys.argv[0]
的文件名部分。作为一个快速的黑客,下面的代码假定sys.argv[0]
目录始终是sys.path
的第一个元素,并忽略它。这似乎不安全,但对于我的个人代码来说,更安全的选项对于我们来说太繁琐了。
非常感谢任何更好的解决方案/建议。
import os
import sys
from nose.tools import assert_equal, assert_not_equal
def get_full_class_name(instance):
'''
Returns the fully-qualified class name.
Handles the case where a class is declared in the currently-running script
(where instance.__class__.__module__ would be set to '__main__').
'''
def get_module_name(instance):
def get_path_relative_to_python_path(path):
path = os.path.abspath(path)
python_paths = [os.path.abspath(p) for p in sys.path]
assert_equal(python_paths[0],
os.path.split(os.path.abspath(sys.argv[0]))[0])
python_paths = python_paths[1:]
min_relpath_length = len(path)
result = None
for python_path in python_paths:
relpath = os.path.relpath(path, python_path)
if len(relpath) < min_relpath_length:
min_relpath_length = len(relpath)
result = os.path.join(os.path.split(python_path)[-1],
relpath)
if result is None:
raise ValueError("Path {} doesn't seem to be in the "
"PYTHONPATH.".format(path))
else:
return result
if instance.__class__.__module__ == '__main__':
script_path = os.path.abspath(sys.argv[0])
relative_path = get_path_relative_to_python_path(script_path)
relative_path = relative_path.split(os.sep)
assert_not_equal(relative_path[0], '')
assert_equal(os.path.splitext(relative_path[-1])[1], '.py')
return '.'.join(relative_path[1:-1])
else:
return instance.__class__.__module__
module_name = get_module_name(instance)
return '.'.join([module_name, instance.__class__.__name__])