NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Новые версии PyInstaller больше не устанавливают переменную env
, поэтому отличный ответ Shish не будет работать. Теперь путь устанавливается как sys._MEIPASS
:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
Я обнаружил, что существующие ответы сбивают с толку, и потребовалось много времени, чтобы решить, где проблема. Вот компиляция всего, что я нашел.
Когда я запускаю свое приложение, я получаю сообщение об ошибке Failed to execute script foo
(если foo.py
является основным файлом). Чтобы устранить эту проблему, не запускайте PyInstaller с помощью --noconsole
(или отредактируйте main.spec
, чтобы изменить console=False
=> console=True
). При этом запустите исполняемый файл из командной строки, и вы увидите сбой.
Первое, что нужно проверить, это то, что он правильно упаковывает ваши лишние файлы. Вы должны добавить кортежи, такие как ('x', 'x')
, если вы хотите включить папку x
.
После сбоя не нажимайте OK. Если вы находитесь в Windows, вы можете использовать Искать все . Найдите один из ваших файлов (например, sword.png
). Вы должны найти временный путь, где он распаковал файлы (например, C:\Users\ashes999\AppData\Local\Temp\_MEI157682\images\sword.png
). Вы можете просмотреть этот каталог и убедиться, что он включает все. Если вы не можете найти его таким образом, найдите что-то вроде main.exe.manifest
(Windows) или python35.dll
(если вы используете Python 3.5).
Если программа установки включает все, следующая вероятная Проблема - это ввод-вывод файлов: ваш код Python ищет в каталоге исполняемого файла вместо каталога temp для файлов.
Чтобы исправить это, любой из ответов на этот вопрос работает. Лично я нашел смесь из них всех, чтобы работать: сначала замените каталог в главном файле точки входа, а все остальное работает как есть:
if hasattr(sys, '_MEIPASS'):
os.chdir(sys._MEIPASS)
Вместо того, чтобы переписать весь мой код пути, как было предложено, я сменил рабочий каталог:
if getattr(sys, 'frozen', False):
os.chdir(sys._MEIPASS)
Просто добавьте эти две строки в начале вашего кода, вы можете оставить остальные как есть.
Возможно, я пропустил шаг или сделал что-то не так, но методы, которые выше, не связывают файлы данных с PyInstaller в один файл exe. Позвольте мне поделиться шагами, которые я сделал.
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
a = Analysis(['C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.py'],
pathex=['C:\\Users\\TCK\\Desktop\\Projeler'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
#Add the file like the below example
a.datas += [('Converter-GUI.ico', 'C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico', 'DATA')]
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='Converter-GUI',
debug=False,
strip=False,
upx=True,
#Turn the console option False if you don't want to see the console while executing the program.
console=False,
#Add an icon to the program.
icon='C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name='Converter-GUI')
Заключение: Есть еще несколько файлов в папке dist.
Примечание: я использую Python 3.5.
EDIT: Наконец, он работает с методом Джонатана Рейнхарта.
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
image_path = resource_path("Converter-GUI.ico")
self.window.iconbitmap(image_path)
pyinstaller --onefile your_file.py
pyinstaller your_file.spec
После 6 шага ваш один файл готов к использованию.
a.datas
с шага 5 брал кортежи строк, см. pythonhosted.org/PyInstaller/spec-files.html#adding-data-files для справки.
– Ian Campbell
5 September 2017 в 17:55
Все остальные ответы используют текущий рабочий каталог в случае, когда приложение не установлено PyInstalled (т. е. sys._MEIPASS
не установлено). Это неправильно, так как это мешает вам запускать приложение из каталога, отличного от того, где находится ваш скрипт.
Лучшее решение:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
os.env['_MEIPASS2']
(с использованием среды ОС) был старым способом получения каталога. AFAIK sys._MEIPASS
- единственный правильный метод.
– Jonathon Reinhart
5 January 2018 в 22:50
Незначительное изменение принятого ответа.
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
pyinstaller распаковывает ваши данные во временную папку и сохраняет этот путь к каталогу в переменной среды _MEIPASS2
. Чтобы получить директорию _MEIPASS2
в упакованном режиме и использовать локальный каталог в режиме распаковки (разработки), я использую это:
def resource_path(relative):
return os.path.join(
os.environ.get(
"_MEIPASS2",
os.path.abspath(".")
),
relative
)
Выход:
# in development
>>> resource_path("app_icon.ico")
"/home/shish/src/my_app/app_icon.ico"
# in production
>>> resource_path("app_icon.ico")
"/tmp/_MEI34121/app_icon.ico"
resource_path("file_to_be_accessed.mp3")
. Будьте осторожны, чтобы использовать максимальный ответ для текущей версии PyInstaller.
– Exeleration-G
18 April 2013 в 11:07
--one-file
?
– fatuhoku
9 October 2013 в 13:53
_MEIPASS2
в envs, ноsys._MEIPASS
работает хорошо, поэтому +1. Я предлагаю:path = getattr(sys, '_MEIPASS', os.getcwd())
– kbec 28 February 2013 в 16:22AttributeError
вместо более общегоException
. Я столкнулся с проблемами, когда мне не хватало импорт sys, а путь молча отключился доos.path.abspath
. – Aaron 9 February 2016 в 02:00images/background.png
попадает вimages/background.png/background.png
) (каталог с именем файла). Не уверен, что этот код учитывает это; Я добавил изменение, которое делает, но я все еще получаю крах при доступе к ресурсам. – ashes999 18 December 2016 в 05:41