如何正确地从其他文件加载类?



我编写了一系列继承父类Command.py的类,它们彼此位于同一目录中。使用以下语句加载这些类没有问题:

from Command import Command

问题在于,如果我试图在其他地方使用这些类回到几个目录,像这样:

project
├── main.py
└── step_sequencer
└── commands
├── Command.py
├── OtherClasses.py
└── command_parser.py

发生挂起的地方是,我从命令解析器在main.py导入一个函数,似乎我的函数的范围现在是在顶层,所以导入命令不起作用:

main.py:

from Commands.CommandsParser import load_classes, parse
print(load_classes())

command_parser.py:

import sys
import importlib.util
import os
import sys
import inspect
abs_path = os.path.abspath(__file__)
def load_classes():
# blank dictionary of all possible command references
command_references = {}
path = os.path.dirname(os.path.realpath(__file__))
files = os.listdir(path)
print(path)
path_dot = path.replace("/", ".")
path_dot = path_dot.strip('.')
# get list of all .py files in directory except this script
command_filenames = [x for x in files if x.endswith('.py') and x != os.path.basename(__file__) and x !=
'__init__.py']
# bring the Command.py to the front of the list to be loaded in first
command_filenames.insert(0, command_filenames.pop(command_filenames.index('Command.py')))
for cmd_file in command_filenames:
# get rid of extension
command_name = os.path.splitext(cmd_file)[0]

# Original implementation
# module = importlib.import_module('Commands.{0}'.format(command_name))
# module = importlib.import_module(command_name)

# This was my workaround here for this method
spec = importlib.util.spec_from_file_location(command_name, path + '/' + command_name + '.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# iterate over attributes of each module and add classes only
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if inspect.isclass(attribute):
try:
# try to get its type, in order to add it to the dictionary for instant access
command_type = getattr(attribute, 'type')
command_references[command_type] = attribute
except AttributeError:
# class has no type, ignore it, since Command class has no type.
pass
return command_references

Command.py:

import sys
import pyautogui as auto

class Command:
# list to create track of all instantiated objects
instances = []
instance_count = 0
def __init__(self, json):
self.json = json
# append instance of class
Command.instances.append(json['type'])
try:
self.name = json['name']
except KeyError:
# tally up count of instances of said object
for instance in self.instances:
if instance == json['type']:
self.instance_count += 1
# name command with generic command name + instance count
self.name = json['type'] + str(self.instance_count)
def execute(self, commands, counter):
pass
def print(self):
return self.json
def is_valid(self):
pass

ClickMouse.py(子类):

from Command import Command, auto
import sys

class Click(Command):
type = "click"
def __init__(self, json):
super().__init__(json)
try:
self.button = json["button"]
except KeyError:
print("Backend: Error: missing 'button' parameter, set default to left click" )
self.button = "left"
def execute(self, commands, commands_counter):
try:
if self.button != 'double':
auto.click(button=self.button)
else:
auto.doubleClick()
except  auto.PyAutoGUIException:
print(auto.PyAutoGUIException)
sys.exit(1)
def is_valid(self):
return self.button in ['left', 'right', 'middle', 'double']
def print(self):
return ""

能够将此step_sequencer目录带到任何地方并且能够解决路径/导入问题的最佳实践是什么?

main.py访问Command.py,使用:

from step_sequencer.commands import Command

访问Command.py内部的Command类,使用:

from step_sequencer.commands.Command import Command

最新更新