Попытка передачи мутабельного значения результата метода: Попытка передачи мутабельного значения результата метода найтизадания

Содержание

код ошибки 80010108 windows 7

Код Ошибки 80010108Rating: 3,5/5 8397 reviews

Если Вы в тупике, покажите Ваш код (или часть кода) здесь. Если вылазит. Run-time error ‘-2147417848 ( 80010108)’: Automation error.

Закрыты отчёты об ошибках, связанные с работой игр и 8539 VMXBuider 0.8 (VB6 app) fails to create new VM, reporting «Run-time error ‘-2147417848 ( 80010108)’: Automation error » Чистка кода DirectDraw.

Коды ошибок 1Сv8

Код Ошибки 80010108 Windows 7

VBA Ошибка VBA: Run time error ‘-2147417848 ( 80010108)’: Method слушай, а у меня твой код (хоть он и излишне замороченный) с.

Что такое макросы, куда вставлять код макроса на Visual Basic. по ошибке Run-Time Error -2147417848 ( 80010108) Automation error и.

В настройках Windows на сервере должна быть включена роль «Сервер приложений» (Application Server) Прочитать статью на ИТС. Если клиент и сервер в разных подсетках (доменах), на сервере в локальную группу «Пользователи DCOM» пропишите пользователя клиента. Члены этой группы могут запускать, активизировать и использовать объекты DCOM на этом компьютере. Проблема: После выбора информационной базы (но до логина в 1с) возникает ощибка «Объект сервера 1С предприятия не обнаружен. 800706BF». Решение: 1) Права пользователя. Возможно, что пользователь, от имени которого запускается клиентское приложение не зарегистрирован и не доступен компьютеру сервера 1С:Предприятия. 2) Проверьте на клиентском компьютере настройки DCOM. dcomcnfg/ Default protocols: — Connection oriented TCP/IP dcomcnfg/ Default properties: — Enable distributed COM on this computer — Default authentication level: Connect — Default impersonation level: Identify 3) Попробуйте на серверном и клиентском компьютере понизить уровень аутентификации: Default authentication level: None 4) Проверьте, не установлено ли сетевых экранов. Откройте порт 135 и те, которые указаны на клиенте и сервере в диалоге: dcomcnfg/ Default protocols/ Properties/ Post Ranges. Если там диапазонов портов не указано — задайте их. Проблема: Ошибка соединения с сервером 1С:Предприятия 8.0: Неправильный путь к файлу C:\\W Решение: Возможная причина ошибки в том, что для пользователя USER1CV8SERVER не заданы переменные окружения TEMP и TMP, поэтому при создании новой базы временные файлы пытаются быть созданными в корне диска C: Проблема: Ошибка создания информационной базы: Компоненты OLE DB провайдера не найдены Решение: Такое сообщение может быть выдано, если сервер 1С:Предприятия не смог создать COM объект OLE DB Provider for Microsoft SQL Server. Ознакомьтесь с разделом «Администрирование/ Установка и настройка/ Сервер 1С:Предприятия и SQL-сервер» на диске ИТС. 1) Найдите в Registry ветку HKEY_CLASSES_ROOT\\CLSID\\{0C7FF16C-38E3-11d0-97AB-00C04FC2AD98}\\InprocServer32 Какой маршрут до файла SQLOLEDB.DLL является значением параметра default? Убедитесь, что в этом каталоге этот файл есть. 2) Убедитесь, что каталог с файлом SQLOLEDB.DLL доступен пользователю USER1CV8SERVER. Для этого к списку пользователей, имеющих права на каталог можно добавить пользователя USER1CV8SERVER или группу everyone. 3) Запустите утилиту Microsoft SQL Server Client Network Utility. На закладке General установите протокол TCP/IP. На закладке Network Libraries посмотрите маршрут сетевой библиотеки для протокола TCP/IP. Убедитесь, что она присутствует в указанном каталоге и пользователь USER1CV8SERVER имеет доступ в этот каталог. Попробуйте переустановить MDAC. Убедитесь, что у пользователя, от имени которого стартует сервер 1С:Предприятия, есть права на каталог, содержащий компоненту OLE DB провайдера, и на файлы в этом каталоге. Проблема: При попытке добавить базу с локальной станции, 1C предлагает только вариант выбора файлового варианта базы. Решение: На появление меню выбора вида создания базы (файловая или на сервере Предприятия) может влиять только ключ. Если ключа нет, то платформа может быть максимум базовой, а базовая не работает с сервером, поэтому этого меню нет. Если же оно есть, но недоступно, то возможно не установлены компоненты доступа к серверу на этой локальной станции. Проблема: Выдается ошибка «Не удалось зафиксировать файл базы данных для открытия или изменения …/1cv8.1CD» Решение: Фиксация файла базы данных – это разновидность внутренней блокировки, которая требуется, чтобы на некоторое непродолжительное время обеспечить целостность структуры файла при выполнении операций чтения данных или фиксации транзакции. При чтении требуется, чтобы эти структура файла была в целостном состоянии, а при фиксации транзакции структура может изменяться. При нормальной работе такая ошибка возникать не должна. Суть сводится к следующему: для выполнения фиксация результатов транзакции может потребоваться выполнить перестройку внутренних структур данных файла *.1cd. А для выполнения чтения данных необходимо гарантировать, чтобы такая перестройка структур данных не выполнялась. Для обеспечения согласования этих операций имеется механизм внутренних блокировок, называемых фиксацией. Фиксация выполняется с ожиданием. В то же время предполагается, что фиксация выполняется на непродолжительное время, меньшее, чем время ожидания. Таким образом, если упомянутая ошибка возникла, то имеет место некоторое нарушение нормального хода событий. Мы наблюдали такую ситуацию и уже описывали ее в партнерской конференции. Вкратце все выглядит примерно так. В какой-то момент времени запрос на блокировку участка файла (функция LockFile() Win32 API) выдает ошибку Network error. В результате возникает ошибка движка файловой базы данных «Не удалось зафиксировать файл базы данных для открытия или изменения». Природа ошибки нам пока непонятна. Известно только, что она возникает далеко не у всех. Не отмечено никакой связи возникновения этой ошибки с версией 1С:Предприятия 8.0 и используемой конфигурацией. По-видимому речь идет о каких-то особенностях некоторых сетей. Вполне возможно, что проблема возникает из за нестабильности работы сети Один из способов проверить — выполнить команду: ping [Имя сервера] -t на компьютере, с которого запускается 1с после чего запустить 1с и посмотреть, что будет происходить … 80004027 — приложение 1CV8 или сомпонента v8.server.1 выключена, если сервер на Windows Server 2003. См. статью «Особенности настройки Windows Server 2003 при установке сервера 1С:Предприятия 8.0» на диске ИТС. 00000005, 00000041, 80070005, 80080005, 80000009, 80030005, 8001011B — клиент не имеет прав на доступ к серверу (access denied). Выполните рекомендации статьи «Вопросы установки и настройки 1C:Предприятия 8.0 в варианте «клиент-сервер»» из раздела методической поддержки 1С:Предприятия 8.0 на диске ИТС. 800706BA, 800706BE — на сервере произошло неожиданное исключение. Сервер упал. Нужны записи из Event Log с сервера. 80010108 — внутренняя ошибка клиентского приложения. Нужны записи Event Log клиентского компьютера и описание действий, выполнявшихся в это время. 80070776 — Запустить DcomCnfg.exe и проверить протокол для DCOM Должен быть TCP/IP с ориентацией на подключения 8000401A — В свойствах COM+ приложения 1CV8 на серверном компьютере на закладке Identity установлен Interactive user, но никакой пользователь интерактивно не вошел в серверный компьютер. 8001011C — На клиентском компьютере запрещено использование DCOM. Помогает запустить на клиентском компьютере dcomcnfg.exe и на закладке Default Properties установить флаг Enable distributed COM on this computer. 80070721 — Ошибка возникает при рассогласовании протоколов аутентификации между DCOM клиентом и сервером в том случае, если для связи между ними используется Microsoft Internet Information Services (IIS). Возможно, для DCOM используется протокол Tunneling TCP/IP. Установите на компьютере — сервере 1С:Предприятия и на клиентских компьютерах для DCOM протокол Connection-oriented TCP/IP. Ошибка блокировки при транзакциях Microsoft OLE DB Provider for SQL Server: Transaction (Process ID 55) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. HRESULT=80004005, SQLSTATE=40001, native=1205 Возникает при конфликте транзакций, часто при записи объектов. Ошибка блокировки при транзакциях 2 Microsoft OLE DB Provider for SQL Server: Lock request time out period exceeded. HRESULT=80040E31, SQLSTATE=HYT00, native=1222 Истек тайм-аут. Более 256 таблиц в запросе Ошибка выполнения запроса «Построенный запрос к СУБД использует слишком много таблиц. Допустимо не более 256.» Когда в запросе идет обращение более, чем к 256 таблицам. Ошибки: 00000005, 00000041, 80070005, 80000009, 80030005, 8001011B Возникают в тех случаях, когда пользователь, от имени которого работает клиентское приложение, не имеет прав доступа к каким-либо ресурсам. В частности, это может означать, что пользователю, от имени которого стартовало клиентское приложение 1С:Предприятия, недоступны либо средства COM+ того компьютера, на котором установлен сервер, либо зарегистрированное на нем COM+ приложение 1CV8, которое является сервером 1С:Предприятия. Если эта ошибка возникает во внешнем соединении 1С:Предприятия, то это означает отсутствие соответствующих прав у пользователя того приложения, которое обратилось к внешнему соединению. Это может быть любое интерактивное приложение или, например, WEB-сервер. В частности, если в качестве WEB-сервера используется Microsoft Internet Information Services, то таким пользователем может быть пользователь IUSR_ или ASPNET. Методика настройки прав доступа пользователей к COM+ серверу описана в разделах «Вопросы установки и настройки 1C:Предприятия 8.0 в варианте «клиент-сервер»» и «Особенности использования внешнего соединения 1С:Предприятия в WEB-приложениях». (С) ИТС Ошибка 80010108 Может возникнуть в том случае, если клиентское приложение некоторое время (несколько минут) находилась в неактивном состоянии, например из-за засыпания компьютера или долгого ожидания на точке останова в отладчике. Причиной этого является особенность механизма DCOM, обеспечивающего принудительный разрыв соединения с сервером, если клиент долго не проявлял активность. (C) ИТС Ошибка 80010005 Может возникнуть в клиентском приложении в процессе обращения к серверу 1С:Предприятия, если при перерисовке экрана клиентское приложение обратилось к серверу 1С:Предприятия повторно. Это может быть проявлением внутренней ошибки клиентского приложения 1С:Предприятия. Для ее оперативного исправления желательно описать обстоятельства ее возниконовения и обратиться на линию технической поддержки 1С:Предприятия 8.0. (C) ИТС Ошибки 800706BA, 800706BE Сигнализируют об аварийной ситуации на сервере 1С:Предприятия, которая привела к его автоматическому перезапуску. (С) ИТС Ошибка 0х80080005: Server execution failed Одной из причин возникновения этой ошибки явлются проблемы с подсистемой COM+, являющейся частью операционной системы. При возникновении такой ошибки, как правило, в системные журналы событий также записываются события с источником COM+, именем серверного приложения System Application и указанием файла Comsvcs.dll. Существуют процедуры восстановления работоспособности COM+, однако они дают желаемый результат не всегда. Описания официально рекомендованных процедур можно найти в http://support.microsoft.com/default.aspx?scid=kb;en-us;315296 (или похожей http://support.microsoft.com/default.aspx?scid=kb;en-us;318731), однако по результатам практических применений рекомендуется процедура, описанная в http://www.jsifaq.com/subN/tip6900/rh6951.htm. Эта последовательность шагов дополнена по сравнению с официальной и может быть использована в операционных системах 2000/XP/2003. Ниже приводится ее перевод на русский язык. Для восстановления поврежденного каталога COM+: 1. Переименуйте каталог %SystemRoot%\\System32\\Clbcatq.dll в %SystemRoot%\\System32\\~Clbcatq.dll (обратите внимание на появление тильды в имени каталога). 2. Перезагрузите компьютер. 3. Удалите из системного реестра ключ COM3, расположенный в ключе HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft. 4. Запустите командную консоль CMD.EXE. 5. Наберите pushd %SystemRoot% и нажмите Enter. 6. Наберите rd /s /q Registration и нажмите Enter. 7. Наберите popd и нажмите Enter. 8. Наберите exit и нажмите Enter. 9. Удалите слово Hide из строки, начинающейся с COM=, в файле %SystemRoot%\\Inf\\Sysoc.inf. Для редактирования файла можно использовать Notepad. 10. Для Windows XP: * Запустите командную консоль CMD.EXE. * Наберите regsvr32 /s ole32.dll и нажмите Enter. * Наберите regsvr32 /s oleaut32.dll и нажмите Enter. * Наберите exit и нажмите Enter. 11. Запустите панель управления Установка/Удаление программ и выберите пункт Добавление\\удаление компонент Windows. 12. Нажмите Next и переустановите COM+. Замечание: Если механизм защиты системных файлов Windows File Protection блокирует одно или несколько из вышеприведенных действий, то необходимо выполнять эти действия в безопасном режиме (Safe Mode). http://users.v8.1c.ru/Adm433.aspx Ошибка записи/проведения Ошибка при вызове метода контекста (Записать): Операция не выполнена ! Возникает, если в модуле записи/проведения присвоить Отказ=истина Ошибка преобразования данных XML возникает при рассинхронизации структуры данных (конфигурации) между узлами распределенной базы В базе нет пользователя с административными правами При редактировании списка пользователей роли берутся только из конфигурации БД. Обновить конфигурацию БД (F7). Попытка передачи мутабельного значения на сервер 1С:Предприятия Возникает только в клиент-серверной версии (SQL). Для исправления ошибки нужен программист. Если у вас типовая конфигурация, попробуйте обновить ее до последнего релиза. Мутабельный — изменяемое. На сервер 1С можно передавать значения только примитивных типов данных. Клиентский поток исполняется на сервере. Удалить клиента веременно невозможно v8: Клиентский поток исполняется на сервере. Удалить клиента веременно невозможно Однако не обязательно перезапускать сервер приложений (выгоняя всех пользователей), чтобы убить зависший таким образом процесс. Достаточно найти этот процесс на SQL сервере и убить его на SQL сервере. Ошибка SDBL: Поля ‘CAST (Q_000_T_001/Recorder AS REF(Document4055)/Fld4092’ и ‘CAST (Q_000_T_001/Recorder AS REF(Document123)/Fld2322’ не совместимы по типам.(pos=10173) В документах «Приходный кассовый ордер» и «Расходный кассовый ордер» реквизит «Основание» имеет в свойстве «Неограниченная длина» включенный флаг , надо снимать флаг и указать длину этого реквизита «Ошибка SQL: Поле не найдено «MaxGetCode « Эта ошибка выдается в файловом варианте, когда клиенты разных версий одновременно работают с ИБ в файловом варианте. Ошибка «Внутренняя ошибка 2738» Решение: Попробуйте переустановить Windows Script http://www.microsoft.com/downloads/details.aspx?displaylang=ru&FamilyID=c717d943-7e4b-4622-86eb-95a22b832caa. Проблема: При установке релизов конфигураций 8.1, начиная с УПП 1.2.6.2, БП 1.5.6.3, под ОС Windows Vista с включенным UAC выдается сообщение «Ошибка при инсталляции». Решение: Начиная с релизов конфигураций УПП 1.2.6.2 и БП 1.5.6.3 для 8.1 введена цифровая подпись. Для подписанных программ виртуализация защищенных каталогов отключена, в том числе и для каталога Program Files, в который записываются шаблоны конфигураций по умолчанию. При включенном UAC прав на запись в этот каталог нет, что и вызывает ошибку записи. Для решения проблемы установки необходимо либо отключать UAC, либо устроить каталог шаблонов в другом месте, доступном для записи. Источник: http://forum.itland.ru/?showtopic=13043 См. также http://www.mista.ru/articles1c/1cv8_setup.htm

Известные нам коды ошибок приложения 1С, которые можно отловить с. 80010108 — внутренняя ошибка клиентского приложения.

Ошибки 1с и как их устранять. Наиболее частые ошибки «1С» и методы их исправления. Выгрузить и загрузить данные XML

Одной из самых неприятнейших встречающихся ошибок при работе с 1С 8.3 или 8.2 является «Ошибка формата потока». Причин ее появления может быть множество и их не всегда легко установить. При этом окно уведомления об ошибке далеко не эталон информативности.

Первым делом попробуйте подумать над тем, что же всё-таки могло привести к данной неполадке.

Наиболее распространенные причины

Самой распространенной причиной ошибки формата потока является неправильная обработка кэша программой 1С 8. Вспомните, не было ли перебоев электропитания до ее возникновения, обновления конфигурации? Корректно ли был завершен сеанс работы пользователя? Зачастую в таком случае ошибка формата потока будет возникать не на всех компьютерах. Проблемы лучше предупреждать, чем потом исправлять, поэтому рекомендуется использовать источники бесперебойного питания на компьютерах.

Ошибка может появляться на всех компьютерах, но при этом только при чтении каких-либо данных, например: при формировании определенного отчета, при загрузке базы, при запуске конфигуратора. В таком случае вероятнее всего, что эти данные были повреждены и программа не может обработать «битую» информацию.

Как исправить ошибку формата потока

  1. Первым делом попробуйте . Если на одном компьютере программа работает нормально, а на другом появляется ошибка формата потока, то, скорее всего этот способ именно для вас.
  2. В том случае, если очистка кэша не помогла, попробуйте открыть информационную базу в режиме конфигуратора и запустите .
  3. Если вам не удалось зайти в конфигуратор, но база файловая – воспользуйтесь ChDBFl.exe. Данная утилита является аналогом тестирования и исправления ошибок в конфигураторе, но более простым.
  4. Убедитесь, что все текущие пользователи данной информационной базы используют одинаковую версию платформы. Если версии различаются, то установите всем актуальные.
  5. Если 1С запускается в режиме «Предприятие», то выгрузите все данные при помощи универсальной выгрузки/загрузки в новую базу.
  6. Отключите, а при необходимости удалите все фаерволы и антивирусы.
  7. Если данная информационная база клиент – серверная, то проверьте, хватает ли дискового пространства на сервере в папке для хранения временных данных.
  8. Удалите платформу 1С (через панель управления) и установите заново.
  9. Если информационная база открывается в конфигураторе, попробуйте выгрузить ее в файл *.dt и загрузить в пустую.
  10. Воспользоваться HEX-редактором, заменив содержимое чистой базы содержимым той, в которой произошла ошибка.

Если все эти способы вам не помогли, что маловероятно, то тут только бубен в помощь или квалифицированный специалист.

Такая проблема, как Ошибка формата потока, в 1С 8.3 встречается достаточно часто. Рассмотрим, как исправить данную ошибку.

Что же такое ошибка формата потока в 1с 8.3?

Такое происходит в следующих ситуациях:

  1. Ошибка формата потока при запуске 1С Предприятия 8.2 или конфигуратора обычно связана с проблемами в кеше. Обычно она вызвана неправильным выключением системы вследствие, например, отключения электричества. Поэтому настоятельно рекомендуется ставить блоки бесперебойного питания, чтобы не потерять важную информацию. Часто ошибка появляется при запуске базы после обновления конфигурации.
  2. Вторая ситуация — при формировании какого-либо отчета, например, открытии отчета , проведении документа, открытии документа и т.д. Часто это связано именно с содержанием информации в базе данных. Причиной этой ошибки чаще всего является наличие «битой» информации внутри системы.

Получите 267 видеоуроков по 1С бесплатно:

Исправление

  1. Как правило, для решения данной проблемы достаточно почистить временные файлы в системе. .
  2. Если не помогло, но есть возможность попасть в конфигуратор, запустите .
  3. Если доступа в конфигуратор нет, и база тестовая — воспользуйтесь , которая располагается в папке программы.
  4. Если вышеперечисленные методы не помогают, но запускается режим 1С предприятие, выгрузите данные в новую базу с помощью обработки « «. Однако при этом возможны потери данных.
  5. Обновление . Еще одной причиной может стать наличие активных сеансов пользователей с разной версией клиентской части платформы 1С. То есть, например, в базе работает пользователь с платформой 1С 8.3.5.1517, а пытается подключиться другой, с версией 8.3.5.1444.

Если это не помогло — есть более изощренные способы решения данной проблемы. Например, с помощью HEX-редактора. Если Вам необходима квалифицированная помощь программистов 1С, обратитесь к нам! Подробности на странице


Последняя редакция №22 от 15.07.08 | История
URL:
Ключевые слова: ошибка,исключение,попытка, 80004005, 80040E31, 00000005, 00000041, 80070005, 80000009, 80030005, 8001011B, 80010108, 80010005, 800706BA, 800706BE, 80080005,SDBL,pos,CAST

Предлагаю всем дружно составить перечень ошибок 1С 80 и какое сообщение об этой ошибке можно получить для анализа в функции ОписаниеОшибки().

Просьба соблюдать формат и дословно приводить текст ошибки.

Ошибка блокировки при транзакциях

Microsoft OLE DB Provider for SQL Server: Transaction (Process ID 55) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

HRESULT=80004005, SQLSTATE=40001, native=1205

Возникает при конфликте транзакций, часто при записи объектов.

Ошибка блокировки при транзакциях 2

Microsoft OLE DB Provider for SQL Server: Lock request time out period exceeded.

HRESULT=80040E31, SQLSTATE=HYT00, native=1222

Истек тайм-аут.

Более 256 таблиц в запросе

Ошибка выполнения запроса «Построенный запрос к СУБД использует слишком много таблиц. Допустимо не более 256.»

Когда в запросе идет обращение более, чем к 256 таблицам.

Ошибки: 00000005, 00000041, 80070005, 80000009, 80030005, 8001011B
Возникают в тех случаях, когда пользователь, от имени которого работает клиентское приложение, не имеет прав доступа к каким-либо ресурсам. В частности, это может означать, что пользователю, от имени которого стартовало клиентское приложение 1С:Предприятия, недоступны либо средства COM+ того компьютера, на котором установлен сервер, либо зарегистрированное на нем COM+ приложение 1CV8, которое является сервером 1С:Предприятия.

Если эта ошибка возникает во внешнем соединении 1С:Предприятия, то это означает отсутствие соответствующих прав у пользователя того приложения, которое обратилось к внешнему соединению. Это может быть любое интерактивное приложение или, например, WEB-сервер. В частности, если в качестве WEB-сервера используется Microsoft Internet Information Services, то таким пользователем может быть пользователь IUSR_ или ASPNET.

Методика настройки прав доступа пользователей к COM+ серверу описана в разделах «Вопросы установки и настройки 1C:Предприятия 8.0 в варианте «клиент-сервер»» и «Особенности использования внешнего соединения 1С:Предприятия в WEB-приложениях».

(С) ИТС

Ошибка 80010108
Может возникнуть в том случае, если клиентское приложение некоторое время (несколько минут) находилась в неактивном состоянии, например из-за засыпания компьютера или долгого ожидания на точке останова в отладчике. Причиной этого является особенность механизма DCOM, обеспечивающего принудительный разрыв соединения с сервером, если клиент долго не проявлял активность.
(C) ИТС

Ошибка 80010005
Может возникнуть в клиентском приложении в процессе обращения к серверу 1С:Предприятия, если при перерисовке экрана клиентское приложение обратилось к серверу 1С:Предприятия повторно. Это может быть проявлением внутренней ошибки клиентского приложения 1С:Предприятия. Для ее оперативного исправления желательно описать обстоятельства ее возниконовения и обратиться на линию технической поддержки 1С:Предприятия 8.0.

(C) ИТС

Ошибки 800706BA, 800706BE
Сигнализируют об аварийной ситуации на сервере 1С:Предприятия, которая привела к его автоматическому перезапуску.
(С) ИТС

Ошибка 0х80080005: Server execution failed
Одной из причин возникновения этой ошибки явлются проблемы с подсистемой COM+, являющейся частью операционной системы. При возникновении такой ошибки, как правило, в системные журналы событий также записываются события с источником COM+, именем серверного приложения System Application и указанием файла Comsvcs.dll. Существуют процедуры восстановления работоспособности COM+, однако они дают желаемый результат не всегда. Описания официально рекомендованных процедур можно найти в http://support.microsoft.com/default.aspx?scid=kb;en-us;315296 (или похожей http://support.microsoft.com/default.aspx?scid=kb;en-us;318731), однако по результатам практических применений рекомендуется процедура, описанная в http://www.jsifaq.com/subN/tip6900/rh6951.htm . Эта последовательность шагов дополнена по сравнению с официальной и может быть использована в операционных системах 2000/XP/2003. Ниже приводится ее перевод на русский язык.

Для восстановления поврежденного каталога COM+:

1. Переименуйте каталог %SystemRoot%\System32\Clbcatq.dll в %SystemRoot%\System32\~Clbcatq.dll (обратите внимание на появление тильды в имени каталога).
2. Перезагрузите компьютер.
3. Удалите из системного реестра ключ COM3, расположенный в ключе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.
4. Запустите командную консоль CMD.EXE.
5. Наберите pushd %SystemRoot% и нажмите Enter.
6. Наберите rd /s /q Registration и нажмите Enter.
7. Наберите popd и нажмите Enter.
8. Наберите exit и нажмите Enter.
9. Удалите слово Hide из строки, начинающейся с COM=, в файле %SystemRoot%\Inf\Sysoc.inf. Для редактирования файла можно использовать Notepad.
10. Для Windows XP:
* Запустите командную консоль CMD.EXE.
* Наберите regsvr32 /s ole32.dll и нажмите Enter.
* Наберите regsvr32 /s oleaut32.dll и нажмите Enter.
* Наберите exit и нажмите Enter.
11. Запустите панель управления Установка/Удаление программ и выберите пункт Добавление\удаление компонент Windows.
12. Нажмите Next и переустановите COM+.
Замечание: Если механизм защиты системных файлов Windows File Protection блокирует одно или несколько из вышеприведенных действий, то необходимо выполнять эти действия в безопасном режиме (Safe Mode).
http://users.v8.1c.ru/Adm433.aspx

Ошибка записи/проведения

Ошибка при вызове метода контекста (Записать): Операция не выполнена!

Возникает, если в модуле записи/проведения присвоить Отказ=истина

Ошибка преобразования данных XML

возникает при рассинхронизации структуры данных (конфигурации) между узлами распределенной базы

В базе нет пользователя с административными правами
При редактировании списка пользователей роли берутся только из конфигурации БД. Обновить конфигурацию БД (F7).

Попытка передачи мутабельного значения на сервер 1С:Предприятия
Возникает только в клиент-серверной версии (SQL). Для исправления ошибки нужен программист. Если у вас типовая конфигурация, попробуйте обновить ее до последнего релиза.
Мутабельный — изменяемое. На сервер 1С можно передавать значения только примитивных типов данных.

Клиентский поток исполняется на сервере. Удалить клиента веременно невозможно
v8: Клиентский поток исполняется на сервере. Удалить клиента веременно невозмож

Однако не обязательно перезапускать сервер приложений (выгоняя всех пользователей), чтобы убить зависший таким образом процесс.
Достаточно найти этот процесс на SQL сервере и убить его на SQL сервере.

Ошибка SDBL: Поля «CAST (Q_000_T_001/Recorder AS REF(Document4055)/Fld4092» и «CAST (Q_000_T_001/Recorder AS REF(Document123)/Fld2322» не совместимы по типам.(pos=10173)

В документах «Приходный кассовый ордер» и «Расходный кассовый ордер» реквизит «Основание» имеет в свойстве «Неограниченная длина» включенный флаг, надо снимать флаг и указать длину этого реквизита

«Ошибка SQL: Поле не найдено «MaxGetCode»

Эта ошибка выдается в файловом варианте, когда клиенты разных версий одновременно работают с ИБ в файловом варианте.

Причин возникновения таких ошибок может быть множество. Первое, что имеет смысл делать в случае возникновения таких ошибок — определиться с источником проблемы.

    Уточнить обстоятельства и сроки появления ошибки: неисправность, которая не может быть воспроизведена, возможно, является просто случайностью, сбоем.

    Проверить работу программы с другого компьютера и от другой учётной записи пользователя.

    Проверить релизы платформы и конфигурации: соответствует ли текущая версия последней официальной.

В дальнейшем, если вы не справитесь с ошибкой самостоятельно, вам надо будет объяснить природу её появления специалисту, соответственно, эти вопросы возникнут в любом случае.

Есть целый ряд ошибок, возникающих при использовании нелицензионного программного обеспечения (как продуктов «1 °C» , так и, например, операционной системы «Windows»). Характерный пример в случае «ломаной» платформы «1С»: патч, взламывающий конкретную версию платформы, перестаёт работать после установки новой версии платформы, вход в базу в этом случае приведёт к появлению сообщения «Не обнаружено свободной лицензии».

Важно! Не забывайте делать резервную копию ваших баз прежде чем изменять что бы то ни было в конфигурации. В случае когда база не открывается с помощью конфигуратора, следует скопировать папку с базой средствами операционной системы и далее выполнять все операции с этой копией.

Версии конфигураций должны быть актуальны (это особенно важно в случае конфигураций, на основе которых создаётся регламентированная отчетность). Обновление до текущей версии будет первым шагом всех без исключения специалистов-разработчиков, в случае если вы обратитесь к ним. После проверки актуальности версий конфигураций следует проверить актуальность релиза платформы (здесь следует учитывать рекомендации «1С»: не все релизы конфигураций соответствуют релизам платформы).

ОшибкаМетоды исправления

База не открывается

    Обновление платформы.

    Очистка временных (cash) файлов: удалить базу из списка и подключить её же заново.

    Вход в базу от другой учётной записи.

Ничего не работает без видимых причин

    Обновление платформы.

    Поиск причины сбоя в журнале регистрации.

Dump базы при запуске

    Отключение аппаратное ускорения видеокарты средствами Windows, перезагрузка системы.

База открывается в конфигураторе, но не в пользовательском режиме

    Обновление платформы.

    Очистка временных (cash) файлов.

    Вход в базу от другой учётной записи (и/или от записи администратора).

    Вход в базу с другого компьютера (чтобы исключить общую неисправность текущего).

    Тестирование тестирования физической целостности базы с помощью утилиты «chdbfl» (папка C:\Program Files (x86)\1cv8\8.x.x.xxx\bin\chdbfl.exe) или, в случае базы-SQL , — тестирование средствами SQL.

    Тестирование и исправление ИБ средствами конфигуратора.

Программа без предупреждения открывает код конфигуратора

    Обновление платформы.

    Очистка временных (cash) файлов.

    Проверка кода в отладчике.

Как правило, такая ситуация возникает из-за ошибок в изменённом коде, чаще всего — в случае нетиповых конфигураций.

Программа работает по-разному для разных пользователей

    Обновление платформы.

    Очистка временных (cash) файлов.

    Настройка прав групп.

    Настройка прав пользователя.

Неправильное отображение блоков формы

    Обновление платформы.

    Очистка временных (cash) файлов.

    Вход в базу от другой учётной записи (и/или от записи администратора).

    Вход в базу с другого компьютера (чтобы исключить общую неисправность текущего).

Программа не работает на каком-то компьютере в работающей сети, но работает на остальных

    Проверка сетевых прав данного компьютера (средствами Windows).

    Обновление платформы. В том числе следует проверить соответствие релизов конфигураций и платформы в пределах сети.

    Очистка временных (cash) файлов.

    Вход в базу от другой учётной записи (и/или от записи администратора).

Недостаточно памяти

    Обновление платформы.

    Очистка временных (cash) файлов.

    Вход в базу от другой учётной записи (и/или от записи администратора).

    Вход в базу с другого компьютера (чтобы исключить общую неисправность текущего).

    Оптимизация проблемных запросов.

    Аппаратное увеличение объёма памяти.

    Увеличение размера файла подкачки.

    Управление выделенной памятью через командную строку Windows. Строка: «bcdedit /set increaseuserva 3072», где 3072 — размер желаемой адресной памяти.

Ошибка СУБД, внутренняя ошибка компоненты dbeng8

    Обновление платформы на всех компьютерах сети.

    Тестирование тестирования физической целостности базы с помощью утилиты «chdbfl»ю.

Эта ошибка характерна для сетей без сервера «1С» и связана с различием кода разных версий платформы на различных точках доступа.

Случаются ситуации, когда при работе с 1С 8.3 или 8.2 у вас появляется ошибка «Ошибка СУБД: Внутренняя ошибка компоненты dbeng8». Конечно же, описание ее не настолько информативно, как бы нам этого хотелось.

В данном случае, скорее всего, нарушена структура внутреннего хранилища таблиц в БД используемого вами прикладного решения. Не отчаивайтесь, ошибка лечится и, если вы воспользуетесь всеми нашими советами, то с большой вероятностью сможете ее исправить.

Обратите внимание, что прежде, чем приступать к ниже описанным методам, обязательно . Не стоит создавать себе лишних проблем.

В подобных случаях, как и с исправлением чего угодно, всегда лучше начинать от простого к сложному. Поэтому, первым делом нужно установить самую свежую версию платформы 1С. Если же вы уже используете ее, либо по каким-то соображениям не хотите обновлять, можно просто заменить библиотеку «dbeng8.dll», взяв его из каталога с другой установленной программой, как на вашем ПК, так и на другом.

В нашем случае она расположена в каталоге «D:\Program Files (x86)\1cv8\8.3.9.2170\bin», так как именно в нем установлена сама платформа.

Тестирование и исправление в 1С

Зачастую способ с обновлением платформы помогает не всегда, так как ошибка кроется в самой БД. В таком случае, с очень большой вероятностью, вам поможет .

Средствами конфигуратора

Решение проблемы данным способом производится из конфигуратора. Перейдите в меню «Администрирование» и выберите пункт «Тестирование и исправление…».

В появившейся форме предварительных настроек снимем флаги с пунктов «Реиндексация таблиц информационной базы» и «Пересчет итогов». Данные надстройки не сыграют роли в исправлении нашей ошибки, а лишь увеличат время обработки данных.

После нажатия на кнопку «Выполнить», программа запустит процесс тестирования и исправления информационной базы, который может занять довольно длительное время. По завершении вам будет представлен полный отчет.

Утилита «chdbfl.exe»

Данная утилита является аналогом тестирования и исправления и предназначена для файловых информационных баз. Не нужно искать в интернете, где ее скачать. Данная утилита включена в состав поставки самой платформы 1С и располагается в той же папке, что и библиотека, на которую ссылается исправляемая нами ошибка.

Кроме этого вам необходимо узнать, где расположена та информационная база, в которой вам выдалась ошибка. Выберите ее в списке информационных баз, и в самом низу окна, данная информация вам будет доступна.

Теперь откроем саму и в поле «Имя файла БД» выберем файл «1Cv8.1CD» из того каталога, адрес которого только что выяснили.

Нам нужно не только провести диагностику, но и восстановить работоспособность информационной базы. В связи с этим в данной ситуации необходимо установить флаг на пункте «Исправлять обнаруженные ошибки».

Эти и некоторые другие способы рассмотрены также в этом видео:

Ошибки в коде 1с. Наиболее частые ошибки «1С» и методы их исправления


Последняя редакция №22 от 15.07.08 | История
URL:
Ключевые слова: ошибка,исключение,попытка, 80004005, 80040E31, 00000005, 00000041, 80070005, 80000009, 80030005, 8001011B, 80010108, 80010005, 800706BA, 800706BE, 80080005,SDBL,pos,CAST

Предлагаю всем дружно составить перечень ошибок 1С 80 и какое сообщение об этой ошибке можно получить для анализа в функции ОписаниеОшибки().

Просьба соблюдать формат и дословно приводить текст ошибки.

Ошибка блокировки при транзакциях

Microsoft OLE DB Provider for SQL Server: Transaction (Process ID 55) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

HRESULT=80004005, SQLSTATE=40001, native=1205

Возникает при конфликте транзакций, часто при записи объектов.

Ошибка блокировки при транзакциях 2

Microsoft OLE DB Provider for SQL Server: Lock request time out period exceeded.

HRESULT=80040E31, SQLSTATE=HYT00, native=1222

Истек тайм-аут.

Более 256 таблиц в запросе

Ошибка выполнения запроса «Построенный запрос к СУБД использует слишком много таблиц. Допустимо не более 256.»

Когда в запросе идет обращение более, чем к 256 таблицам.

Ошибки: 00000005, 00000041, 80070005, 80000009, 80030005, 8001011B
Возникают в тех случаях, когда пользователь, от имени которого работает клиентское приложение, не имеет прав доступа к каким-либо ресурсам. В частности, это может означать, что пользователю, от имени которого стартовало клиентское приложение 1С:Предприятия, недоступны либо средства COM+ того компьютера, на котором установлен сервер, либо зарегистрированное на нем COM+ приложение 1CV8, которое является сервером 1С:Предприятия.

Если эта ошибка возникает во внешнем соединении 1С:Предприятия, то это означает отсутствие соответствующих прав у пользователя того приложения, которое обратилось к внешнему соединению. Это может быть любое интерактивное приложение или, например, WEB-сервер. В частности, если в качестве WEB-сервера используется Microsoft Internet Information Services, то таким пользователем может быть пользователь IUSR_ или ASPNET.

Методика настройки прав доступа пользователей к COM+ серверу описана в разделах «Вопросы установки и настройки 1C:Предприятия 8.0 в варианте «клиент-сервер»» и «Особенности использования внешнего соединения 1С:Предприятия в WEB-приложениях».
(С) ИТС

Ошибка 80010108
Может возникнуть в том случае, если клиентское приложение некоторое время (несколько минут) находилась в неактивном состоянии, например из-за засыпания компьютера или долгого ожидания на точке останова в отладчике. Причиной этого является особенность механизма DCOM, обеспечивающего принудительный разрыв соединения с сервером, если клиент долго не проявлял активность.
(C) ИТС

Ошибка 80010005
Может возникнуть в клиентском приложении в процессе обращения к серверу 1С:Предприятия, если при перерисовке экрана клиентское приложение обратилось к серверу 1С:Предприятия повторно. Это может быть проявлением внутренней ошибки клиентского приложения 1С:Предприятия. Для ее оперативного исправления желательно описать обстоятельства ее возниконовения и обратиться на линию технической поддержки 1С:Предприятия 8.0.
(C) ИТС

Ошибки 800706BA, 800706BE
Сигнализируют об аварийной ситуации на сервере 1С:Предприятия, которая привела к его автоматическому перезапуску.
(С) ИТС

Ошибка 0х80080005: Server execution failed
Одной из причин возникновения этой ошибки явлются проблемы с подсистемой COM+, являющейся частью операционной системы. При возникновении такой ошибки, как правило, в системные журналы событий также записываются события с источником COM+, именем серверного приложения System Application и указанием файла Comsvcs.dll. Существуют процедуры восстановления работоспособности COM+, однако они дают желаемый результат не всегда. Описания официально рекомендованных процедур можно найти в http://support.microsoft.com/default.aspx?scid=kb;en-us;315296 (или похожей http://support.microsoft.com/default.aspx?scid=kb;en-us;318731), однако по результатам практических применений рекомендуется процедура, описанная в http://www.jsifaq.com/subN/tip6900/rh6951.htm . Эта последовательность шагов дополнена по сравнению с официальной и может быть использована в операционных системах 2000/XP/2003. Ниже приводится ее перевод на русский язык.
Для восстановления поврежденного каталога COM+:

1. Переименуйте каталог %SystemRoot%\System32\Clbcatq.dll в %SystemRoot%\System32\~Clbcatq.dll (обратите внимание на появление тильды в имени каталога).
2. Перезагрузите компьютер.
3. Удалите из системного реестра ключ COM3, расположенный в ключе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.
4. Запустите командную консоль CMD.EXE.
5. Наберите pushd %SystemRoot% и нажмите Enter.
6. Наберите rd /s /q Registration и нажмите Enter.
7. Наберите popd и нажмите Enter.
8. Наберите exit и нажмите Enter.
9. Удалите слово Hide из строки, начинающейся с COM=, в файле %SystemRoot%\Inf\Sysoc.inf. Для редактирования файла можно использовать Notepad.
10. Для Windows XP:
* Запустите командную консоль CMD.EXE.
* Наберите regsvr32 /s ole32.dll и нажмите Enter.
* Наберите regsvr32 /s oleaut32.dll и нажмите Enter.
* Наберите exit и нажмите Enter.
11. Запустите панель управления Установка/Удаление программ и выберите пункт Добавление\удаление компонент Windows.
12. Нажмите Next и переустановите COM+.
Замечание: Если механизм защиты системных файлов Windows File Protection блокирует одно или несколько из вышеприведенных действий, то необходимо выполнять эти действия в безопасном режиме (Safe Mode).
http://users.v8.1c.ru/Adm433.aspx

Ошибка записи/проведения

Ошибка при вызове метода контекста (Записать): Операция не выполнена!

Возникает, если в модуле записи/проведения присвоить Отказ=истина

Ошибка преобразования данных XML

возникает при рассинхронизации структуры данных (конфигурации) между узлами распределенной базы

В базе нет пользователя с административными правами
При редактировании списка пользователей роли берутся только из конфигурации БД. Обновить конфигурацию БД (F7).

Попытка передачи мутабельного значения на сервер 1С:Предприятия
Возникает только в клиент-серверной версии (SQL). Для исправления ошибки нужен программист. Если у вас типовая конфигурация, попробуйте обновить ее до последнего релиза.
Мутабельный — изменяемое. На сервер 1С можно передавать значения только примитивных типов данных.

Клиентский поток исполняется на сервере. Удалить клиента веременно невозможно
v8: Клиентский поток исполняется на сервере. Удалить клиента веременно невозмож

Однако не обязательно перезапускать сервер приложений (выгоняя всех пользователей), чтобы убить зависший таким образом процесс.
Достаточно найти этот процесс на SQL сервере и убить его на SQL сервере.

Ошибка SDBL: Поля «CAST (Q_000_T_001/Recorder AS REF(Document4055)/Fld4092» и «CAST (Q_000_T_001/Recorder AS REF(Document123)/Fld2322» не совместимы по типам.(pos=10173)

В документах «Приходный кассовый ордер» и «Расходный кассовый ордер» реквизит «Основание» имеет в свойстве «Неограниченная длина» включенный флаг, надо снимать флаг и указать длину этого реквизита

«Ошибка SQL: Поле не найдено «MaxGetCode»

Эта ошибка выдается в файловом варианте, когда клиенты разных версий одновременно работают с ИБ в файловом варианте.

Бухгалтерам приходится часто сталкиваться с сообщением «Ошибка загрузки метаданных 1С», вызывающим активную тревогу, поскольку разобраться самостоятельно, как устранить такую ошибку, как сделать так, чтобы программа вновь заработала , не сопровождаясь проблемами, большинство неопытных бухгалтеров просто не знают.

Суть ошибки в отсутствии в базе необходимого файла.

Прежде всего, следует понимать, что сообщение «Ошибка загрузки метаданных в 1С 7.7» возникает в тех случаях, когда программное обеспечение при запуске не может обнаружить непосредственно сам файл метаданных в информационной базе.

Такая проблема может возникать также, когда этот файл был нечаянно повреждён. Кстати, с такими повреждениями приходится часто сталкиваться тем бухгалтерам, которые игнорируют правила корректного отключения ПК. Безусловно, иногда внешние факторы провоцируют такое , когда внезапно отключается электроэнергия.

Особенно некорректное отключение провоцирует такой сбой, если базы находятся на съёмных носителях. Безусловно, если этот съёмный носитель выходит со строя , воспользоваться записанными на нём метаданными не удастся. Не следует исключать и вероятность того, что проблема возникла вследствие проникновения на ПК вирусного ПО.

Способы устранения ошибки

Если вы стали свидетелем возникновения сообщения «Ошибка загрузки метаданных в 1С на Windows 7», панику отбросьте в сторону, сосредоточьтесь и начните разбираться с тем, как всё-таки решить возникшую проблему. Поверьте, если следовать рекомендациям, эта проблема не покажется для вас такой уж страшной и неимоверно сложной.

Конечно, вы должны понять, что привести к ошибке метаданных в 1С 7.7 может не одно только повреждение, а сразу несколько. Только в связи с тем, что первоначально программа загружает md.файл, она, выявляя его повреждение, сигнализирует об этом сообщением «Ошибка метаданных 1С». Узнать сразу об остальных неисправностях компонентов баз вы просто не можете, поскольку программа просто вас об этом не уведомляет.

К сожалению, спровоцировать такую ужасную для вас проблему, могли вы даже собственноручно. Это часто случается, когда возникает желание переписать md.файл, воспользовавшись копией. Это катастрофическая ошибка для программы, поэтому совсем неудивительно, что она начинает «мстить» бухгалтерам за неумелое обращение с ней. Желая переписать информацию, недопустимо делать копию.

Алгоритм действий

Чтобы не навредить ещё сильнее программе, важно неукоснительно следовать рекомендациям опытных пользователей. Если обнаружена уже повреждённая информационная база, не торопитесь предпринимать какие-либо действия до тех пор, пока не сделаете посекторную копию.

Если выполнить такие рекомендации, впоследствии удастся базу легко восстановить. К сожалению, те, кто игнорирует эти советы, могут лишиться возможности устранить системный сбой. Итак, если в 1С Предприятие возникла ошибка загрузки метаданных, первым делом проверьте, а видит ли сама программа путь к информационной базе.

Если даже видит, не спешите переходить к следующим шагам, проверьте правильность указанного пути. Иногда при системном сбое путь становится некорректным, безусловно, воспользоваться информационной базой программа не может, по этой причине она не будет корректно загружаться. К сожалению, если путь правильный, значит, проблема всё-таки посерьёзнее, но и с ней можно разобраться.

Начнём искать причины проблемы, если ПО видит этот файл, но не может его прочитать. Предлагаем вам открыть проводник Windows, после чего попытаться создать точную копию файла конфигурации, размещая его на другом дисковом пространстве.

Если даже при таких действиях возникает сообщение об ошибке, сообщающей, что не удаётся прочитать файл, значит, высока вероятность того, что ваш диск, на котором сохранена база, просто повреждён. Иногда такое случается, когда на съёмном диске устанавливается защита, ограничивающая права на чтение.

К сожалению, достаточно часто бухгалтера сталкиваются с тем, что файл можно прочитать, но он оказывается повреждённым по причине вирусной атаки, некорректного выключения и прочего. Итак, прежде чем приступить к дальнейшим действиям, очень важно сделать резервную копию, которую разместить на другом дисковом пространстве.

Хорошо, если бухгалтера периодически создают резервную копию, тогда достаточно распаковать эту копию и заменить повреждённый файл этой копией. Если же такого «спасительного» архива просто нет, воспользуйтесь «дружеской» помощью утилиты GComp. Эта утилита помогает распаковать файл конфигурации, а затем точно также его успешно упаковать, восстановив работоспособность программы.

Также рекомендуем просмотреть название фала, воспользовавшись любым HEX-редактором. Если вы обнаружите, что ничего общего с Compound он не имеет, значит, кто-то его с «огромным аппетитом скушал». В большинстве случаев после вирусного вмешательства что-то сделать с таким файлом уже невозможно.

Если в вашей программе была установлена конфигурация стандартная, тогда поищите такую же на просторах интернета, после завершения успешных поисков, просто её замените. Конечно, если файл содержал крайне важную информацию, лучше доверить все эти манипуляции профессионалам, которые в большинстве случаев смогут вернуть вам потерянное.

Важно понимать, что, решаясь самостоятельно восстанавливать метаданные, риск возникновения фатальных неудач значительно выше, нежели при системном сбое. По этой причине ответственно подходите к решению этой проблемы, неукоснительно следуйте всем инструкциям, чтобы получить удовлетворение от отличного результата.

Описание ошибки формата потока в 1С 8.3

Ошибка формата потока в 1С встречается наиболее часто у всех пользователей. И обычно в таких случаях объяснить её появление вызывает затруднение – вроде бы работали в 1С, всё как обычно. В очередной раз запуская 1С, мы получаем вот такое сообщение:

Ни одна из кнопок Ошибки формата потока не позволяет запустить базу и продолжить работу. Именно потому, что эта ошибка самая популярная и частая, мы сперва объясним её причины, а уже затем перейдем к рассмотрению методов её решения.

Причины появления ошибки формата потока в 1С 8.3

Ошибка формата потока в 1С связана с чтением кэша базы при обращении к ней. Кэш, если говорить простыми словами, это вспомогательная информация (настройки, избранное, частые команды и т.п.) 1С, хранящаяся в отдельных от базы файлах. Во время работы 1С регулярно обращается к кэшу. При возникновении ситуации, когда это обращение было прервано (при отключении электричества, неполадках в сети, экстренном завершении работы 1С), кэш может быть записан с ошибками. В таком случае, при последующем запуске чтение кэша приведёт к этой самой ошибке – ошибке формата потока в 1С.

Способы решения ошибки формата потока в 1С 8.3

Перед началом решения проблемы любым из способов обязательно сделайте резервную копию базы! Это поможет вам вернуться к изначальному результату в случаях, когда попытка решения проблемы окажется неудачной.

Для быстрого создания резервной копии откройте папку с базой (как это делается в способе №1) и скопируйте её содержимое в любое другое место. Проводите работы по исправлению ошибок только имея резервную копию!
1.
2.
3.
4.
5.
6.

Очистка кэша базы 1С

Самый простой и помогающий в большинстве случаев способ – очистка кэша базы 1С. Для этого запустим 1С: Предприятие и узнаем путь, по которому хранится база:

Откроем эту папку в Проводнике и удалим все файлы, кроме файла базы, как показано на рисунке ниже. Заметим, что количество файлов могут отличаться, все они должны быть удалены, кроме одного – 1Сv8 (файловая информационная база).

Очистка кэша 1С

Следующий способ – очистка кэша 1С: Предприятие. Для этого нужно открыть папки, где они хранятся. На Windows 7 и выше их две:

C:\Users\Username\AppData\Roaming\1C

C:\Users\Username\AppData\Local\1C

Следует удалить папку 1cv8 в обоих из них:

После очистки кэша попробуйте зайти в базу ещё раз. Ошибка осталась? Попробуйте следующий способ.

Исправление базы утилитой chdbfl.exe

Возможно, ошибка формата потока может быть связана с ошибками в самой базе. Для этого её стоит проверить с помощью специальной программы chdbfl.exe, которая идёт в комплекте с 1С: Предприятие. Для этого перейдите в папку с программой (чаще всего это C:\Program Files\1cv8\8.3.XX.YYY\bin\) и найдите файлик chdbfl.exe:

Открыв его, нажмите многоточие в правом верхнем углу и найдите файл неработающей базы. Опираясь на способ выше, можно сказать – что это тот самый файл базы, который вы не удалили при очистке кэша.

После этого поставьте галочку Исправлять обнаруженные ошибки и нажмите Выполнить. Дождитесь окончания проверки и попробуйте запустить базу. Ошибка осталась? Попробуйте следующий способ.

Тестирование и исправление базы через Конфигуратор

Следующим способом решения ошибки формата потока в 1С является Тестирование и исправление базы, доступные из Конфигуратора.

Запустите 1С: Предприятие через режим Конфигуратор:

В открывшемся Конфигураторе выберите Администрирование – Тестирование и Исправление:

В открывшемся окне установите настройки, как на рисунке ниже, и нажмите Выполнить.

Дождитесь окончания всех процедур. Закройте Конфигуратор и попробуйте зайти в базу. Ошибка осталась? Попробуйте следующий способ.

Выгрузка и загрузка базы через dt

Данный способ может помочь устранить такие ошибки, которые не устраняются п.3 и п.4 данной статьи. Зайдите в базу через режим Конфигуратор, как в способе выше. Выберите Администрирование – Выгрузить информационную базу:

В открывшемся окне выберите место расположения выгрузки. Оно может быть любым, главное – запомнить это место.

Нажав Сохранить, дождитесь окончания выгрузки. Выйдите из режима Конфигуратора. Откройте ещё раз 1С: Предприятие, и выберите пункт Добавить – Создание новой информационной базы – Создание информационной базы без конфигурации – Далее – Готово.

Откройте созданную базу через Конфигуратор и нажмите Администрирование – Загрузить информационную базу. Укажите в открывшемся окне тот файл выгрузки, который вы сформировали только что. Дождитесь окончания загрузки, закройте Конфигуратор и попробуйте зайти в новую загруженную базу. Ошибка осталась? Попробуйте следующий способ.

Продвинутые способы решения ошибки формата данных 1С

Подробное рассмотрение продвинутых способов решения ошибки формата данных в 1С выходит за рамки данной статьи, поскольку для их использования нужно обладать теми или иными знаниями в области обращения с компьютером, поэтому инструкции и пометки по каждому из них были бы довольно объёмными.

Ограничимся их перечислением:
1. Выгрузка и загрузка данных между неработающей и пустой базой с помощью обработки «Выгрузка и загрузка данных XML».
2. Различные версии используемых 1С, работающих в одной базе через сеть (подробнее см.) необходимо привести в порядок.
3. Отключение протокола IPv6 через реестр Windows.
4. Переустановка или обновление 1С: Предприятие.
5. Перенос базы на другой компьютер и попытка запустить её там.
6. Отключение или удаление фаерволов и/или антивирусов.
7. Проверка формата потока с помощью утилиты Tool_1CD
8. Обновите конфигурацию с помощью.cf файла.

Проблема «Ошибка формата потока в 1С 8.3» не решена? Получите бесплатную консультацию от наших специалистов по решению данной проблемы!

Такая проблема, как Ошибка формата потока, в 1С 8.3 встречается достаточно часто. Рассмотрим, как исправить данную ошибку.

Что же такое ошибка формата потока в 1с 8.3?

Такое происходит в следующих ситуациях:

  1. Ошибка формата потока при запуске 1С Предприятия 8.2 или конфигуратора обычно связана с проблемами в кеше. Обычно она вызвана неправильным выключением системы вследствие, например, отключения электричества. Поэтому настоятельно рекомендуется ставить блоки бесперебойного питания, чтобы не потерять важную информацию. Часто ошибка появляется при запуске базы после обновления конфигурации.
  2. Вторая ситуация — при формировании какого-либо отчета, например, открытии отчета , проведении документа, открытии документа и т.д. Часто это связано именно с содержанием информации в базе данных. Причиной этой ошибки чаще всего является наличие «битой» информации внутри системы.

Получите 267 видеоуроков по 1С бесплатно:

Исправление

  1. Как правило, для решения данной проблемы достаточно почистить временные файлы в системе. .
  2. Если не помогло, но есть возможность попасть в конфигуратор, запустите .
  3. Если доступа в конфигуратор нет, и база тестовая — воспользуйтесь , которая располагается в папке программы.
  4. Если вышеперечисленные методы не помогают, но запускается режим 1С предприятие, выгрузите данные в новую базу с помощью обработки « «. Однако при этом возможны потери данных.
  5. Обновление . Еще одной причиной может стать наличие активных сеансов пользователей с разной версией клиентской части платформы 1С. То есть, например, в базе работает пользователь с платформой 1С 8.3.5.1517, а пытается подключиться другой, с версией 8.3.5.1444.

Если это не помогло — есть более изощренные способы решения данной проблемы. Например, с помощью HEX-редактора. Если Вам необходима квалифицированная помощь программистов 1С, обратитесь к нам! Подробности на странице

В информационных базах на платформе 1С могут возникнуть множество различных ошибок:

нарушение логической/физической целостности базы, ошибки пользователей, «кривой» код разработчика и многое другое.

Причин может быть множество: отключили свет, и не было источника бесперебойного питания, или вечер пятницы удался, и пользователь уже и не может вспомнить в понедельник, что он натворил такого.

Во-первых, стоит задать несколько уточняющих вопросов пользователю:

1) Релизы платформы/конфигурации.

2) Полный текст сообщения об ошибке. Пользователи имеют досадное свойство не читать целиком такие сообщения, а возможно в нем содержится рекомендация к устранению неисправности.

3) Как давно возникла и при каких обстоятельствах появляется. Не воспроизводимые ошибки, которых мы ранее не встречали, мы наврядли сможем исправить.

4) Возникает ли если запустить 1с с другого компьютера/от другого пользователя? Это даст нам пищу для размышлений — сможет ли помочь очистка кэша, настройка прав, или очистка настроек пользователя.

Теперь немного о самих ошибках и том как их решать.

Общее:
Часть ошибок возникает при использовании нелицензионного ПО (windows, 1C и т.д.).

Распространенный пример — ломаная платформа. Один из патчей взламывает конкретную версию платформы, поэтому после установки новой версии платформы и попытке зайти в базу можно увидеть окно «Не обнаружено свободной лицензии».

Если Вы встретили ошибку в первый раз — возможно, кто-то уже ее встречал —

поищите в google, возможно кто-то уже с этим сталкивался и решил проблему, и Вы не потратите лишних пару часов своего времени.

Релиз конфигураций должен быть актуальным (в первую очередь для конфигураций из которых сдается регламентированная отчетность), неспроста на линии консультаций практически всегда предлагают вначале обновиться, а потом уже смотреть дальше.

Актуальный релиз платформы — у каждой конфигурации написано, какой релиз платформы рекомендован для работы с этой конфигурацией.

Технологический журнал позволяет протоколировать все события 1С:Предприятия (или часть, используя фильтр).
Про него можно прочитать и .

!!!ВАЖНО

Перед любыми действиями с базой — сделать архивную копию!

Если база не открывается в конфигураторе — скопировать папку с базой и выполнять все операции на копии!

1) База вообще не открывается ни в пользовательском режиме, ни в конфигураторе.

  • Самое быстрое, что можно сделать — очистить временные файлы (удалить базу из списка баз и подключить заново)

    Это действие не удалит временные файлы (кэш), а создаст новую папку для временных файлов базы, удалить файлы можно:
    В Windows 7 в C:\Users\Имя_Пользователя\AppData\Roaming\1C\1Cv8x
    В Windows XP C:\Documents and Settings\Имя_Пользователя\Application Data\1C\1Cv8х

  • Также можно попытаться зайти в базу от другого пользователя.
  • Если база файловая, то стоит запустить утилиту для тестирования физической целостности базы chdbfl. Она находится в папке:
    C:\Program Files (x86)\1cv8\8.x.x.xxx\bin\chdbfl.exe
  • Если база sql-ная то тестирование средствами sql.
  • Если ни то ни другое не помогло, то можно обновить платформу (см. под какой платформой работает релиз)
  • Если не получилось ничего из перечисленного, можно воспользоваться программкой Tool_1CD.

2) Если база при запуске уходит в дамп.

  • Отключить аппаратное ускорение видеокарты:
  1. Откройте свойства экрана. Это можно сделать через Панель управления, или просто щелкнув правой кнопкой мыши по любому месту рабочего стола, свободному от окон и значков, и выбрав пункт контекстного меню «Свойства».
  2. В открывшемся окне настройки дисплея перейдите на закладку «Параметры» и нажмите кнопку «Дополнительно».
  3. В открывшемся окне свойств видеокарты перейдите на вкладку «Диагностика».
  4. Передвиньте движок «Ускорение» в крайнюю левую позицию («нет») и нажмите «Применить» или «Ок». Аппаратное ускорение отключено. Изменения вступят в силу после перезагрузки системы.
  1. Откройте Панель управления (Пуск — Панель управления).
  2. Найдите и откройте элемент «Экран».
  3. В левой части открывшегося окна щелкните по ссылке «Настройка параметров экрана».
  4. В открывшемся окне нажмите на ссылку «Дополнительные параметры».
  5. Перейдите на вкладку «Диагностика» и нажмите кнопку «Изменить параметры».
  6. В открывшемся окне передвиньте движок в крайнее левое положение («нет») и нажмите «Ок». Если UAC включен, придется подтвердить, что изменения санкционированы пользователем. Аппаратное ускорение отключено. Изменения вступят в силу после перезагрузки системы.

В Windows 7 в некоторых случаях кнопка «Изменить параметры» будет неактивна. В этом случае отключить аппаратное ускорение невозможно, так как видеокарта и ее драйвер не поддерживают манипуляции аппаратным ускорением.

  • Если антивирус Касперский, то можно попробовать отключить самозащиту и переименовать файлы kloehk.dll и mzvkbd3.dll в папке Касперского. (Ошибка возникала на старых версиях 2011 года, но еще иногда встречается)
  • Проверить соответствие релиза платформы/конфигурации.
  • Попробовать зайти в базу с другой платформы.

3) База открывается в конфигураторе, но не хочет заходить в пользовательский режим.

  • Очистка временных файлов
  • Попытка зайти за другого пользователя
  • chdbfl / тестирование средствами sql
  • Тестирование и исправление ИБ:
    В конфигураторе Администрирование-Тестирование и исправление — галочки в зависимости от ситуации.
  • Попробовать создать др. пользователя с полными правами и зайти от него.
  • Попробовать перенести на другой ПК и открыть там, может что-то с ПК.

4) При каком-то действии выкидывает на код в конфигуратор.

  • Для проверки стоит очистить кэш.
  • Если не помогло то скорей всего ошибка в коде — особенно актуально для нетиповых и самописных конфигураций, но встречается иногда и в типовых.

Если конфигурация нетиповая, то тут либо обновление прошло некорректно или разработчик дорабатывавший конфигурацию не предусмотрел все возможности пользовательских ошибок — защита от дурака (если это возможно!).

Если типовая, то возможно ошибка в релизе.

В любом случае стоит пробежать в отладчике и посмотреть что не так.

5) Под одним пользователем дает что-то сделать, под другим нет.

  • Настройки прав пользователей.
  • Настройки пользователя.
  • Очистка кэша.

6) С одного ПК заходит, с другого нет.

  • Проверить в проводнике видит ли базу — может к папке с базой не предоставлен общий доступ.
  • Очистка кэша.
  • Зайти под другим пользователем.

7) Я ничего не делал/делала но у меня все сломалось

  • Если смогут подсказать что именно «не делали» и когда, то можно воспользоваться

8) Недостаточно памяти.

Был у меня случай, пришел клиент, говорит, при закрытии месяца вылетает ошибка «Недостаточно памяти». Взялся я за эту проблему. Думал, что легко, сначала добавил оперативки — ошибка. Было 2 гигабайта, стало 4, а все равно 1с-ке мало. Размер файла подкачки менял — ошибка, переустановка системы (поставил Windows 7) дало только временный результат, где-то на неделю. Перепробовал все. Спустя некоторое время решение было найдено.

Решение

На клиентском компе запустить командную строку от имени администратора, прописать там следующее:

BCDEdit /set increaseuserva xxxx — вместо хххх пишите объем виртуального адресного пространства в мегабайтах, т.е. сколько нужно памяти под работу приложений. По умолчанию 2 гига. Вообще в 32-разрядных операционных системах выделяется 4 гигабайта: 2 — на приложения и 2 на нужды самой ОС. Я выбрал 3000 (т.е. CDEdit /set increaseuserva 3000 ). Однако система может подглючивать. Особенно, если у вас 2 гига оперативки, как у меня. Это для ОС семейства Windows Vista, 7, Windows 2008.

Для Windows XP \ Windows 2003 пишем
/3GB /userva=xxxx (xxxx в МБ в диапазоне 2048 — 3072) в файле boot.ini, рекомендуемый максимум значений userva 2900-3030.

9) Элементы форм налезают друг на друга и имеют неправильное расположение.

10) Ошибка СУБД Внутренняя ошибка компоненты dbeng8

  • Ошибка связана с различием кода разных версий платформы, когда пользователи пытаются использовать файловый вариант. Для клиент-серверного варианта при запуске происходит контроль и работа с разными версиями платформы в принципе невозможна.

Решение: обновиться до актуального релиза на всех рабочих местах.

Если не помогло, тогда делаем следующее:

  • Тестирование и исправление

11) Ошибка в платформе 8.3.4.428

  • В версии 8.3.4.428 платформы «1С:Предприятие» обнаружена критичная ошибка, возникающая при реструктуризации данных. Данная ошибка локализована и будет исправлена в следующей версии платформы.

12) Конфликт блокировок при выполнении транзакции:


Microsoft OLE DB Provider for SQL Server: Could not continue scan with NOLOCK due to data movement.
HRESULT=80040E14, SQLSrvr: SQLSTATE=42000, state=3, Severity=C, native=601, line=1

«Как проверить (восстановить) базу на MS SQL Server средствами сервера
Проверку логической целостности нужно выполнять штатными средствами 1С:Предприятия (Тестирование и исправление ИБ). В случае, если такую проверку не удается выполнить, следует проверить физическую целостность БД средствами MS SQL. Для проверки целостности средствами MS SQL нужно выполнить следующую команду:
Код:
DBCC CHECKDB («»,REPAIR_REBUILD)
Перед выполнением этой команды нужно базу данных перевести в режим «single user»:
Код:
sp_dboption «»,»single user»,true
В процессе работы DBCC CHECKDB могут быть обнаружены ошибки и часть может быть сразу же исправлена. Если ошибки остались, то по всей видимости их нельзя восстановить без потери некоторых данных. В этом случае нужно запустить DBCC CHECKDB с параметром REPAIR_ALLOW_DATA_LOSS (перед запуском желательно сделать копию файлов базы данных).
Код:
DBCC CHECKDB («»,REPAIR_ALLOW_DATA_LOSS)
После выполнения DBCC CHECKDB нужно не забыть вернуться в нормальный режим (выйти из режима «single user»):
Код:
sp_dboption «»,»single user»,false» (Взято с сайта )

Конечно список далеко не полный, так что буду рад, если его дополнят в комментариях.

Функции — SwiftBook

Функции – это самостоятельные фрагменты кода, решающие определенную задачу. Каждой функции присваивается уникальное имя, по которому ее можно идентифицировать и «вызвать» в нужный момент.

Язык Swift предлагает достаточно гибкий единый синтаксис функций – от простых C-подобных функций без параметров до сложных методов в стиле Objective-C с локальными и внешними параметрами. Параметры могут служить как для простой инициализации значений внутри функции, так и для изменения внешних переменных после выполнения функции.

Каждая функция в Swift имеет тип, описывающий тип параметров функции и тип возвращаемого значения. Тип функции можно использовать аналогично любым другим типам в Swift, т. е. одна функция может быть параметром другой функции либо ее результирующим значением. Функции также могут вкладываться друг в друга, что позволяет инкапсулировать определенный алгоритм внутри локального контекста.

При объявлении функции можно задать одно или несколько именованных типизированных значений, которые будут ее входными данными (или параметрами), а также тип значения, которое функция будет возвращать в качестве результата (или возвращаемый тип).

У каждой функции должно быть имя, которое отражает решаемую задачу. Чтобы воспользоваться функцией, ее нужно «вызвать», указав имя и входные значения (аргументы), соответствующие типам параметров этой функции. Аргументы функции всегда должны идти в том же порядке, в каком они были указаны при объявлении функции.

В приведенном ниже примере функция называется greet(person:), потому что это отражает ее задачу – получить имя пользователя и вежливо поздороваться. Для этого задается один входной параметр типа String под названием person, а возвращается тоже значение типа String, но уже содержащее приветствие:

func greet(person: String) -> String {
    let greeting = "Привет, " + person + "!"
    return greeting
}

Вся эта информация указана в объявлении функции, перед которым стоит ключевое слово func. Тип возвращаемого значения функции ставится после результирующей стрелки -> (это дефис и правая угловая скобка).

Из объявления функции можно узнать, что она делает, какие у нее входные данные и какой результат она возвращает. Объявленную функцию можно однозначно вызывать из любого участка кода:

print(greet(person: "Anna"))
// Выведет "Привет, Anna!"
print(greet(person: "Brian"))
// Выведет "Привет, Brian!"

Функция greet(person:) вызывается, принимая значение типа String, которое стоит после имени person, например вот так — greet(person: «Anna»). Поскольку функция возвращает значение типа String, вызов функции greet(person:) может быть завернут в вызов для функции print(_:separator:terminator:), чтобы напечатать полученную строку и увидеть возвращаемое значение (см. выше).

Тело функции greet(person:) начинается с объявления новой константы типа String под названием greeting, и устанавливается простое сообщение-приветствие. Затем это приветствие возвращается в точку вызова функции с помощью ключевого слова return. После выполнения оператора return greeting функция завершает свою работу и возвращает текущее значение greeting.

Функцию greet(person:) можно вызывать многократно и с разными входными значениями. В примере выше показано, что будет, если функцию вызвать с аргументом «Anna» и со значением «Brian». В каждом случае функция возвратит персональное приветствие.

Чтобы упростить код этой функции, можно записать создание сообщения и его возврат в одну строку:

func greetAgain(person: String) -> String {
    return "Hello again, " + person + "!"
}
print(greetAgain(person: "Anna"))
// Выведет "Hello again, Anna!"

В языке Swift параметры функций и возвращаемые значения реализованы очень гибко. Разработчик может объявлять любые функции – от простейших, с одним безымянным параметром, до сложных, со множеством параметров и составными именами.

Функции без параметров

В некоторых случаях функции могут не иметь входных параметров. Вот пример функции без входных параметров, которая при вызове всегда возвращает одно и то же значение типа String:

func sayHelloWorld() -> String {
    return "hello, world"
}
print(sayHelloWorld())
// Выведет "hello, world"

Обратите внимание, что несмотря на отсутствие параметров, в объявлении функции все равно нужно ставить скобки после имени. При вызове после имени функции также указываются пустые скобки.

Функции с несколькими входными параметрами

У функции может быть несколько параметров, которые указываются через запятую в скобках.

Эта функция принимает два параметра: имя человека и булево значение, приветствовали ли его уже, и возвращает соответствующее приветствие для этого человека:

func greet(person: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}
print(greet(person: "Tim", alreadyGreeted: true))
// Выведет "Hello again, Tim!"

Вы вызываете функцию greet(person:alreadyGreeted:), передавая значение типа String параметру с ярлыком person и булево значение с ярлыком alreadyGreeted, взятое в скобки через запятую. Обратите внимание, что эта функция отличается от функции greet(person:), которую вы видели в предыдущем разделе. Хотя имена обеих функций начинаются с greet, функция greet(person:alreadyGreeted:) принимает два аргумента, а greet(person:) принимает только один.

Функции, не возвращающие значения

В некоторых случаях функции могут не иметь возвращаемого типа. Вот другая реализация функции greet(person:), которая выводит свое собственное значение типа String, но не возвращает его:

func greet(person: String) {
    print("Привет, \(person)!")
}
greet(person: "Dave")
// Выведет "Привет, Dave!"

Так как у функции нет выходного значения, в ее объявлении отсутствует результирующая стрелка (->) и возвращаемый тип.

Заметка

Строго говоря, функция greet(person:) все же возвращает значение, хотя оно нигде и не указано. Функции, для которых не задан возвращаемый тип, получают специальный тип Void. По сути, это просто пустой кортеж, т. е. кортеж с нулем элементов, который записывается как ().

Выходное значение функции может быть игнорировано:

func printAndCount(string: String) -> Int {
    print(string)
    return string.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
// Выведет "hello, world" и возвращает значение 12
printWithoutCounting(string: "hello, world")
// Выведет "hello, world", но не возвращает значения

Первая функция, printAndCount(string:) выводит строку, а затем возвращает подсчет символов в виде целого (Int). Вторая функция, printWithoutCounting(string:) вызывает первую, но игнорирует ее возвращаемое значение. При вызове второй функции первая функция по-прежнему печатает сообщение, но ее возвращаемое значение не используется.

Заметка

Хотя возвращаемые значения можно игнорировать, функция все же должна возвратить то, что задано в ее объявлении. Функция, для которой указан возвращаемый тип, не может заканчиваться оператором, который ничего не возвращает, иначе произойдет ошибка во время компиляции.

Функции, возвращающие несколько значений

Вы можете использовать кортежный тип в качестве возвращаемого типа для функции для возврата нескольких значений в виде составного параметра.

В следующем примере объявлена функция minMax(array:), которая ищет минимальный и максимальный элементы в массиве типа Int:

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

Функция minMax(array:) возвращает кортеж из двух значений типа Int. Этим значениям присвоены имена min и max, чтобы к ним можно было обращаться при запросе возвращаемого типа функции.

Тело функции minMax(array:) начинается с инициализации двух рабочих переменных currentMin и currentMax значением первого целого элемента в массиве. Затем функция последовательно проходит по всем остальным значениям в массиве и сравнивает их со значениями currentMin и currentMax соответственно. И наконец, самое маленькое и самое большое значения возвращаются внутри кортежа типа Int.

Так как имена элементов кортежа указаны в возвращаемом типе функции, к ним можно обращаться через точку и считывать значения:

let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// Выведет "min is -6 and max is 109"

Обратите внимание, что элементам кортежа не нужно давать название в момент возвращения кортежа из функции, так как их имена уже указаны как часть возвращаемого типа функции.

Опциональный кортеж как возвращаемый тип

Если возвращаемый из функции кортеж может иметь «пустое значение», то его следует объявить как опциональный кортеж, т. е. кортеж, который может равняться nil. Чтобы сделать возвращаемый кортеж опциональным, нужно поставить вопросительный знак после закрывающей скобки:(Int, Int)? или (String, Int, Bool)?.

Заметка

Кортеж-опционал вида (Int, Int)? — это не то же самое, что кортеж, содержащий опционалы: (Int?, Int?). Кортеж-опционал сам является опционалом, но не обязан состоять из опциональных значений.

Функция minMax(array:) выше возвращает кортеж из двух значений типа Int, однако не проверяет корректность передаваемого массива. Если аргумент array содержит пустой массив, для которого count равно 0, функция minMax в том виде, в каком она приведена выше, выдаст ошибку выполнения, когда попытается обратиться к элементу array[0].

Для устранения этого недочета перепишем функцию minMax(array:) так, чтобы она возвращала кортеж-опционал, который в случае пустого массива примет значение nil:

func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

Чтобы проверить, возвращает ли эта версия функции minMax(array:) фактическое значение кортежа или nil, можно использовать привязку опционала:

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
    print("min is \(bounds.min) and max is \(bounds.max)")
}
// Выведет "min is -6 and max is 109"

Функции с неявным возвращаемым значением

Если тело функции состоит из единственного выражения, то функция неявно возвращает это выражение. Например, обе функции в примере ниже имеют одно и то же поведение:

func greeting(for person: String) -> String {
    "Привет, " + person + "!"
}
print(greeting(for: "Дейв"))
// Выведет "Привет, Дейв!"

func anotherGreeting(for person: String) -> String {
    return "Привет, " + person + "!"
}
print(anotherGreeting(for: "Дейв"))
// Выведет "Привет, Дейв!"

Поведение функции greeting(for:) заключается в том, чтобы просто вернуть приветственное сообщение, что означает, что мы можем использовать сокращенную запись этой функции. Функция anotherGreeting(for:) возвращает то же самое приветственное сообщение, используя ключевое слово return. Таким образом, если вы пишите функцию, которая состоит из одного лишь возвращаемого значения, то вы можете опустить слово return.

Как вы увидите в главе «Сокращенный вариант объявления геттера», геттер так же может использовать сокращенную форму записи с опущенным словом return.

Заметка

Код, который вы написали с неявным возвращаемым значением должен иметь это самое возвращаемое значение. Например, вы не можете использовать fatalError(«Oh no!») или print(13) как неявные возвращаемые значения.

Каждый параметр функции имеет ярлык аргумента и имя параметра. Ярлык аргумента используется при вызове функции. Каждый параметр при вызове функции записывается  с ярлыком аргумента, стоящим перед ним. Имя параметра используется при реализации функции. По умолчанию параметры используют имена их параметров в качестве ярлыка аргумента.

func someFunction(firstParameterName: Int, secondParameterName: Int) {
    // Внутри тела функции firstParameterName и secondParameterName
    // ссылаются на значения аргументов, первого и второго параметров.
}
someFunction(firstParameterName: 1, secondParameterName: 2)

Все параметры должны иметь уникальные имена. Несмотря на то, что несколько параметров могут иметь один ярлык аргумента, уникальные ярлыки аргумента метки помогают сделать ваш код более читабельным.

Указываем ярлыки аргументов

Вы пишете ярлык аргумента перед именем параметра через пробел:

func someFunction(argumentLabel parameterName: Int) {
    // В теле функции parameterName относится к значению аргумента
    // для этого параметра.
}

Вот вариант функции greet(person:), которая принимает имя человека и его родной город, затем возвращает приветствие:

func greet(person: String, from hometown: String) -> String {
    return "Hello \(person)!  Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// Выводит "Hello Bill!  Glad you could visit from Cupertino."

Использование ярлыков аргументов позволяет функции вызываться в более выразительной манере, в виде предложения, при этом все же предоставляя тело функции в более читаемом виде и с более понятыми намерениями.

Пропуск ярлыков аргумента

Если вы не хотите использовать ярлык аргумента в качестве параметра, используйте подчеркивание (_) вместо явного ярлыка аргумента для этого параметра.

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
    // В теле функции firstParameterName и secondParameterName
    // ссылаются на значения аргументов для первого и второго параметров.
}
someFunction(1, secondParameterName: 2)

Если у параметра есть ярлык аргумента, то аргумент должен иметь ярлык при вызове функции.

Значения по умолчанию для параметров

При объявлении функции любому из ее параметров можно присвоить значение по умолчанию. Если у параметра есть значение по умолчанию, то при вызове функции этот параметр можно опустить.

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    // Если вы пропускаете второй аргумент при вызове функции, то
    // значение parameterWithDefault будет равняться 12 внутри тела функции.
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault равен 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault равен 12

Расположите параметры, у которых нет дефолтных значений в начале списка параметров функции до параметров с дефолтными значениями. Параметры, не имеющие значения по умолчанию, как правило, более важны для значения функции — их запись в первую очередь облегчает распознавание функции уже вызванной ранее, независимо от того, опущены ли какие-то параметры по умолчанию.

Вариативные параметры

Вариативным называют параметр, который может иметь сразу несколько значений или не иметь ни одного. С помощью вариативного параметра можно передать в функцию произвольное число входных значений. Чтобы объявить параметр как вариативный, нужно поставить три точки (…) после его типа.

Значения, переданные через вариативный параметр, доступны внутри функции в виде массива соответствующего типа. Например, вариативный параметр numbers типа Double… доступен внутри функции в виде массива-константы numbers типа [Double].

В приведенном ниже примере вычисляется среднее арифметическое (или же среднее) последовательности чисел, имеющей произвольную длину:

func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// возвращает 3.0, что является средним арифметическим этих пяти чисел
arithmeticMean(3, 8.25, 18.75)
// возвращает 10.0, что является средним арифметическим этих трех чисел

Функции могут иметь несколько вариативных параметров. Первый параметр, который идет после вариативного параметра должен иметь ярлык аргумента. Ярлык аргумента позволяет однозначно определить, какие аргументы передаются вариативному, а какие — параметрам, которые идут после вариативного параметра.

Сквозные параметры

Параметры функции по умолчанию являются константами. Попытка изменить значение параметра функции из тела этой функции приводит к ошибке компиляции. Это означает, что вы не сможете изменить значение параметра по ошибке. Если вы хотите, чтобы функция изменила значение параметра, и вы хотите, чтобы эти изменения сохранились после того, как закончился вызов функции, определите этот параметр в качестве сквозного параметра.

Для создания сквозного параметра нужно поставить ключевое слово inout перед типом объявлением параметра. Сквозной параметр передает значение в функцию, которое затем изменяется в ней и возвращается из функции, заменяя исходное значение. Более подробную информацию поведения сквозных параметров и связанных с ними оптимизаций компилятора см. Сквозные Параметры.

Вы можете передать только переменную в качестве аргумента для сквозного параметра. Вы не можете передать константу или значения литерала в качестве аргумента, так как константы и литералы не могут быть изменены. Вы ставите амперсанд (&) непосредственно перед именем переменной, когда передаете ее в качестве аргумента сквозного параметра, чтобы указать, что он может быть изменен с помощью функции.

Заметка

Сквозные параметры не могут иметь значения по умолчанию, а вариативные параметры не могут быть сквозными, с ключевым словом inout.

Вот пример функции под названием swapTwoInts(_:_:), у которой есть два сквозных целочисленных параметра – a и b:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Функция swapTwoInts(_:_:) просто меняет значение переменной b на значение a, а значение a – на значение b. Для этого функция сохраняет значение a в локальной константе temporaryA, присваивает значение b переменной a, а затем присваивает значение temporaryA переменной b.

Вы можете вызвать функцию swapTwoInts (_: _:) с двумя переменными типа Int, чтобы поменять их значения. Обратите внимание, что имена someInt и anotherInt начинаются с амперсанда, когда они передаются в swapTwoInts (_: _:) функции:

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Выведет "someInt is now 107, and anotherInt is now 3"

В вышеприведенном примере видно, что исходные значения переменных someInt и anotherInt изменены функцией swapTwoInts (_: _:), несмотря на то, что изначально они были объявлены за ее пределами.

Заметка

Сквозные параметры – это не то же самое, что возвращаемые функцией значения. В примере с функцией swapTwoInts нет ни возвращаемого типа, ни возвращаемого значения, но параметры someInt и anotherInt все равно изменяются. Сквозные параметры – это альтернативный способ передачи изменений, сделанных внутри функции, за пределы тела этой функции.

У каждой функции есть специальный функциональный тип, состоящий из типов параметров и типа возвращаемого значения.

Пример:

func addTwoInts(a: Int, _ b: Int) -> Int {
  return a + b
}
func multiplyTwoInts(a: Int, _ b: Int) -> Int {
  return a * b
}

В данном примере объявлены две простые математические функции – addTwoInts и multiplyTwoInts. Каждая из этих функций принимает два значения типа Int и возвращает одно значение типа Int, содержащее результат математической операции.

Обе функции имеют тип (Int, Int) -> Int. Эта запись означает следующее:

«функция с двумя параметрами типа Int, возвращающая значение типа Int».

Вот еще один пример, но уже функции без параметров и возвращаемого значения:

func printHelloWorld() {
  print("hello, world")
}

Эта функция имеет тип () -> Void, т. е. «функция без параметров, которая возвращает Void».

Использование функциональных типов

В Swift с функциональными типами можно работать так же, как и с другими типами. Например, можно объявить константу или переменную функционального типа и присвоить ей функцию соответствующего типа:

var mathFunction: (Int, Int) -> Int = addTwoInts

Эта запись означает следующее:

«Объявить переменную mathFunction, имеющую тип «функция, принимающая два значения типа Int, и возвращающая одно значение типа Int». Присвоить этой новой переменной указатель на функцию addTwoInts».

Функция addTwoInts имеет тот же тип, что и переменная mathFunction, поэтому с точки зрения языка Swift такое присваивание корректно.

Теперь функцию можно вызывать с помощью переменной mathFunction:

print("Result: \(mathFunction(2, 3))")
// Выведет "Result: 5"

Той же переменной можно присвоить и другую функцию такого же типа – аналогично нефункциональным типам:

mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
// Выведет "Result: 6"

Как и в случае с любым другим типом, вы можете не указывать тип явно, а предоставить Swift самостоятельно вывести функциональный тип при присваивании функции константе или переменной:

let anotherMathFunction = addTwoInts
// для константы anotherMathFunction выведен тип (Int, Int) -> Int

Функциональные типы как типы параметров

Функциональные типы наподобие (Int, Int) -> Int могут быть типами параметров другой функции. Это позволяет определять некоторые аспекты реализации функции непосредственно во время ее вызова.

Следующий код печатает на экране результаты работы приведенных выше математических функций:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Выведет "Result: 8"

В этом примере объявлена функция printMathResult(_:_:_:), у которой есть три параметра. Первый параметр под названием mathFunction имеет тип (Int, Int) -> Int. Соответственно, аргументом этого параметра может быть любая функция такого же типа. Второй и третий параметры называются a и b и относятся к типу Int. Они служат для передачи двух входных значений для математической функции.

При вызове printMathResult(_:_:_:) получает в качестве входных данных функцию addTwoInts(_:_:) и два целочисленных значения 3 и 5. Затем она вызывает переданную функцию со значениями 3 и 5, а также выводит на экран результат 8.

Задача функции printMathResult(_:_:_:) заключается в том, чтобы печатать результат работы математической функции соответствующего типа. При этом конкретные детали этой математической функции не имеют значения – главное, чтобы она была подходящего типа. Все это позволяет безопасно управлять работой функции printMathResult(_:_:_:) непосредственно во время вызова.

Функциональные типы как возвращаемые типы

Функциональный тип можно сделать возвращаемым типом другой функции. Для этого нужно записать полный функциональный тип сразу же после возвратной стрелки (->) в возвращаемой функции.

В следующем примере объявлены две простые функции – stepForward(_:) и stepBackward(_:). Функция stepForward(_:) возвращает входное значение, увеличенное на единицу, а функция stepBackward(_:) – уменьшенное на единицу. Обе функции имеют тип (Int) -> Int:

func stepForward(_ input: Int) -> Int {
    return input + 1
}
func stepBackward(_ input: Int) -> Int {
    return input - 1
}

Следующая функция под названием chooseStepFunction(backward:) имеет возвращаемый тип (Int) -> Int. Функция chooseStepFunction(backward:) возвращает функцию stepForward(_:) или функцию stepBackward(_:) в зависимости от значения логического параметра backward:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    return backward ? stepBackward : stepForward
}

Теперь с помощью chooseStepFunction(backward:) можно получать функцию, которая будет сдвигать значение влево или вправо:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero ссылается на функцию stepBackward()

В предыдущем примере мы определяли, нужно ли прибавить или отнять единицу, чтобы последовательно приблизить переменную currentValue к нулю. Изначально currentValue имеет значение 3, т. е. сравнение currentValue > 0 даст true, а функция chooseStepFunction(backward:), соответственно, возвратит функцию stepBackward(_:). Указатель на возвращаемую функцию хранится в константе moveNearerToZero.

Так как moveNearerToZero теперь ссылается на нужную функцию, можно использовать эту константу для отсчета до нуля:

print("Counting to zero:")
// Counting to zero:
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// 3...
// 2...
// 1...
// zero!

Все ранее рассмотренные в этом разделе функции являются глобальными, т. е. определенными в глобальном контексте. Но помимо глобальных можно объявлять и функции, находящиеся внутри других функций, или же вложенные.

Вложенные функции по умолчанию недоступны извне, а вызываются и используются только заключающей функцией. Заключающая функция может также возвращать одну из вложенных, чтобы вложенную функцию можно было использовать за ее пределами.

Приведенный выше пример с функцией chooseStepFunction(backward:) можно переписать со вложенными функциями:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero теперь ссылается на вложенную функцию stepForward() 
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// -4...
// -3...
// -2...
// -1...
// zero!

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

React.Component – React

Эта страница содержит подробный справочник API для определения классового компонента React. Предполагается, что вы знакомы с такими концепциями React, как компоненты и пропсы, а также состояние и жизненный цикл. Прочитайте про них, если вы этого не сделали.

Обзор

React позволяет определять компоненты как классы или функции. В настоящее время классовые компоненты имеют больше возможностей. Они разобраны на этой странице. Чтобы определить такой компонент, необходимо отнаследоваться от React.Component:

class Welcome extends React.Component {
  render() {
    return <h2>Привет, {this.props.name}</h2>;
  }
}

Единственный обязательный метод в подклассе React.Component — render(). Все остальные методы, описанные ниже, являются необязательными.

Мы рекомендуем не создавать собственные классы базовых компонентов. В компонентах React повторное использование кода обычно достигается за счёт композиции, а не наследования.

Примечание:

React не заставляет вас использовать синтаксис классов из ES6. Вместо этого вы можете использовать модуль create-react-class или его аналоги. Посмотрите раздел Использование React без ES6, чтобы узнать больше.

Жизненный цикл компонента

Каждый компонент имеет несколько «методов жизненного цикла». Переопределение такого метода позволяет выполнять код на конкретном этапе этого процесса. Вы можете использовать эту диаграмму жизненного цикла как шпаргалку. Далее на странице полужирным шрифтом выделены самые распространённые методы жизненного цикла.

Монтирование

При создании экземпляра компонента и его вставке в DOM, следующие методы вызываются в установленном порядке:

Примечание:

Этот метод устарел. Не используйте его в новом коде.

Обновление

Обновление происходит при изменении пропсов или состояния. Следующие методы вызываются в установленном порядке при повторном рендере компонента:

Примечание:

Эти методы устарели. Не используйте их в новом коде.

Размонтирование

Этот метод вызывается при удалении компонента из DOM:

Обработка ошибок

Следующие методы вызываются, если произошла ошибка в процессе рендеринга, методе жизненного цикла или конструкторе любого дочернего компонента.

Другие методы API

В каждом компоненте доступны методы API:

Свойства класса

Свойства экземпляра


Справочник

Распространённые методы жизненного цикла

Методы в этом разделе охватывают большинство задач, с которыми вы столкнётесь при использовании React-компонентов. Для визуального представления вы можете использовать эту диаграмму жизненного цикла.

render()

render() — единственный обязательный метод в классовом компоненте.

При вызове он проверяет this.props и this.state и возвращает один из следующих вариантов:

  • Элемент React. Обычно создаётся с помощью JSX. Указывает React, что рендерить: DOM-узел или пользовательский компонент. Например, <div /> или <MyComponent />.
  • Массивы и фрагменты. Возвращает несколько элементов из render(). Подробнее про фрагменты.
  • Порталы. Рендерит несколько дочерних элементов в другое поддерево DOM. Подробнее про порталы.
  • Строки и числа. Рендерит текстовые DOM-узлы.
  • Booleans или null. Ничего не рендерит. (Обычно необходим для поддержки паттерна return test && <Child />, где test — логическое значение.)

Функция render() должна быть чистой. Это означает, что она не изменяет состояние компонента, всегда возвращает один и тот же результат, не взаимодействует напрямую с браузером.

Взаимодействовать с браузером необходимо в componentDidMount() или других методах жизненного цикла. Чистый render() делает компонент понятным.

Примечание:

render() не вызывается, если shouldComponentUpdate() возвращает false.


constructor()

Вы можете не использовать конструктор в React-компоненте, если вы не определяете состояние или не привязываете методы.

Конструктор компонента React вызывается до того, как компонент будет примонтирован. В начале конструктора необходимо вызывать super(props). Если это не сделать, this.props не будет определён. Это может привести к багам.

Конструкторы в React обычно используют для двух целей:

Вы не должны вызывать setState() в constructor(). Если вам нужно внутреннее состояние, присвойте начальное состояние this.state прямо в конструкторе.

constructor(props) {
  super(props);
  
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}

Конструктор — единственное место, где можно напрямую изменять this.state. В остальных методах необходимо использовать this.setState().

Не используйте побочные эффекты или подписки в конструкторе. Вместо этого используйте componentDidMount().

Примечание:

Не копируйте пропсы в состояние! Это распространённая ошибка:

constructor(props) {
 super(props);
 
 this.state = { color: props.color };
}

Проблема в том, что это излишне и приводит к багам (обновления в пропе color не будут зафиксированы в состоянии). Вместо этого используйте this.props.color.

Используйте данный подход, если вы намеренно хотите игнорировать обновления пропсов. В таком случае лучше переименовать проп в initialColor или defaultColor. После этого вы сможете заставить компонент «сбросить» своё внутреннее состояние, изменив свой ключ, когда это будет необходимо.

Прочитайте нашу статью в блоге про отсутствие необходимости в производном состоянии. Она описывает случаи, в которых вам необходимо состояние, зависящее от пропсов.


componentDidMount()

componentDidMount() вызывается сразу после монтирования (то есть, вставки компонента в DOM). В этом методе должны происходить действия, которые требуют наличия DOM-узлов. Это хорошее место для создания сетевых запросов.

Этот метод подходит для настройки подписок. Но не забудьте отписаться от них в componentWillUnmount().

Вы можете сразу вызвать setState() в componentDidMount(). Это вызовет дополнительный рендер перед тем, как браузер обновит экран. Гарантируется, что пользователь не увидит промежуточное состояние, даже если render() будет вызываться дважды. Используйте этот подход с осторожностью, он может вызвать проблемы с производительностью. В большинстве случаев начальное состояние лучше объявить в constructor(). Однако, это может быть необходимо для случаев, когда нужно измерить размер или положение DOM-узла, на основе которого происходит рендер. Например, для модальных окон или всплывающих подсказок.


componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot)

componentDidUpdate() вызывается сразу после обновления. Не вызывается при первом рендере.

Метод позволяет работать с DOM при обновлении компонента. Также он подходит для выполнения таких сетевых запросов, которые выполняются на основании результата сравнения текущих пропсов с предыдущими. Если пропсы не изменились, новый запрос может и не требоваться.

componentDidUpdate(prevProps) {
  
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

В componentDidUpdate() можно вызывать setState(), однако его необходимо обернуть в условие, как в примере выше, чтобы не возник бесконечный цикл. Вызов setState() влечет за собой дополнительный рендер, который незаметен для пользователя, но может повлиять на производительность компонента. Вместо «отражения» пропсов в состоянии рекомендуется использовать пропсы напрямую. Подробнее о том, почему копирование пропсов в состояние вызывает баги.

В тех редких случаях когда реализован метод жизненного цикла getSnapshotBeforeUpdate(), его результат передаётся componentDidUpdate() в качестве третьего параметра snapshot.

Примечание:

componentDidUpdate() не вызывается, если shouldComponentUpdate() возвращает false.


componentWillUnmount()

componentWillUnmount() вызывается непосредственно перед размонтированием и удалением компонента. В этом методе выполняется необходимый сброс: отмена таймеров, сетевых запросов и подписок, созданных в componentDidMount().

Не используйте setState() в componentWillUnmount(), так как компонент никогда не рендерится повторно. После того, как экземпляр компонента будет размонтирован, он никогда не будет примонтирован снова.


Редко используемые методы жизненного цикла

Методы из этого раздела используются редко. В большинстве компонентов они не нужны, хотя иногда бывают полезны. Вы можете увидеть большинство приведённых ниже методов на этой диаграмме жизненного цикла, если наверху страницы нажмёте на чекбокс «Показать менее популярные методы жизненного цикла».

shouldComponentUpdate()
shouldComponentUpdate(nextProps, nextState)

Используйте shouldComponentUpdate(), чтобы указать необходимость следующего рендера на основе изменений состояния и пропсов. По умолчанию происходит повторный рендер при любом изменении состояния. В большинстве случаев вы должны полагаться на это поведение.

shouldComponentUpdate() вызывается перед рендером, когда получает новые пропсы или состояние. Значение по умолчанию равно true. Этот метод не вызывается при первом рендере или когда используется forceUpdate().

Этот метод нужен только для повышения производительности. Но не опирайтесь на его возможность «предотвратить» рендер, это может привести к багам. Вместо этого используйте PureComponent, который позволяет не описывать поведение shouldComponentUpdate() вручную. PureComponent поверхностно сравнивает пропсы и состояние и позволяет не пропустить необходимое обновление.

Если вы уверены, что хотите написать его вручную, вы можете сравнить this.props с nextProps, а this.state с nextState. Верните false чтобы пропустить обновление React. Возврат false не предотвращает повторный рендер дочерних компонентов при изменении их состояния.

Мы не рекомендуем делать глубокое сравнение или использовать JSON.stringify() в shouldComponentUpdate(). Это неэффективно и плохо влияет на производительность.

В настоящее время, если shouldComponentUpdate() возвращает false, то UNSAFE_componentWillUpdate(), render() и componentDidUpdate() не будут вызваны. В будущем React может рассматривать shouldComponentUpdate() как подсказку, а не строгое указание. В таком случае возврат false сможет привести к повторному рендеру компонента.


static getDerivedStateFromProps()
static getDerivedStateFromProps(props, state)

getDerivedStateFromProps вызывается непосредственно перед вызовом метода render, как при начальном монтировании, так и при последующих обновлениях. Он должен вернуть объект для обновления состояния или null, чтобы ничего не обновлять.

Этот метод существует для редких случаев, когда состояние зависит от изменений в пропсах. Например, это подойдёт для реализации компонента <Transition>, который сравнивает свои предыдущие и следующие дочерние компоненты, чтобы решить, какой из них нужно анимировать.

Производное состояние приводит к сложному коду и делает ваши компоненты сложными для понимания. Убедитесь, что вы знакомы с простыми альтернативами:.

Этот метод не имеет доступа к экземпляру компонента. Чтобы использовать пропсы, состояние и методы класса в getDerivedStateFromProps(), их нужно вынести за пределы класса в виде чистых функций.

Если вы хотите повторно использовать код между getDerivedStateFromProps() и другими методами класса, извлеките чистые функции пропсов и состояния компонента и поместите их вне определения класса.

Обратите внимание, что этот метод запускается при каждом рендере, независимо от причины. Это отличается от метода UNSAFE_componentWillReceiveProps, который запускается только при повторном рендере родительского компонента, а не в результате вызова setState.


getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState)

getSnapshotBeforeUpdate() вызывается прямо перед этапом «фиксирования» (например, перед добавлением в DOM). Он позволяет вашему компоненту брать некоторую информацию из DOM (например, положение прокрутки) перед её возможным изменением. Любое значение, возвращаемое этим методом жизненного цикла, будет передано как параметр componentDidUpdate().

Это применяется редко, но может быть полезно в таких интерфейсах, как цепочка сообщений в чатах, в которых позиция прокрутки обрабатывается особым образом.

Значение снимка (или null) должно быть возвращено.

Например:

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    
    
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    
    
    
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{}</div>
    );
  }
}

В примерах выше важно получить значение свойства scrollHeight в getSnapshotBeforeUpdate из-за того, что могут возникать задержки между этапами жизненного цикла «рендер» (например, render) и «фиксирование» (например, getSnapshotBeforeUpdate и componentDidUpdate).


Предохранители

Предохранители — это React-компоненты, которые перехватывают JavaScript-ошибки в любом месте их дочернего дерева компонентов. Затем логируют эти ошибки и отображают запасной интерфейс вместо «поломанного» дерева компонентов. Предохранители отлавливают ошибки при рендере, в методах жизненного цикла и в конструкторах всего дерева под ними.

Классовый компонент становится предохранителем, если в нём используются методы жизненного цикла static getDerivedStateFromError() и (или) componentDidCatch(). Обновление состояния в этом методе жизненного цикла позволяет перехватить необработанную JavaScript-ошибку в дереве ниже и отобразить запасной интерфейс.

Используйте предохранители только для обработки неожиданных исключений, не используйте их для управления потоком исполнения в вашем приложении.

Подробнее в разделе Предохранители в React 16.

Примечание:

Предохранители перехватывают ошибки в компонентах ниже по дереву. Предохранители не могут поймать ошибку внутри себя.

static getDerivedStateFromError()
static getDerivedStateFromError(error)

Этот метод жизненного цикла вызывается после возникновения ошибки у компонента-потомка. Он получает ошибку в качестве параметра и возвращает значение для обновления состояния.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {        return { hasError: true };  }
  render() {
    if (this.state.hasError) {            return <h2>Что-то пошло не так.</h2>;    }
    return this.props.children;
  }
}

Примечание:

getDerivedStateFromError() вызывается во время этапа «рендера». Поэтому здесь запрещены любые побочные эффекты, но их можно использовать в componentDidCatch().


componentDidCatch()
componentDidCatch(error, info)

Этот метод жизненного цикла вызывается после возникновения ошибки у компонента-потомка. Он получает два параметра:

  1. error — перехваченная ошибка
  2. info — объект с ключом componentStack, содержащий информацию о компоненте, в котором произошла ошибка.

componentDidCatch() вызывается во время этапа «фиксации», поэтому здесь можно использовать побочные эффекты. Метод можно использовать для логирования ошибок.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    
    return { hasError: true };
  }

  componentDidCatch(error, info) {                        logComponentStackToMyService(info.componentStack);  }
  render() {
    if (this.state.hasError) {
      
      return <h2>Что-то пошло не так.</h2>;
    }

    return this.props.children;
  }
}

Обработка ошибок в методе componentDidCatch() отличается между React-сборками для продакшена и разработки.

В процессе разработки ошибки будут подниматься (всплывать) наверх до объекта window, поэтому любой вызов window.onerror или window.addEventListener('error', callback) перехватит ошибки, которые были обработаны componentDidCatch().

На продакшене, напротив, ошибки не всплывают, поэтому родительский обработчик ошибок перехватит только те ошибки, которые не были обработаны componentDidCatch().

Примечание:

В случае ошибки вы можете рендерить запасной интерфейс с помощью componentDidCatch(), вызвав setState. Однако, этот способ скоро будет считаться устаревшим. Используйте static getDerivedStateFromError() для рендера резервного интерфейса.


Устаревшие методы жизненного цикла

Приведённые ниже методы жизненного цикла устарели. Их не рекомендуется использовать в новом коде, хотя они продолжают работать. Вы можете узнать больше о переходе с устаревших методов жизненного цикла в блоге.

UNSAFE_componentWillMount()
UNSAFE_componentWillMount()

Примечание:

Этот метод жизненного цикла раньше назывался componentWillMount. По этому названию он будет доступен до 17 версии. Чтобы автоматически обновить компоненты, используйте rename-unsafe-lifecycles.

UNSAFE_componentWillMount() вызывается непосредственно перед монтированием. Он вызывается перед render(), поэтому синхронный вызов setState() в этом методе не вызовет дополнительный рендер. Для инициализации состояния мы рекомендуем использовать constructor().

Избегайте добавления каких-либо побочных эффектов или подписок в этом методе. Вместо этого используйте componentDidMount().

Это единственный метод жизненного цикла, вызываемый при серверном рендеринге.


UNSAFE_componentWillReceiveProps()
UNSAFE_componentWillReceiveProps(nextProps)

Примечание:

Этот метод жизненного цикла раньше назывался componentWillReceiveProps. По этому названию он будет доступен до 17 версии. Чтобы автоматически обновить компоненты, используйте rename-unsafe-lifecycles.

Примечание:

Использование этого метода жизненного цикла часто приводило к багам

Другие рекомендации можно посмотреть в статье про производное состояние.

UNSAFE_componentWillReceiveProps() вызывается до того, как смонтированный компонент получит новые пропсы. Чтобы обновить состояние в ответ на изменение пропсов (например, для его сброса), можно сравнить this.props с nextProps и обновить состояние в этом методе с помощью this.setState().

Обратите внимание, если родительский компонент заставляет ваш компонент повторно рендериться, метод будет вызываться, даже если пропсы не изменились. Убедитесь, что сравниваете текущие и следующие значения, если вы хотите обрабатывать изменения.

Во время монтирования React не вызывает UNSAFE_componentWillReceiveProps() с начальными значениями пропсов. Этот метод вызывается, если некоторые пропсы компонента могут обновиться. Вызов this.setState() обычно не вызывает UNSAFE_componentWillReceiveProps().


UNSAFE_componentWillUpdate()
UNSAFE_componentWillUpdate(nextProps, nextState)

Примечание:

Этот метод жизненного цикла раньше назывался componentWillUpdate. По этому названию он будет доступен до 17 версии. Чтобы автоматически обновить компоненты, используйте rename-unsafe-lifecycles.

UNSAFE_componentWillUpdate() вызывается непосредственно перед рендером при получении новых пропсов или состояния. В этом методе можно выполнить некоторую подготовку перед обновлением. Этот метод не вызывается при первом рендере.

Внутри этого метода нельзя вызвать this.setState(), а также делать какие-либо действия, которые влияют на обновление компонента перед возвратом UNSAFE_componentWillUpdate() (например, отправка действия Redux).

Обычно этот метод можно заменить на componentDidUpdate(). Вы можете использовать getSnapshotBeforeUpdate() для работы с DOM (например, запоминать положение прокрутки страницы).

Примечание:

UNSAFE_componentWillUpdate() не вызывается, если shouldComponentUpdate() возвращает false.


Другие методы API

В отличие от методов жизненного цикла, представленных выше (React вызывает их сам), методы, приведённые ниже, можно вызывать из компонентов.

Их всего два: setState() и forceUpdate().

setState()
setState(updater, [callback])

setState() добавляет в очередь изменения в состоянии компонента. Также он указывает React, что компонент и его дочерние элементы должны быть повторно отрендерены с обновлённым состоянием. Этот метод используется для обновления интерфейса в ответ на обработчики событий и ответы сервера.

Думайте о setState(), как о запросе, а не как о команде немедленного обновления компонента. Для увеличения производительности React может задержать его выполнение, а затем обновить несколько компонентов за один проход. React не гарантирует моментальное применение изменений в состоянии.

Метод setState() не всегда обновляет компонент сразу. Он может группировать или откладывать обновление до следующего раза. Это делает чтение this.state сразу после вызова setState() потенциальной ловушкой. Вместо этого используйте componentDidUpdate() или колбэк setState() (setState(updater, callback)), каждый из которых гарантированно вызывается после того как было применено обновление. Если вам нужно обновить состояние на основе предыдущего, используйте аргумент updater, описанный ниже.

setState() всегда приводит к повторному рендеру, если только shouldComponentUpdate() не возвращает false. Если используются мутабельные объекты, и условие рендеринга не может быть реализовано в shouldComponentUpdate(), вызывайте setState() только при разнице следующего и предыдущего состояния. Это предотвратит ненужные повторные рендеры.

Первым аргументом передаётся функция updater, которая имеет следующий вид:

(state, props) => stateChange

state — ссылка на состояние компонента при изменении. Объект состояния не должен мутировать. Изменения должны проявляться в виде нового объекта на основе входных данных из state и props. Предположим, что мы хотели бы увеличить значение состояния с помощью props.step:

this.setState((state, props) => {
  return {counter: state.counter + props.step};
});

Как state, так и props, полученные функцией обновления, гарантированно будут обновлены. Результат функции поверхностно объединяется с state.

Второй параметр в setState() — необязательный колбэк, вызываемый после выполнения setState и повторного рендера компонента. Вместо этого в большинстве случаев для такой логики мы рекомендуем использовать componentDidUpdate().

В качестве первого аргумента setState(), вместо функции, вы можете передать объект:

setState(stateChange[, callback])

В нём образуется новое состояние после поверхностного объединения с stateChange. Например, установим количество товаров в корзине:

this.setState({quantity: 2})

Эта форма записи setState() также асинхронна, и несколько вызовов в течение одного цикла могут быть объединены вместе. Например, вам нужно увеличить количество элементов несколько раз в одном цикле. Результат этого можно представить так:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

Последующие вызовы будут переопределять значения из предыдущих вызовов того же цикла. Из-за этого количество увеличится только один раз. В случае, если следующее состояние зависит от текущего, мы рекомендуем использовать форму функции обновления:

this.setState((state) => {
  return {quantity: state.quantity + 1};
});

Для более подробной информации смотрите:


forceUpdate()
component.forceUpdate(callback)

По умолчанию при изменении состояния компонента или пропсов, происходит повторный рендер. Если ваш метод render() зависит от некоторых других данных, вы можете указать React необходимость в повторном рендере, вызвав forceUpdate().

Вызов forceUpdate() приведёт к выполнению метода render() в компоненте, пропуская shouldComponentUpdate(). Это вызовет обычные методы жизненного цикла для дочерних компонентов, включая shouldComponentUpdate() каждого дочернего компонента. React по-прежнему будет обновлять DOM только в случае изменения разметки.

Чаще всего, forceUpdate() не используется. Вместо этого используются в render() данные из this.props и this.state.


Свойства класса

defaultProps

defaultProps можно определить как свойство самого класса компонента, которое позволяет установить пропсы класса по умолчанию. Это используется для неопределённых (undefined) пропсов, но не для пропсов со значением null. Например:

class CustomButton extends React.Component {
  
}

CustomButton.defaultProps = {
  color: 'синий'
};

Если props.color не передаётся, по умолчанию установится 'синий':

  render() {
    return <CustomButton /> ; 
  }

Если props.color имеет значение null, оно останется null:

  render() {
    return <CustomButton color={null} /> ; 
  }

displayName

Строка displayName используется в сообщениях для отладки. Обычно вам не нужно её явно указывать. По умолчанию используется имя функции или класса, указанное при определении компонента. Если вам нужно установить его явно, например, для отладки или создания компонента высшего порядка, посмотрите раздел Обёртка отображаемого имени для простой отладки.


Свойства экземпляра

props

this.props содержит свойства, которые были определены тем, кто вызывает этот компонент. Подробнее об этом можно узнать в разделе Компоненты и пропсы

Существует специальный проп this.props.children, который обычно определяется дочерними тегами в JSX-выражении, а не в самом теге.

state

Состояние содержит данные, специфичные для этого компонента. Они могут измениться со временем. Состояние определяется пользователем и должно быть простым объектом JavaScript.

Вам не нужно вставлять в состояние значение, если оно не используется для рендера или потока данных (например, идентификатор таймера). Такие значения можно определить как поля экземпляра компонента.

Дополнительную информацию можно найти в разделе Состояние и жизненный цикл.

Никогда не мутируйте this.state напрямую, так как более поздний вызов setState() может перезаписать эту мутацию. Относитесь к this.state как к иммутабельному объекту.

База знаний | Gilev.ru | Ускоряем 1С:Предприятие | Gilev.ru | Ускоряем 1С:Предприятие

Выбор SSD для клиент-серверного варианта 1С для коллективной работы отличается от покупки SSD для своего ноутбука.

 

Значимым требованием к диску является в том числе такой фактор, как ресурс перезаписи.

Быстрее всего на класс устройства можно сориентироваться по показателям DWPD (или “полных перезаписей устройства в день в течение гарантийного срока”) и/или TBW/PBW (или “общий объём данных, который за время гарантийного срока можно записать на устройство»), измеряется в терабайтах для TBW и петабайтах для PBW. Чем выше/больше “полных перезаписей устройства в день” DWPD — тем обычно выше класс устройства.

 

Разные производители по-разному трактуют классы промышленных SSD, но в целом можно привести такой пример разделения:

  • DWPD 0.1 и меньше — класс “boot”, то есть носитель для операционной системы, и больше на него ничего записывать не надо;
    Условно можно считать что это диски для одного пользователя 1С.

  • ssd 0.3-1 — класс read intensive или RI, он же “оптимизированный для операций чтения”. Носители например для складывания архивов или архивных баз, разных “файлопомоек”, куда интенсивность записи невысокая;
    В отдельных случаях это могут быть диски для файловых баз 1С на несколько человек.

  • DWPD 3-5 — класс mixed use или MU, устройства предназначены для “средних уровней интенсивности записи”, какие-нибудь второстепенные базы со средним уровнем активности;
    Самый популярный диапазон. Учтите, что независимо от реальных задач, в “полках” чаще всего бывают именно эти диски. Такие диски хороши для нескольких десятков пользователей 1С.

  • DWPD 10 и более — класс write intensive или WI, устройства предназначены для высокого уровня интенсивности записи, объём записи будет такой, что за сутки может быть перезаписан много раз без существенной потери производительности. Именно этот класс рекомендуется использовать “в общем” для серверов с высокой активностью записи, но гораздо лучше это делать не вслепую, а предварительно оценив фактические объёмы записи на нужном сервере.
    Продавцы “железа” не любят продавать эти диски. Более того, они отговаривают клиентов их покупать. Однако если речь идёт о накопителях для сервера, обслуживающего многие сотни пользователей 1С — соответствующие нагрузке модели дисков находятся как правило именно в этом классе устройств.

Косвенно класс устройства можно понять, сопоставляя паспортные IOPS на чтение и запись. Чем ниже показатель записи по отношению к чтению — тем вероятно ниже и класс устройства. Например, у крайне производительных intel Optane с DWPD 30-60 соотношение примерно 550K/550K, у “средних” P4610 с DWPD 3 соотношение 638K/222K, а у совсем “слабых” P4101 с DWPD на уровне 0.1-0.3 — соотношение 275K/16K у старшей модели в линейке и 60K/2.2K у младшей. 

 

Очень важно понимать, что показатель износостойкости говорит не только о том, сколько всего данных за гарантийный срок можно будет записать на носитель, но и косвенно говорит о том, какой объём данных в среднем в сутки можно на этот носитель записать без существенного ухудшения производительности (то есть деградации производительности, о чём мы подробнее расскажем в одной из следующих статей). Закончиться ресурс накопителя может ещё только через годы, а деградация производительности может себя проявить прямо с первого дня активной эксплуатации.

 

К сожалению, на сайте intel не по всем моделям можно быстро увидеть паспортную ресурсоёмкость устройства, которая выражается в параметрах , поэтому приходится использовать сторонние источники. В качестве примера ресурса, где можно быстро сравнить ресурсоемкость по DWPD/TBW: https://en.wikipedia.org/wiki/List_of_Intel_SSDs. 

 

Оценка текущей интенсивности записи на диск

Для понимания, какой вам нужен диск, наиболее достоверным действием будет замер ваших текущих нагрузок на диск: какова реальная интенсивность записи на диск.

 

Если Вы используете 1С в наиболее популярном варианте в связке с MS SQL Server, то основная нагрузка на диск будет через него и с помощью запросов к статистике сервера можно получить оценку интенсивности записи .

Нюанс тут заключается в том, что СУБД оценивает только “свою” запись (то есть не видит любые другие объёмы, записанные другими службами), и полученные цифры говорят об объемах чтения и записи только с момента старта службы MS SQL.
Обратите внимание, что если у вас будут и другие источники значимой интенсивности записи, то ниже показанный способ будет недостаточным. Если вы пишете например в виртуалке на виртуальный диск, расположенный на общем внешнем хранилище дисков, то реальную нагрузку на диски мы можем и не измерить правильно в таком подходе.

 

Как смотреть накопленную статистику MS SQL Server

Данные с СУБД можно получать сразу в сгруппированном по дискам виде, и сразу с пересчётом в гигабайты, например таким запросом: 

SELECT SUBSTRING(saf.physical_name, 1, 1) AS [Диск]

, SUM(vfs.num_of_bytes_read/1024/1024/1024) AS [Прочитано (Гб)]

, SUM(vfs.num_of_bytes_written/1024/1024/1024) AS [Записано (Гб)]

FROM sys.master_files AS saf

JOIN sys.dm_io_virtual_file_stats(NULL,NULL) AS vfs

ON vfs.database_id = saf.database_id

AND vfs.file_id = saf.file_id

GROUP BY SUBSTRING(saf.physical_name, 1, 1)

ORDER BY [Диск]

 

например, получится вот такой результат:

При этом, поскольку это данные с момента старта службы — будет полезно сразу оценить и время, за которое эти данные накоплены, например таким запросом:

ВАЖНО. Если с момента рестарта пройдет меньше суток, то надо как минимум подождать пока набегут сутки и повторно посчитать.

ВАЖНО. Интенсивность записи в разные дни может быть сильно разная. Достаточно репрезентативным показательным интервалом времени аптайма сервера для оценки можно считать квартал. Либо генерируете в исследуемом небольшом период пик нагрузки.

ВАЖНО. Любая запись на диски, сделанная НЕ средствами СУБД, например полных бэкапов внешними средствами (например Акронис Бэкап) в замер субд не попадет.

 

Как видно на снимке, служба сервера запущена 14 дней 19 часов (или 355 часов) назад, и статистика накоплена именно за это время.

Дальше можно просто вычислить средний объём записи в сутки.

Например, в примере на диск P за это время записано 5142 гигабайта, то есть за неполных 15 дней выходит в среднем примерно по 350 гигабайт в сутки. Как получена эта величина: 5142 записанных гигабайта делим на 355 часов сбора статистики и умножаем на 24 часа в сутках.

Таким образом в текущем примере интенсивность записи — 350 гигабайт в сутки.


Теперь чтобы подобрать SSD, надо посмотреть на подходящий размер и соответствующих “полных перезаписей устройства в день” DWPD.

Если Вы берете диск с 0,1 DWPD intel P4101 емкостью 512 Gb, то 512 * 0,1 = 51,2 Гб/сутки < реальной нагрузки 350 гигабайт в сутки. На практике Вы получите непредсказуемую неудовлетворительную работу диска.
Кроме того, в реальной жизни не только SQL Server генерирует нагрузку, так что надо еще делать поправочный коэф.-т на другую активность.

Требуемый нам диск должен перезаписывать более 400 Гигабайт. Понятно, что кроме этого надо смотреть на требуемый реальный размер диска. Вдруг у нас база размером в терабайт. Рассмотрим на примере диска intel p4610 размером 1,6 Тб 

https://ark.intel.com/content/www/ru/ru/ark/products/140103/intel-ssd-dc-p4610-series-1-6tb-2-5in-pcie-3-1-x4-3d2-tlc.html

Рейтинг износоустойчивости (операции записи за все время эксплуатации): 12.25PBW — это означает гарантированную возможность записать 12.25 петабайта за гарантийный срок, который составляет: Гарантийный период: 5 yrs, то есть 5 лет. 

Пересчитываем условно рейтинг износоустойчивости в расчёте “на 1 день”: 12.25 петабайт = 12250 терабайт, делим на (5 лет Х на 365 дней), получаем 6.7 терабайта в день, теперь делим эту величину на объём диска и получаем примерно 4 объёма полной перезаписи в день (то есть DWPD).

 

Сравниваем 6.7 Тб и 350 Гб реальной нагрузки (лучше с некоторым поправочным коэф.-том) — получаем приемлемый запас по ресурсу перезаписи, который гарантированно справится с текущей нагрузкой.

При этом надо понимать, что статистика представляет собой “среднее по больнице”, в периоды высокой активности пользователей запись может быть в несколько раз больше, или во время ночных регламентов на СУБД, а в другие периоды бывает поспокойней. 

Наиболее представительной данная информация будет например, если скриптом получать в некую табличку результат запросов по объёму записи каждый час в течение скажем нескольких дней высокой загрузки, а затем определить интенсивность записи именно в пиковые периоды, когда это могло мешать производительности бизнеса. Например, ночью нагрузка на диски будет большая, но в это время никто в базе не работает, и диски к началу рабочего дня уже могли успеть “прийти в себя”. Но может оказаться и так, что в течение нескольких часов нагрузка на диски по записи существенно превышает паспортную, и производительность записи заметно ухудшается.

 

Бонус: если используется платный сервис http://gilev.ru/sqlsize 

Если на сервере СУБД используется платный сервис http://gilev.ru/sqlsize, то можно сразу воспользоваться уже собранными там данными.

Поскольку данные статистики использования дисков накапливаются с момента старта службы — будет полезно сразу оценить время, за которое эти данные накоплены, в сервисе SQLSize это пункт “Параметры СУБД — Параметры SQL сервер”, пункты “Аптайм (часов)” и “Аптайм (дней)”, например мы там увидим 297 часов или 13 дней.

Далее смотрим статистику использования дисковой подсистемы в пункте “Нагрузка на сервер СУБД — Диски — Интенсивность использования”.

Надпись справа от названия отчёта информирует о том, когда именно была получена эта информация. На данном снимке нас интересует колонка “Записано, МБ”. Если просуммировать все показанные на снимке значения из этой колонки — получается примерно 4540 гигабайт записи на диск C.

 

Дальше можно просто вычислить средний объём записи в сутки.

В данном примере получается в среднем примерно по 350 гигабайт в сутки. При этом надо понимать, что статистика представляет собой “среднее по больнице”, ведь наверняка в периоды высокой активности пользователей запись существенно больше, или во время ночных регламентов на СУБД, а в другие периоды бывает поспокойней. Наиболее представительной данная информация будет например, если скриптом получать в некую табличку результат запросов по объёму записи каждый час в течение скажем нескольких дней высокой загрузки, а затем определить интенсивность запись именно в пиковые периоды, когда это могло мешать производительности бизнеса. Например, ночью нагрузка на диски будет большая, но в это время никто в базе не работает, и диски к началу рабочего дня уже могли успеть “прийти в себя”. Но может оказаться и так, что в течение нескольких часов нагрузка на диски по записи существенно превышает паспортную, и производительность записи заметно ухудшается (о чём нам как бы намекает из вышеприведённого снимка колонка “Отклик на запись”, где среднее сглаженное время отклика одной операции записи на разных файлах плавает от 13 до 27 миллисекунд, что было когда-то приемлемо для механических дисков, но это много для SSD, особенно с учётом того, что это той же “среднее по больнице” за 13 дней).

 

Дальше будет полезно выяснить, какая же модель накопителей используется в данном сервере, после этого сравнить «расчётные по DWPD» объёмы записи с фактическими.

Выяснено, что диск обслуживается рассмотренным выше по тексту накопителем intel P4101, вот линк на его спецификацию: https://ark.intel.com/content/www/ru/ru/ark/products/148630/intel-ssd-dc-p4101-series-1-024tb-m-2-80mm-pcie-3-0-x4-3d2-tlc.html 

Заметим, что производитель решил умолчать в данной спецификации о таких важных параметрах, как DWPD (гарантийный показатель количества перезаписей в день) и гарантийный ресурс устройства на запись. Практически единственным намёком на класс устройства в данной спецификации может служить соотношение IOPS на чтение и запись, а именно 275К против 16К.

Однако заметим, что если поискать данное устройство на сайте intel https://www.intel.ru/content/www/ru/ru/products/memory-storage/solid-state-drives/data-center-ssds.html — мы его найдём в разделе “Твердотельные накопители Intel® серии D1: 

Оптимальная надежность и производительность бюджетного уровня для рабочих нагрузок с большим количеством операций чтения“. На странице описания собственно модели P4101 https://www.intel.ru/content/www/ru/ru/products/memory-storage/solid-state-drives/data-center-ssds/d1-series/dc-p4101-series.html написано: “Этот твердотельный накопитель с 64-слойной технологией Intel® TLC PCIe* NAND в форм-факторе M.2 разработан для моделей использования в качестве загрузочного диска и рабочих нагрузок с небольшим количеством операций чтения, таких как индексирование поисковых запросов и кэширование на периферии.”. Это такой намёк от intel, что не надо подобный диск использовать под активно записываемые базы данных 🙂

 

Дальнейшие поиски в интернете показывают различные варианты DWPD для данного устройства, но в целом они колеблются между 0.1 и 0.3, что для накопителя с ёмкостью 1 терабайт означает расчётный объём допустимой записи не более 100-300 гигабайт в сутки, причём расчёт исходит из идеально ровного распределения данного объёма внутри времени суток, то есть за каждый час не более 1/24 данного объёма. Очевидно, если в наблюдаемом примере каждые сутки на диск пишется более 350 гигабайт — это даже в оптимистичном варианте находится выше уровня предельно допустимой нагрузки. А если исходить из того, что в пиках активности запись на диск производится гораздо интенсивнее — станет понятно, что данная модель откровенно не подходит для имеющейся нагрузки, нужно устройство с существенно более высоким показателем DWPD на имеющийся объём (например, из имеющихся в продаже устройств могут подойти: intel P4610 с паспортным DWPD 3, то есть при объёме 1.6 терабайта — возможность записать в сутки до 4.8 терабайт, или Samsung PM1735 с таким же паспортным DWPD3).

О ПРОДАВЦАХ

Естественно любой продавец будет продавать диски подешевле, так как при этом он будет делать Вам более выгодное предложение нежели конкурент. В его задачу будет входить убедить Вас всеми правдами и неправдами — у нас есть «аналог», но только подешевле… При этом смотреть Вашу реальную интенсивность он вряд ли будет. Реальная судьба систем продавцов не интересует, даже если они Вам говорят обратное — они не могут быть объективны и не несут финансовой ответственности за ситуации, когда диск не решает возложенные на него задачи.

Понятно, что это всего лишь один из факторов, который надо учитывать при покупке SSD. Но его недооценка частенько приводит к очень неприятным последствиям.

 

 

python — как передать переменную по ссылке?

Аргументы передаются по присваиванию. Обоснование этого двоякое:

  1. переданный параметр на самом деле является ссылкой на объект (но ссылка передается по значению)
  2. некоторые типы данных изменяемы, а другие нет

Итак:

  • Если вы передадите в метод изменяемый объект , метод получит ссылку на тот же объект, и вы можете изменить его к своему удовольствию, но если вы повторно привяжете ссылку в методе, внешняя область ничего не будет знать об этом, и после того, как вы закончите, внешняя ссылка по-прежнему будет указывать на исходный объект.

  • Если вы передаете методу неизменяемый объект , вы все равно не сможете повторно привязать внешнюю ссылку и даже не сможете изменить объект.

Для большей наглядности приведем несколько примеров.

Список — изменяемый тип

Попробуем изменить список, переданный методу:

  def try_to_change_list_contents (the_list):
    print ('получил', the_list)
    the_list.append ('четыре')
    print ('изменено на', the_list)

external_list = ['один', 'два', 'три']

print ('раньше, внешний_лист =', внешний_лист)
try_to_change_list_contents (внешний_лист)
print ('после, внешний_лист =', внешний_лист)
  

Выход:

  раньше, outer_list = ['one', 'two', 'three']
получил ['один', 'два', 'три']
изменено на ['один', 'два', 'три', 'четыре']
after, outer_list = ['один', 'два', 'три', 'четыре']
  

Поскольку переданный параметр является ссылкой на outer_list , а не его копией, мы можем использовать методы изменяющегося списка, чтобы изменить его и отразить изменения во внешней области видимости.

Теперь посмотрим, что происходит, когда мы пытаемся изменить ссылку, переданную в качестве параметра:

  def try_to_change_list_reference (the_list):
    print ('получил', the_list)
    the_list = ['and', 'we', 'can', 'not', 'lie']
    print ('установить в', the_list)

external_list = ['мы', 'нравится', 'правильный', 'английский']

print ('раньше, внешний_лист =', внешний_лист)
try_to_change_list_reference (внешний_лист)
print ('после, внешний_лист =', внешний_лист)
  

Выход:

  раньше, outer_list = ['мы', 'нравится', 'правильный', 'английский']
получил ['мы', 'как', 'правильный', 'английский']
установить на ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['мы', 'нравится', 'правильный', 'английский']
  

Поскольку параметр the_list передавался по значению, назначение ему нового списка не имело никакого эффекта, чтобы код вне метода мог видеть. the_list был копией ссылки outer_list , и у нас было the_list , указывающее на новый список, но не было возможности изменить место, куда указывает outer_list .

String — неизменяемый тип

Это неизменяемое, поэтому мы ничего не можем сделать, чтобы изменить содержимое строки

А теперь попробуем изменить ссылку

  def try_to_change_string_reference (the_string):
    print ('получил', the_string)
    the_string = 'В королевстве у моря'
    print ('установить в', the_string)

external_string = 'Это было много-много лет назад'

print ('раньше, external_string =', outer_string)
try_to_change_string_reference (внешняя_строка)
print ('после, external_string =', outer_string)
  

Выход:

  раньше, outer_string = Это было много-много лет назад
получил Это было много-много лет назад
установлен в королевство у моря
after, outer_string = Это было много-много лет назад
  

Опять же, поскольку параметр the_string был передан по значению, присвоение ему новой строки не повлияло на то, что код вне метода мог видеть. the_string была копией ссылки outer_string , и у нас было the_string , указывающее на новую строку, но не было возможности изменить, где указывала outer_string .

Надеюсь, это немного проясняет ситуацию.

РЕДАКТИРОВАТЬ: Было отмечено, что это не отвечает на вопрос, который изначально задал @David: «Могу ли я что-то сделать, чтобы передать переменную по фактической ссылке?». Давай поработаем над этим.

Как нам это обойти?

Как показывает ответ @Andrea, вы можете вернуть новое значение.Это не меняет способа передачи информации, но позволяет получить обратно нужную информацию:

  def return_a_whole_new_string (the_string):
    new_string = something_to_do_with_the_old_string (the_string)
    вернуть new_string

# тогда вы могли бы назвать это как
my_string = return_a_whole_new_string (моя_строка)
  

Если вы действительно хотите избежать использования возвращаемого значения, вы можете создать класс для хранения вашего значения и передать его в функцию или использовать существующий класс, например список:

  def use_a_wrapper_to_simulate_pass_by_reference (stuff_to_change):
    new_string = something_to_do_with_the_old_string (stuff_to_change [0])
    stuff_to_change [0] = новая_строка

# тогда вы могли бы назвать это как
оболочка = [my_string]
use_a_wrapper_to_simulate_pass_by_reference (оболочка)

do_something_with (оболочка [0])
  

Хотя это кажется немного громоздким.

передается по ссылке — объект Python NoneType не работает должным образом

Это как раз тот случай, когда вызов по объекту (правила Python) отличается от вызова по ссылке (семантика ссылок C ++).

Разница в том, что присвоение неквалифицированному имени повторно связывает имя, оно не оказывает никакого влияния на то, с чем это имя могло быть ранее связано (кроме возможного его уничтожения, если не осталось других ссылок). Имя не имеет связи с другими именами, которые могут ссылаться на тот же объект, поэтому эти другие имена не меняются.

Итак, в этом случае объект изначально настроен так, чтобы указывать на тот же объект example.value указывает на. Но в следующей строке вы повторно связываете объект (неквалифицированное присвоение имени), и он указывает на совершенно другой объект.

Для сравнения, если бы у вас было:

  def assign_value (сам, объект):
    object.value = OtherClass ()
  

и позвонил по номеру:

  example.assign (пример)
  

, затем , пример и объект будут ссылаться на один и тот же объект, и ваше присвоение квалифицированному имени заменит значение на этом одном объекте.

С учетом всего сказанного, ваш вариант использования не требует таких изменений. Вызов example.assign (example.value) не имеет никакого смысла, потому что self передается неявно и автоматически предоставит вам доступ к значению (квалифицированный доступ не меньше). Похоже, что вы действительно хотели, это просто ленивая инициализация при запросе без каких-либо аргументов:

  def assign (self):
    self.value = OtherClass ()
  

называется:

  пример.назначать()
  

В ответ на ваши изменения: Python явно документирует это поведение вызова:

Фактические параметры (аргументы) вызова функции вводятся в локальную таблицу символов вызываемой функции при ее вызове; таким образом, аргументы передаются с использованием вызова по значению (где значение всегда является ссылкой на объект, а не значением объекта). [1]

В сноске 1 поясняется:

[1] На самом деле, вызов по ссылке на объект был бы лучшим описанием, поскольку, если передается изменяемый объект, вызывающий будет видеть любые изменения, которые вызываемый объект вносит в него (элементы, вставленные в список).

Это предназначено; Ссылочная семантика C ++ не работает, если у вас нет другой доступной семантики вызова, потому что нет очевидного способа отказаться, а это означает, что каждая переменная в огромной цепочке вызовов в конечном итоге ссылается на один и тот же объект, вызывая множество действий-на-a -расстояние.

python — хорошее применение для значений по умолчанию изменяемых аргументов функции?

В ответ на вопрос о том, как правильно использовать изменяемые значения аргументов по умолчанию, я предлагаю следующий пример:

Изменяемое значение по умолчанию может быть полезно для программирования простых в использовании, импортируемых команд, созданных вами.Изменяемый метод по умолчанию сводится к наличию частных статических переменных в функции, которую вы можете инициализировать при первом вызове (очень похоже на класс), но без необходимости прибегать к глобальным переменным, без использования оболочки и без необходимости создавать экземпляр объект класса, который был импортирован. Он по-своему элегантен, надеюсь, вы согласитесь.

Рассмотрим эти два примера:

  def dittle (cache = []):

    from time import sleep # Не требуется, за исключением примера.Список внутреннего кеша # dittle имеет следующий формат: cache [строка, счетчик]
    # Любой аргумент, переданный в dittle (), который нарушает этот формат, недействителен.
    # (Строка - это чистая память, но счетчик используется dittle.)

     # - Ловушка ошибок -
    если type (cache)! = list или cache! = [] and (len (cache) == 2 and type (cache [1])! = int):
        print ("Пользователь вызвал dittle (" + repr (cache) + "). \ n >> Предупреждение: dittle () не принимает аргументов, поэтому этот вызов игнорируется. \ n")
        возвращение

    # - Инициализировать функцию.(Выполняется только при первом вызове.) -
    если не кеш:
        print ("\ n cache =", кеш)
        print ("Инициализация частного изменяемого статического кеша. Запускается только при первом вызове!")
        cache.append («Привет, мир!»)
        cache.append (0)
        print ("cache =", cache, end = "\ n \ n")
    # -- Нормальная операция --
    cache [1] + = 1 # Статический счетчик циклов.
    outstr = "dittle () called" + str (cache [1]) + "times."
    если cache [1] == 1: outstr = outstr.replace ("s.", ".")
    печать (outstr)
    print ("Внутренний кеш содержит строку = '" + cache [0] + "'")
    Распечатать()
    если cache [1] == 3:
        print ("Давайте немного отдохнем.")
        sleep (2.0) # Поскольку мы импортировали его, мы можем использовать его.
        print ("Уф! Готово продолжить. \ n")
        сон (1.0)
    elif cache [1] == 4:
        cache [0] = "Хорошо быть живым!" # Давайте изменим личное сообщение.

# =================== ГЛАВНАЯ ======================
если __name__ == "__main__":

    for cnt in range (2): dittle () # Вызовы могут управляться циклом, но не обязательно.

    print ("Попытка передать список в dittle ()")
    dittle (["ПЛОХО", "Данные"])
    
    print ("Попытка передать не-список в dittle ()")
    dittle ("привет")
    
    print ("Обычный вызов dittle ().. ")
    dittle ()
    
    print ("Попытка установить частное изменяемое значение извне.")
    # Даже попытка инсайдера передать действительный формат будет принята
    # только для одного вызова, а затем сбрасывается, когда он гаснет
    # области. Он не может прервать нормальную работу.
    dittle ([«Я Гриффер! \ n (Обратите внимание, это изменение не сохранится!)», - 7])
    
    print ("Обычный вызов dittle () снова.")
    dittle ()
    dittle ()
  

Если вы запустите этот код, вы увидите, что функция dittle () интернализируется при самом первом вызове, но не при дополнительных вызовах, она использует частный статический кеш (изменяемый по умолчанию) для внутреннего статического хранилища между вызовами, отклоняет попытки захватить статическое хранилище, устойчив к злонамеренному вводу и может действовать в зависимости от динамических условий (здесь количество вызовов функции.)

Ключ к использованию изменяемых значений по умолчанию — не делать ничего, что будет переназначать переменную в памяти, а всегда менять переменную на месте.

Чтобы действительно увидеть потенциальную мощь и полезность этого метода, сохраните эту первую программу в вашем текущем каталоге под именем «DITTLE.py», затем запустите следующую программу. Он импортирует и использует нашу новую команду dittle (), не требуя запоминания каких-либо шагов или программирования обручей для перехода.

Вот наш второй пример.Скомпилируйте и запустите это как новую программу.

  от DITTLE import dittle

print ("\ n Мы эмулировали новую команду Python с помощью 'dittle ()'. \ n")
# Ничего не объявлять, нечего создавать, нечего запоминать.

dittle ()
dittle ()
dittle ()
dittle ()
dittle ()
  

Разве это не так гладко и чисто, насколько это возможно? Эти изменяемые значения по умолчанию действительно могут пригодиться.

Поразмыслив некоторое время над своим ответом, я не уверен, что сделал различие между использованием изменяемого метода по умолчанию и обычного способ сделать то же самое ясно.

Обычный способ — использовать импортируемую функцию, которая обертывает объект Class (и использует глобал). Итак, для сравнения, здесь метод на основе классов, который пытается делать то же самое, что и изменяемый метод по умолчанию.

  из времени импорта сна

класс dittle_class ():

    def __init __ (сам):
        
        self.b = 0
        self.a = "Привет, мир!"
        
        print ("\ n Инициализация объекта класса. Выполняется только при первом вызове.")
        print ("self.a = '" + str (self.a), "', self.b = ", self.b, end =" \ n \ n ")
    
    отчет def (сам):
        self.b = self.b + 1
        
        если self.b == 1:
            print ("Вызывается Диттл ()", self.b, "time.")
        еще:
            print ("Вызывается Диттл ()", self.b, "times.")
        
        если self.b == 5:
            self.a = "Как здорово быть живым!"
        
        print ("Внутренняя строка =", self.a, end = "\ n \ n")
            
        если self.b == 3:
            print ("Давайте немного отдохнем.")
            sleep (2.0) # Поскольку мы импортировали его, мы можем использовать его.print ("Уф! Готово продолжить. \ n")
            сон (1.0)

cl = dittle_class ()

def dittle ():
    глобальный cl
    
    если type (cl.a)! = str и type (cl.b)! = int:
        print ("Класс существует, но не имеет допустимого формата.")
        
    cl.report ()

# =================== ГЛАВНАЯ ======================
если __name__ == "__main__":
    print ("Мы эмулировали команду Python с помощью нашей собственной команды 'dittle ()'. \ n")
    for cnt in range (2): dittle () # Вызов может быть драйвером цикла, но не обязательно.print ("Попытка передать аргументы в dittle ()")
    try: # Пользователь должен поймать фатальную ошибку. Изменяемый пользователь по умолчанию этого не сделал.
        dittle (["ПЛОХО", "Данные"])
    Кроме:
        print ("Это вызвало фатальную ошибку, которую нельзя отловить в функции. \ n")
    
    print ("Обычный вызов dittle () ..")
    dittle ()
    
    print ("Попытка установить переменную Class извне.")
    cl.a = "Я горючее. Мой урон остается неизменным".
    cl.b = -7
    
    dittle ()
    dittle ()
  

Сохраните эту программу на основе классов в текущем каталоге как DITTLE.ру затем запустите следующий код (тот же, что и раньше).

  от DITTLE import dittle
# Ничего не объявлять, нечего создавать, нечего запоминать.

dittle ()
dittle ()
dittle ()
dittle ()
dittle ()
  

При сравнении этих двух методов преимущества использования изменяемого значения по умолчанию в функции должны быть более очевидными. Изменяемый метод по умолчанию не требует глобальных переменных, его внутренние переменные не могут быть установлены напрямую. И хотя изменяемый метод принимал переданный аргумент для одного цикла, а затем игнорировал его, метод Class был навсегда изменен, потому что его внутренняя переменная напрямую открыта извне.А какой метод проще программировать? Я думаю, это зависит от вашего уровня комфорта с методами и сложности ваших целей.

python — когда я помещаю список в функцию, список изменяется? Должен ли он оставаться таким же, поскольку параметры не являются глобальными?

  по умолчанию A (x):
    х = 10
    печать (х)

а = 2
А (а) # 10
print (a) # 2 a по-прежнему относится к тому же объекту


def B (x):
    х [0] = 1
    печать (х)

б = [0,0,0,0,0]
B (b) # [1, 0, 0, 0, 0]
print (b) # [1, 0, 0, 0, 0] b изменено!
  

Передача неизменяемых объектов

У нас есть переменная и , относящаяся к объекту со значением 2 .Когда мы передаем a в A (x) , функция имеет локальную переменную x , ссылающуюся на тот же объект. Поскольку целое число неизменяемое , по определению мы не можем изменять значение объекта до 10 на месте, все время переменная a продолжает ссылаться на объект со значением 2, что объясняет, почему значение a не изменить после звонка.

ПРИМЕЧАНИЕ: мы все еще можем «модифицировать» неизменяемые объекты, фиксируя возврат функции.

  по умолчанию A (x):
    х = 10
    возврат (х)

а = 2
а = А (а)
print (a) # 10 a теперь относится к новому объекту, созданному функцией
  

Назначив значение функции return для a, мы переназначили a для ссылки на новый объект со значением 10, созданным в функции. Обратите внимание, что объект, на который изначально ссылается a, никогда не изменяется — он по-прежнему равен 2 — но, имея указатель на новый объект, созданный функцией, мы можем «изменить» значение a.

Передача изменяемых объектов

Функция B (b) генерирует другой результат, когда мы передаем изменяемый объект.

Код b = [0,0,0,0,0] имеет переменную b , относящуюся к объекту списка, содержащему ссылки на три неизменяемых объекта: целые 0, 0, 0, 0 и 0.

Как обычно, когда мы передаем b в B () , функция имеет локальную переменную x , ссылающуюся на тот же объект, что и b . x [0] = 1 изменяет список на месте, поскольку список является изменяемым. Поскольку новый объект не создается и изменение произошло вместо объекта, когда мы печатаем b, мы получаем измененный список.

Tricky Python II: Передача параметров для изменяемых и неизменяемых объектов | Таня Крюкова

кредит: http://skillprogramming.com/top-rated/python-learning-tricks-959

В нашем последнем посте «Хитрый Python I» мы обсуждали, как Python управляет изменяемыми и неизменяемыми объектами в памяти. В этом посте мы сосредоточимся на том, как передача параметров работает в Python по сравнению с C, и исследуем, что это означает для изменяемых и неизменяемых объектов, которые мы передаем функциям.

Передача параметров: C против Python

Когда мы передаем переменную в C, функция присваивает значение параметра локальной переменной и выполняет с ней действия. Это означает, что функция резервирует область памяти с именем локальной переменной, а затем сохраняет копию значения параметра, переданного в этом пространстве памяти (« передается по значению »). Локальная переменная выходит из стека при возврате функции, следовательно, необходимы указатели, чтобы гарантировать, что изменения, внесенные в переменную функцией, сохраняются даже после выхода из функции (« передать по ссылке »).

Функции в Python также присваивают значение параметра локальной переменной, но назначение выглядит иначе. Вместо того, чтобы сохранять копию значения параметра в локальной переменной, Python просто указывает, что локальная переменная ссылается на значение. Напомним, что в Python все является объектом; это означает, что теперь локальная переменная указывает на объект — тот же объект , который является значением параметра, — который также , на который указывает переменная параметра. Другими словами, на объект значения параметра теперь могут ссылаться как локальные, так и параметрические переменные.Это похоже на передачу указателя в C, поскольку функция имеет прямой доступ к исходному объекту (а не только к локальной копии его значения) и может манипулировать им на месте.

Звучит просто, правда? Но все может быстро усложниться, если мы добавим концепцию изменяемых / неизменяемых объектов…

Передача неизменяемых объектов

Начнем с примера:

 >>> def increment (n): 
... n + = 1 >>> a = 3
>>> increment (a)
>>> print (a)
a = 3 # a по-прежнему ссылается на тот же объект

. Вам может быть интересно: могут ли функции в Python изменять значение на месте, тогда почему значение a остается неизменным? Давайте разберем это:

При a = 3 у нас есть переменная a , относящаяся к объекту со значением 3 :

Когда мы передаем a для увеличения (n), функция имеет локальную переменную n относится к тому же объекту:

Теперь самое интересное: n + = 1 .Поскольку целое число неизменяемо, по определению мы не можем изменить значение объекта на 4 на месте: , мы должны создать новый объект со значением 4. Мы можем визуализировать это, как показано ниже:

Все это время переменная a продолжает ссылаться на объект со значением 3, поскольку мы не меняли ссылку:

… что объясняет, почему значение a не изменяется после вызова increment () .

Означает ли это, что мы никогда не сможем манипулировать неизменяемыми объектами, передавая их функциям? Оказывается, мы все еще можем «модифицировать» неизменяемые объекты с помощью , захватив возвращаемый функцией.

 >>> def increment (n): 
... n + = 1
... return n >>> a = 3
>>> a = increment (a) # возвращаемое значение increment ( ) захвачен!
>>> print (a)
a = 4 # a теперь относится к новому объекту, созданному функцией

. Назначив возвращаемое значение функции a , мы переназначили a для ссылки на новый объект со значением 4, созданный в функции. Обратите внимание, что объект a, на который изначально ссылаются, никогда не изменяется — он по-прежнему равен 3 — но, имея a , указывающий на новый объект, созданный функцией, мы можем «изменить» значение a .

Передача изменяемых объектов

Та же функция increment () генерирует другой результат, когда мы передаем изменяемый объект:

 >>> def increment (n): 
... n.append ([4])> >> L = [1, 2, 3]
>>> инкремент (L)
>>> print (L)
L = [1, 2, 3, 4] # изменено!

Код L = [1, 2, 3] имеет переменную L , относящуюся к объекту списка, содержащему ссылки на три неизменяемых объекта: целые 1, 2 и 3.

Как обычно, когда мы передаем L в increment () , функция имеет локальную переменную n , ссылающуюся на тот же объект, что и L :

Метод .append () изменяет список на месте, поскольку список изменяемый:

Поскольку новый объект не создается и изменение произошло вместо объекта, когда мы печатаем L , мы получаем измененный список.

Давайте попробуем другой пример:

 >>> def assign_value (n, v): 
... n = v

>>> L1 = [1, 2, 3]
>>> L2 = [4, 5, 6]
>>> assign_value (L1, L2)
>>> print (L1)
[1, 2, 3]

Изначально списки выглядят так:

Когда мы передаем их в assign_value (n, v) , функция имеет n , v , см. L1 , L2 соответственно:

Однако, поскольку тело функции имеет n = v , это переназначает n для ссылки на то, к чему относится v (то есть L2):

В конце оба n, L2 и v обратитесь к списку [4, 5, 6] , а L1 относится к [1, 2, 3] .

На этом завершается наша серия Tricky Python . Я надеюсь, вам понравится это! Чтобы найти больше примеров, у Неда Батчелдера есть отличная статья по управлению памятью Python, которую я настоятельно рекомендую. Спасибо за чтение!

Вызов Python по ссылке или вызов по значению

Python использует систему, которая известна как «Вызов по ссылке на объект» или «Вызов по назначению». В случае, если вы передаете функции аргументы, такие как целые числа, строки или кортежи, передача аналогична вызову по значению, потому что вы не можете изменить значение неизменяемых объектов, передаваемых в функцию.В то время как передача изменяемых объектов может рассматриваться как вызов по ссылке, потому что, когда их значения изменяются внутри функции, это также будет отражаться за пределами функции.
Пример 1:

Python3

строка = «Вундеркинды»

def 8

def 8 9 тест (строка)

строка = "GeeksforGeeks"

печать ( "Внутренняя функция:" , строка)

тест (строка)

печать ( "Внешняя функция:" , строка)

Выход

 Внутренняя функция: GeeksforGeeks
Внешняя функция: Компьютерщики 

Пример 2

Python3

def add_more ( список ):

список append ( 50 )

print ( «Внутренняя функция» , список )

mylist = [ 10 , 20 , 30 , 40 ]

add_more (mylist)

print ( "Внешняя функция:" , mylist)

Выход

 Внутренняя функция [10, 20, 30, 40, 50]
Внешняя функция: [10, 20, 30, 40, 50] 



Привязка имен к объектам

В python каждая переменная, которой мы присваиваем значение / контейнер, рассматривается как объект.Когда мы присваиваем значение переменной, мы на самом деле привязываем имя к объекту .

Python3

a = «первый»

b = «первый»

печать ( (a))

print ( id (b))

print (a is b)

Выход

 110001234557894
110001234557894
True 

Теперь давайте попробуем разобраться в этом лучше на другом примере.
Пример 2:

Python3

a = [ 10 , 20 , 30 ]

b = [ 10 , 20 , 30 ]

печать ( id (a))

печать ( id (b))

print (a is b)

Выход

 5411536222
5411

737777 Ложь

Вывод двух приведенных выше примеров отличается, потому что список изменяемый , а строка неизменяемая .Неизменяемая переменная не может быть изменена после создания. Если мы хотим изменить неизменяемую переменную , например строку, мы должны создать новый экземпляр и привязать переменную к новому экземпляру. Принимая во внимание, что изменяемая переменная может быть изменена на месте.
Пример 3:

Python3

def foo (a):

7

a новое значение "

печать ( " Внутренняя функция: " , a)

строка = " старое значение "

foo (строка)

print ( «Внешняя функция:» , строка)

Вывод:

 Внутренняя функция: новое значение
Внешняя функция: старое значение 

В приведенном выше примере строка, которая представляет собой неизменяемый объект типа , передается в качестве аргумента функции foo.В рамках данной функции foo a = «новое значение» было привязано к тому же объекту, за пределами которого была привязана строка. В рамках функции foo мы изменяем «старое значение» на «новое значение». Как только мы выходим из области действия функции foo, a = «новое значение» больше не находится в пространстве имен, и значение, на которое ссылается строка, никогда не изменялось.
Пример 4: Теперь давайте посмотрим, как изменяемая переменная передается в функцию.

Python3

def foo (a):

a [ 0 ] = «Ничего»

9000 bar = [ 'Hi' , 'как' , 'равно' , 'you' , 'do' ]

foo (bar)

print (bar)

Вывод:

 ['Ничего,' как ',' ты ',' делаешь '] 

Когда мы передаем изменяемую переменную в функцию foo и изменяем ее на другое имя, функция foo все еще указывает на этот объект и продолжает указывать на этот объект во время своего выполнения.

Внимание компьютерщик! Укрепите свои основы с помощью курса Python Programming Foundation и изучите основы.

Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS . И чтобы начать свое путешествие по машинному обучению, присоединяйтесь к Машинное обучение - курс базового уровня


FAQ по программированию - документация Python 3.9.6

Есть ли отладчик на уровне исходного кода с точками останова, пошаговым режимом и т. Д.?

Да.

Несколько отладчиков для Python описаны ниже, а встроенная функция breakpoint () позволяет перейти к любому из них.

Модуль pdb - это простой, но адекватный отладчик консольного режима для Python. это часть стандартной библиотеки Python и документирована в библиотеке . Справочное руководство . Вы также можете написать свой собственный отладчик, используя код для pdb в качестве примера.

Интерактивная среда разработки IDLE, входящая в стандартную Дистрибутив Python (обычно доступный как Tools / scripts / idle) включает графический отладчик.

PythonWin - это среда разработки Python, которая включает отладчик графического интерфейса пользователя на основе pdb. В Отладчик PythonWin раскрашивает точки останова и имеет довольно много интересных функций, таких как отладка программ, отличных от PythonWin. PythonWin доступен как часть проект pywin32 и как часть Распространение ActivePython.

Eric - это IDE, построенная на PyQt и компонент редактирования Scintilla.

trepan3k - отладчик, подобный gdb.

Visual Studio Code - это IDE с отладкой инструменты, которые интегрируются с ПО для контроля версий.

Существует ряд коммерческих Python IDE, которые включают графические отладчики. В их числе:

Как я могу создать автономный двоичный файл из скрипта Python?

Вам не нужна возможность компилировать Python в код C, если все, что вам нужно, это автономная программа, которую пользователи могут загружать и запускать без установки сначала дистрибутив Python. Есть ряд инструментов, которые определяют набор модулей, необходимых для программы, и связать эти модули вместе с Бинарный файл Python для создания одного исполняемого файла.

Один - использовать инструмент замораживания, который включен в дерево исходных текстов Python как Инструменты / заморозка . Он преобразует байт-код Python в массивы C; компилятор C вы можете встроить все свои модули в новую программу, которая затем будет связана с стандартные модули Python.

Он работает путем рекурсивного сканирования исходного кода на предмет операторов импорта (в обоих forms) и ищем модули в стандартном пути Python, а также в исходный каталог (для встроенных модулей). Затем он превращает байт-код для модулей написано на Python в коде C (инициализаторы массивов, которые можно превратить в код объекты с помощью модуля маршала) и создает настраиваемый файл конфигурации, который содержит только те встроенные модули, которые фактически используются в программе.Это затем компилирует сгенерированный код C и связывает его с остальной частью Python интерпретатор для формирования автономного двоичного файла, который действует точно так же, как ваш скрипт.

Следующие пакеты могут помочь в создании консоли и графического интерфейса. исполняемые файлы:

Почему я получаю ошибку UnboundLocalError, когда переменная имеет значение?

Это может быть сюрпризом, если UnboundLocalError ранее работал код, когда он изменен путем добавления оператора присваивания где-нибудь в тело функции.

Этот код:

 >>> х = 10
>>> def bar ():
... печать (x)
>>> бар ()
10
 

работает, но этот код:

 >>> х = 10
>>> def foo ():
... печать (x)
... х + = 1
 

приводит к ошибке UnboundLocalError:

 >>> foo ()
Отслеживание (последний вызов последний):
  ...
UnboundLocalError: локальная переменная 'x', на которую ссылается перед присваиванием
 

Это связано с тем, что когда вы выполняете присвоение переменной в области видимости, это переменная становится локальной для этой области и затеняет любую переменную с аналогичным именем во внешнем объеме.Поскольку последний оператор в foo присваивает новое значение x , компилятор распознает его как локальную переменную. Следовательно, когда ранее print (x) пытается распечатать неинициализированную локальную переменную и возникает ошибка.

В приведенном выше примере вы можете получить доступ к переменной внешней области, объявив ее весь мир:

 >>> х = 10
>>> def foobar ():
... глобальный x
... печать (x)
... х + = 1
>>> foobar ()
10
 

Это явное заявление необходимо для того, чтобы напомнить вам, что (в отличие от внешне аналогичная ситуация с переменными класса и экземпляра) вы фактически изменяя значение переменной во внешней области:

Вы можете сделать то же самое во вложенной области, используя нелокальный ключевое слово:

 >>> def foo ():
... x = 10
... def bar ():
... нелокальный x
... печать (x)
... х + = 1
...    бар()
... печать (x)
>>> foo ()
10
11
 

Каковы правила для локальных и глобальных переменных в Python?

В Python переменные, которые упоминаются только внутри функции, неявно Глобальный. Если переменной присваивается значение в любом месте тела функции, предполагается, что он является локальным, если явно не объявлен как глобальный.

Поначалу это может показаться немного удивительным, но небольшое размышление объясняет это.На одной рукой, требуя global для присвоенных переменных, обеспечивает панель от непреднамеренных побочных эффектов. С другой стороны, если требуется global для всех глобальных ссылок вы всегда будете использовать global . У тебя было бы объявить глобальными каждую ссылку на встроенную функцию или компонент импортированный модуль. Этот беспорядок сводит на нет полезность global . объявление для выявления побочных эффектов.

Почему лямбда-выражения, определенные в цикле с разными значениями, возвращают один и тот же результат?

Предположим, вы используете цикл for для определения нескольких различных лямбда-выражений (или даже простых функции), e.г .:

 >>> квадраты = []
>>> для x в диапазоне (5):
... squares.append (лямбда: x ** 2)
 

Это дает вам список, содержащий 5 лямбд, которые вычисляют x ** 2 . Ты можно ожидать, что при вызове они вернут, соответственно, 0 , 1 , 4 , 9 и 16 . Однако, когда вы действительно попробуете, вы увидите, что все они возвращают 16 :

 >>> квадраты [2] ()
16
>>> квадраты [4] ()
16
 

Это происходит потому, что x не является локальным для лямбда-выражений, но определено в внешняя область видимости, и к ней обращаются, когда вызывается лямбда, а не когда она определено.В конце цикла значение x равно 4 , поэтому все теперь функции возвращают 4 ** 2 , то есть 16 . Вы также можете проверить это, измените значение x и посмотрите, как изменятся результаты лямбд:

 >>> х = 8
>>> квадраты [2] ()
64
 

Во избежание этого необходимо сохранить значения в переменных, локальных для лямбды, чтобы они не полагались на значение глобального x :

 >>> квадраты = []
>>> для x в диапазоне (5):
... squares.append (лямбда n = x: n ** 2)
 

Здесь n = x создает новую переменную n , локальную для лямбда-выражения, и вычисляет когда лямбда определена так, что она имеет то же значение, что и x в эта точка в цикле. Это означает, что значение n будет 0 в первой лямбде, 1 во второй, 2 в третьей и так далее. Поэтому каждая лямбда теперь будет возвращать правильный результат:

 >>> квадраты [2] ()
4
>>> квадраты [4] ()
16
 

Обратите внимание, что это поведение не свойственно лямбдам, но применяется к обычным функции тоже.

Как поделиться глобальными переменными между модулями?

Канонический способ обмена информацией между модулями в рамках одной программы - для создания специального модуля (часто называемого config или cfg). Просто импортируйте конфиг модуль во всех модулях вашего приложения; модуль затем становится доступным как глобальное имя. Поскольку существует только один экземпляр каждого модуля, любые изменения внесенные в объект модуля отражаются повсюду. Например:

config.py:

 x = 0 # Значение по умолчанию для параметра конфигурации 'x'
 

мод.py:

Конфигурация импорта
config.x = 1
 

main.py:

Конфигурация импорта
импорт мода
печать (config.x)
 

Обратите внимание, что использование модуля также является основой для реализации дизайна Singleton. узор по той же причине.

Каковы «лучшие практики» использования импорта в модуле?

Как правило, не используйте из импорта имени модуля * . Это загромождает пространство имен импортера, и линтерам намного сложнее обнаружить undefined имена.

Импортировать модули в начало файла. Так станет понятно, какие еще модули ваш код требует и позволяет избежать вопросов о том, входит ли имя модуля в область видимости. Использование одного импорта на строку упрощает добавление и удаление импорта модуля, но при использовании нескольких операций импорта на строку используется меньше места на экране.

Рекомендуется импортировать модули в следующем порядке:

  1. стандартных библиотечных модуля - например, sys , os , getopt , re

  2. сторонних библиотечных модулей (все, что установлено в пакетах сайтов Python справочник) - эл.г. mx.DateTime, ZODB, PIL.Image и т. д.

  3. модуля собственной разработки

Иногда необходимо переместить импорт в функцию или класс, чтобы избежать проблемы с циклическим импортом. Гордон Макмиллан говорит:

Циклический импорт подходит, если оба модуля используют форму «import ». импорта. Они терпят неудачу, когда 2-й модуль хочет вырвать имя из first («из имени импорта модуля»), а импорт - на верхнем уровне. Это потому что имена в 1-м еще недоступны, потому что первый модуль занят импортом 2-го.

В этом случае, если второй модуль используется только в одной функции, то импорт можно легко перенести в эту функцию. К моменту вызова импорта первый модуль завершит инициализацию, а второй модуль сможет выполнить свою Импортировать.

Также может потребоваться переместить импорт с верхнего уровня кода, если некоторые из модули зависят от платформы. В этом случае, возможно, даже не удастся импортировать все модули в верхней части файла. В этом случае импорт правильные модули в соответствующем программном коде - хороший вариант.

Перемещайте импорт только в локальную область, например внутри определения функции, если необходимо решить такую ​​проблему, как избежать циклического импорта или пытается сократить время инициализации модуля. Эта техника особенно полезно, если многие из импорта не нужны, в зависимости от того, как программа выполняется. Вы также можете переместить импорт в функцию, если модули используются только в этой функции. Обратите внимание, что при загрузке модуля первый раз может быть дорогим из-за однократной инициализации модуль, но загрузка модуля несколько раз практически бесплатна и стоит всего лишь пару поисков по словарю.Даже если имя модуля вышло за рамки, модуль, вероятно, доступен в sys.modules .

Почему значения по умолчанию разделяются между объектами?

Этот тип ошибок обычно укусывает начинающих программистов. Рассмотрим эту функцию:

 def foo (mydict = {}): # Опасность: общая ссылка на один dict для всех вызовов
    ... вычислить что-нибудь ...
    mydict [ключ] = значение
    вернуть mydict
 

При первом вызове этой функции mydict содержит единственный элемент.В во второй раз mydict содержит два элемента, потому что когда начинается foo () при выполнении mydict начинается с уже содержащегося в нем элемента.

Часто ожидается, что вызов функции создает новые объекты по умолчанию. значения. Это не то, что происходит. Значения по умолчанию создаются ровно один раз, когда функция определена. Если этот объект был изменен, как словарь в этом Например, последующие вызовы функции будут ссылаться на этот измененный объект.

По определению неизменяемые объекты, такие как числа, строки, кортежи и Нет , защищены от изменений.Изменения в изменяемых объектах, таких как словари, списки, и экземпляры классов могут привести к путанице.

Из-за этой функции рекомендуется не использовать изменяемые объекты как значения по умолчанию. Вместо этого используйте Нет в качестве значения по умолчанию и внутри функции проверьте, равен ли параметр Нет и создайте новый список / словарь / что угодно, если есть. Например, не пишите:

а:

 def foo (mydict = None):
    если mydict - Нет:
        mydict = {} # создать новый dict для локального пространства имен
 

Эта функция может быть полезной.Когда у вас есть функция, требующая много времени, вычислить, распространенным методом является кэширование параметров и результирующего значения каждого вызова функции, и вернуть кешированное значение, если то же значение попросил еще раз. Это называется «запоминанием» и может быть реализовано следующим образом:

 # Вызывающие могут предоставить только два параметра и опционально передать _cache по ключевому слову
def дорого (arg1, arg2, *, _cache = {}):
    если (arg1, arg2) в _cache:
        return _cache [(arg1, arg2)]

    # Рассчитать значение
    результат =... дорогое вычисление ...
    _cache [(arg1, arg2)] = result # Сохранить результат в кеше
    вернуть результат
 

Вместо значения по умолчанию можно использовать глобальную переменную, содержащую словарь. стоимость; это дело вкуса.

Как передать необязательные параметры или параметры ключевого слова из одной функции в другую?

Соберите аргументы, используя спецификаторы * и ** в функциях список параметров; это дает вам позиционные аргументы в виде кортежа и аргументы ключевого слова как словарь.Затем вы можете передать эти аргументы, когда вызов другой функции с использованием * и ** :

 def f (x, * args, ** kwargs):
    ...
    kwargs ['ширина'] = '14 .3c '
    ...
    g (x, * аргументы, ** kwargs)
 

В чем разница между аргументами и параметрами?

Параметры определяются именами, которые появляются в определение функции, а аргументы - это значения фактически передается функции при ее вызове. Параметры определяют, какие типы аргументы, которые функция может принимать.Например, учитывая определение функции:

 def func (foo, bar = None, ** kwargs):
    проходить
 

foo , bar и kwargs являются параметрами функции func . Однако при звонке func , например:

 func (42, bar = 314, extra = somevar)
 

значения 42 , 314 и somevar являются аргументами.

Почему при изменении списка «y» изменился и список «x»?

Если вы написали такой код:

 >>> x = []
>>> у = х
>>> у.добавить (10)
>>> у
[10]
>>> х
[10]
 

вам может быть интересно, почему добавление элемента к y изменило также x .

Есть два фактора, которые дают этот результат:

  1. Переменные - это просто имена, относящиеся к объектам. Выполнение y = x не создать копию списка - он создает новую переменную y , которая ссылается на тот же объект x относится к. Это означает, что есть только один объект (список), и к нему относятся как x , так и y .

  2. Списки изменяемы, что означает, что вы можете изменять их содержимое.

После вызова append () содержимое изменяемого объекта имеет изменено с [] на [10] . Поскольку обе переменные относятся к одному и тому же объект, используя любое имя, получает доступ к измененному значению [10] .

Если вместо этого мы назначим неизменяемому объекту x :

 >>> x = 5 # целые числа неизменяемы
>>> у = х
>>> x = x + 1 # 5 не может быть изменен, здесь мы создаем новый объект
>>> х
6
>>> у
5
 

мы видим, что в этом случае x и y больше не равны.Это потому что целые числа неизменяемы, и когда мы делаем x = x + 1 , мы не изменение int 5 путем увеличения его значения; вместо этого мы создаем новый объект (int 6 ) и присвоение ему значения x (то есть изменение объект x относится к). После этого назначения у нас есть два объекта (int 6 и 5 ) и две относящиеся к ним переменные ( x теперь относятся к 6 , но y все еще относится к 5 ).

Некоторые операции (например, y.append (10) и y.sort () ) изменяют объект, тогда как внешне похожие операции (например, y = y + [10] и sorted (y) ) создают новый объект. В целом в Python (и во всех случаях в стандартной библиотеке) метод, изменяющий объект, вернет Нет чтобы избежать путаницы между двумя типами операций. Итак, если вы по ошибке напишите y.sort () , думая, что это даст вам отсортированную копию y , вместо этого вы получите Нет , что, вероятно, приведет к тому, что ваша программа генерировать легко диагностируемую ошибку.

Однако есть один класс операций, в котором одна и та же операция иногда имеет разное поведение с разными типами: расширенное задание операторы. Например, + = изменяет списки, но не кортежи или целые числа ( a_list + = [1, 2, 3] эквивалентно a_list.extend ([1, 2, 3]) и изменяет a_list , тогда как some_tuple + = (1, 2, 3) и some_int + = 1 создают новые объекты).

Другими словами:

  • Если у нас есть изменяемый объект ( list , dict , set , и т.п.), мы можем использовать некоторые специальные операции, чтобы изменить его и все переменные которые относятся к нему, увидят изменение.

  • Если у нас есть неизменяемый объект ( str , int , tuple , и т. д.), все переменные, которые относятся к нему, всегда будут иметь одно и то же значение, но операции, которые преобразуют это значение в новое значение, всегда возвращают новое объект.

Если вы хотите знать, относятся ли две переменные к одному и тому же объекту или нет, вы можете используйте оператор is или встроенную функцию id () .

Как мне написать функцию с выходными параметрами (вызов по ссылке)?

Помните, что аргументы в Python передаются путем присваивания. С момента присвоения просто создает ссылки на объекты, нет псевдонима между именем аргумента в вызывающий и вызываемый, и поэтому никакого вызова по ссылке как такового. Вы можете добиться желаемый эффект несколькими способами.

  1. Возвращая кортеж результатов:

     >>> def func1 (a, b):
    ... a = 'new-value' # a и b - локальные имена
    ... b = b + 1 # назначается новым объектам
    ... return a, b # вернуть новые значения
    ...
    >>> x, y = 'старое значение', 99
    >>> func1 (x, y)
    ('новое значение', 100)
     

    Это почти всегда самое ясное решение.

  2. С использованием глобальных переменных. Это не является потокобезопасным и не рекомендуется.

  3. Путем передачи изменяемого (изменяемого на месте) объекта:

     >>> def func2 (a):
    ... a [0] = 'new-value' # 'a' ссылается на изменяемый список
    ... a [1] = a [1] + 1 # изменяет общий объект
    ...
    >>> args = ['старое значение', 99]
    >>> func2 (аргументы)
    >>> аргументы
    ['новое значение', 100]
     
  4. Путем передачи изменяемого словаря:

     >>> def func3 (аргументы):
    ... args ['a'] = 'new-value' # args - изменяемый словарь
    ... args ['b'] = args ['b'] + 1 # изменить его на месте
    ...
    >>> args = {'a': 'старое значение', 'b': 99}
    >>> func3 (аргументы)
    >>> аргументы
    {'a': 'новое значение', 'b': 100}
     
  5. Или объедините значения в экземпляр класса:

     >>> Пространство имен класса:
    ... def __init __ (self, /, ** args):
    ... для ключа значение в args.items ():
    ... setattr (сам, ключ, значение)
    ...
    >>> def func4 (аргументы):
    ... args.a = 'new-value' # args - изменяемое пространство имен
    ... args.b = args.b + 1 # изменить объект на месте
    ...
    >>> args = Пространство имен (a = 'старое значение', b = 99)
    >>> func4 (аргументы)
    >>> vars (аргументы)
    {'a': 'новое значение', 'b': 100}
     

    Практически никогда не бывает серьезных причин усложнять задачу.

Лучше всего вернуть кортеж, содержащий несколько результатов.

Как сделать в Python функцию высшего порядка?

У вас есть два варианта: вы можете использовать вложенные области или вы можете использовать вызываемые объекты. Например, предположим, что вы хотите определить linear (a, b) , который возвращает функция f (x) , которая вычисляет значение a * x + b . Использование вложенных областей:

 def linear (a, b):
    def результат (x):
        вернуть a * x + b
    вернуть результат
 

Или используя вызываемый объект:

 класс линейный:

    def __init __ (self, a, b):
        себя.a, self.b = a, b

    def __call __ (self, x):
        вернуть self.a * x + self.b
 

В обоих случаях

дает вызываемый объект, где налогов (10e6) == 0,3 * 10e6 + 2 .

Подход вызываемых объектов имеет тот недостаток, что он немного медленнее и приводит к немного более длинному коду. Однако обратите внимание, что набор вызываемых может передать свою подпись по наследству:

 класс экспоненциальный (линейный):
    # __init__ унаследовано
    def __call __ (self, x):
        вернуть себя.а * (х ** сам.б)
 

Объект может инкапсулировать состояние для нескольких методов:

Счетчик классов
:

    значение = 0

    def set (self, x):
        self.value = x

    def up (self):
        self.value = self.value + 1

    def down (self):
        self.value = self.value - 1

счетчик = счетчик ()
inc, dec, reset = count.up, count.down, count.set
 

Здесь inc () , dec () и reset () действуют как функции, которые разделяют та же счетная переменная.

Как мой код может узнать имя объекта?

Вообще говоря, не может, потому что у объектов на самом деле нет имен. По сути, присвоение всегда связывает имя со значением; то же самое верно и в отношении def и class , но в этом случае значение будет вызываемый. Рассмотрим следующий код:

 >>> класс A:
...     проходить
...
>>> B = A
>>> a = B ()
>>> б = а
>>> print (b)
<__ main __. Объект по адресу 0x16D07CC>
>>> print (а)
<__ main__.Объект по адресу 0x16D07CC>
 

Возможно, у класса есть имя: хотя он привязан к двум именам и вызывается через имя B созданный экземпляр по-прежнему сообщается как экземпляр class A. Однако невозможно сказать, является ли имя экземпляра a или b, поскольку оба имени привязаны к одному и тому же значению.

Вообще говоря, не обязательно, чтобы ваш код «знал имена» определенных ценностей. Если вы намеренно не пишете интроспективный программ, это обычно указывает на то, что изменение подхода может быть выгодный.

В comp.lang.python Фредрик Лунд однажды дал отличную аналогию в ответ на этот вопрос:

Так же, как вы получили имя той кошки, которую нашли у себя на крыльце: кошка (объект) сам по себе не может сказать вам свое имя, и ему все равно, поэтому единственный способ узнать, как это называется, - спросить всех своих соседей (пространства имен), если это их кот (объект)…

… .и не удивляйтесь, если вы обнаружите, что он известен под разными именами, или вообще без имени!

Что случилось с приоритетом оператора запятой?

Запятая не является оператором в Python.Рассмотрим этот сеанс:

 >>> "а" в "б", "а"
(Ложь, 'а')
 

Поскольку запятая является не оператором, а разделителем между выражениями, выше оценивается, как если бы вы ввели:

не:

То же самое верно и для различных операторов присваивания ( = , + = и т. Д.). Они на самом деле не операторы, а синтаксические ограничители в операторах присваивания.

Существует ли эквивалент тернарного оператора C «?:»?

Да, есть.Синтаксис следующий:

 [on_true] if [выражение] else [on_false]

х, у = 50, 25
small = x, если x 

До того, как этот синтаксис был представлен в Python 2.5, распространенной идиомой было использование логические операторы:

 [выражение] и [on_true] или [on_false]
 

Однако эта идиома небезопасна, поскольку может дать неверные результаты, если on_true имеет ложное логическое значение. Поэтому всегда лучше использовать форма ... if ... else ... .

Можно ли писать запутанные однострочные строки в Python?

Да. Обычно это делается путем вложения лямбда в Лямбда . См. Следующие три примера, принадлежащие Ульфу Бартельту:

 из functools import reduce

# Простые числа <1000
print (list (filter (None, map (lambda y: y * reduce (lambda x, y: x * y! = 0,
map (лямбда x, y = y: y% x, диапазон (2, int (pow (y, 0.5) +1))), 1), диапазон (2,1000)))))

# Первые 10 чисел Фибоначчи
print (list (map (lambda x, f = lambda x, f: (f (x-1, f) + f (x-2, f)) if x> 1 else 1:
f (x, f), диапазон (10))))

# Набор Мандельброта
print ((lambda Ru, Ro, Iu, Io, IM, Sx, Sy: reduce (lambda x, y: x + y, map (lambda y,
Iu = Iu, Io = Io, Ru = Ru, Ro = Ro, Sy = Sy, L = лямбда yc, Iu = Iu, Io = Io, Ru = Ru, Ro = Ro, i = IM,
Sx = Sx, Sy = Sy: reduce (lambda x, y: x + y, map (lambda x, xc = Ru, yc = yc, Ru = Ru, Ro = Ro,
i = i, Sx = Sx, F = лямбда xc, yc, x, y, k, f = lambda xc, yc, x, y, k, f: (k <= 0) или (x * x + y * у
> = 4.0) или 1 + f (xc, yc, x * xy * y + xc, 2.0 * x * y + yc, k-1, f): f (xc, yc, x, y, k, f): chr (
64 + F (Ru + x * (Ro-Ru) / Sx, yc, 0,0, i)), диапазон (Sx))): L (Iu + y * (Io-Iu) / Sy), диапазон ( Sy
)))) (- 2,1, 0,7, -1,2, 1,2, 30, 80, 24))
# \ ___ ___ / \ ___ ___ / | | | __ строк на экране
# V V | | ______ столбцов на экране
# | | | __________ максимум «итераций»
# | | _________________ диапазон по оси y
# | ____________________________ диапазон по оси x
 

Не пробуйте это дома, детки!

Что означает косая черта (/) в списке параметров функции?

Косая черта в списке аргументов функции означает, что параметры до это только позиционное.Только позиционные параметры - это параметры без внешне используемое имя. При вызове функции, которая принимает только позиционные параметры, аргументы сопоставляются с параметрами исключительно на основе их положения. Например, divmod () - это функция, которая принимает только позиционные параметры. Его документация выглядит так:

 >>> справка (divmod)
Справка по встроенной функции divmod во встроенных модулях:

divmod (х, у, /)
    Вернуть кортеж (x // y, x% y). Инвариант: div * y + mod == x.

Косая черта в конце списка параметров означает, что оба параметра только позиционный. Таким образом, вызов divmod () с аргументами ключевого слова приведет к к ошибке:

 >>> divmod (x = 3, y = 4)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: divmod () не принимает аргументов ключевого слова
 

Как указать шестнадцатеричные и восьмеричные целые числа?

Чтобы указать восьмеричную цифру, поставьте перед восьмеричным значением ноль, а затем нижний или заглавная «о».Например, чтобы установить для переменной «a» восьмеричное значение «10» (8 в десятичной системе), введите:

В шестнадцатеричной системе счисления так же просто. Просто поставьте перед шестнадцатеричным числом ноль, а затем букву «x» в нижнем или верхнем регистре. Шестнадцатеричные цифры можно указывать в нижнем регистре. или в верхнем регистре. Например, в интерпретаторе Python:

 >>> a = 0xa5
>>> а
165
>>> b = 0XB2
>>> б
178
 

Почему -22 // 10 возвращает -3?

Это в первую очередь вызвано желанием, чтобы i% j имели тот же знак, что и j .Если вы этого хотите, а также хотите:

 я == (я // j) * j + (я% j)
 

, то целочисленное деление должно вернуть пол. C также требует, чтобы это удостоверение удерживайте, а затем компиляторы, которые усекают i // j , должны заставить i% j иметь тот же знак, что и i .

Существует несколько реальных вариантов использования i% j , когда значение j отрицательно. Когда j положительный, их много, и практически во всех из них он более полезен для i% j должно быть > = 0 .Если часы показывают 10 сейчас, что они говорят 200 часов тому назад? -190% 12 == 2 полезно; -190% 12 == -10 - это ошибка, ожидающая кусать.

Как преобразовать строку в число?

Для целых чисел используйте встроенный конструктор типа int () , например интервал ('144') == 144 . Точно так же float () преобразуется в числа с плавающей запятой, например с плавающей запятой ('144') == 144.0 .

По умолчанию они интерпретируют число как десятичное, так что int ('0144') == 144 верно, а int ('0x144') вызывает ValueError . int (строка, base) принимает базу для преобразования в качестве второго необязательного аргумента, поэтому int ( '0x144', 16) == 324 . Если база указана как 0, число интерпретируется используя правила Python: ведущий «0o» указывает на восьмеричное, а «0x» - на шестнадцатеричный номер.

Не используйте встроенную функцию eval () , если все, что вам нужно, это преобразовать строки в числа. eval () будет значительно медленнее и представляет угроза безопасности: кто-то может передать вам выражение Python, которое может иметь нежелательные побочные эффекты.Например, кто-то мог пройти __import __ ('os'). System ("rm -rf $ HOME") , который сотрет ваш дом каталог.

eval () также имеет эффект интерпретации чисел как выражений Python, так что, например, eval ('09 ') дает синтаксическую ошибку, потому что Python не позволяет ведущий «0» в десятичном числе (кроме «0»).

Как изменить строку на месте?

Вы не можете, потому что строки неизменяемы. В большинстве ситуаций вам следует просто создайте новую строку из различных частей, которые вы хотите собрать это из.Однако, если вам нужен объект с возможностью изменения на месте данные Unicode, попробуйте использовать объект io.StringIO или массив модуль:

 >>> import io
>>> s = "Привет, мир"
>>> sio = io.StringIO (s)
>>> sio.getvalue ()
'Привет мир'
>>> sio.seek (7)
7
>>> sio.write («туда!»)
6
>>> sio.getvalue ()
'Привет!'

>>> импортный массив
>>> a = array.array ('u', s)
>>> print (а)
array ('u', 'Привет, мир')
>>> а [0] = 'у'
>>> print (а)
array ('u', 'yello, world')
>>> а.туникод ()
'yello, world'
 

Как использовать строки для вызова функций / методов?

Существуют разные техники.

  • Лучше всего использовать словарь, который отображает строки в функции. Главная Преимущество этого метода в том, что строки не должны совпадать с именами функций. Это также основной метод, используемый для имитации дела. построить:

     def a ():
        проходить
    
    def b ():
        проходить
    
    dispatch = {'go': a, 'stop': b} # Обратите внимание на отсутствие скобок для функций
    
    dispatch [get_input ()] () # Обратите внимание на конечные скобки для вызова функции
     
  • Используйте встроенную функцию getattr () :

     import foo
    getattr (фу, 'бар') ()
     

    Обратите внимание, что getattr () работает с любым объектом, включая классы, класс экземпляры, модули и так далее.

    Используется в нескольких местах стандартной библиотеки, например:

     класс Foo:
        def do_foo (сам):
            ...
    
        def do_bar (сам):
            ...
    
    f = getattr (foo_instance, 'do_' + имя операции)
    f ()
     
  • Используйте locals () для разрешения имени функции:

     def myFunc ():
        print ("привет")
    
    fname = "myFunc"
    
    f = locals () [fname]
    f ()
     

Есть ли аналог Perl chomp () для удаления завершающих символов новой строки из строк?

Вы можете использовать S.rstrip ("\ r \ n") , чтобы удалить все вхождения любой строки терминатор с конца строки S без удаления других завершающих пробел. Если строка S представляет более одной строки, с несколькими пустые строки в конце, терминаторы для всех пустых строк будут удалено:

 >>> lines = ("строка 1 \ r \ n"
... "\ r \ n"
... "\ r \ n")
>>> lines.rstrip ("\ n \ r")
'линия 1 '
 

Так как это обычно требуется только при чтении текста по одной строке за раз, используйте С.rstrip () этот способ работает хорошо.

Существует ли эквивалент scanf () или sscanf ()?

Не как таковой.

Для простого синтаксического анализа ввода самый простой подход - обычно разбить строку на слова, разделенные пробелами, с использованием метода split () строковых объектов а затем преобразовать десятичные строки в числовые значения с помощью int () или поплавок () . split () поддерживает дополнительный полезный параметр «sep». если в строке используется что-то кроме пробелов в качестве разделителя.

Для более сложного синтаксического анализа ввода более эффективны регулярные выражения. чем C sscanf () и лучше подходит для этой задачи.

Как преобразовать кортежи в списки?

Конструктор типа tuple (seq) преобразует любую последовательность (фактически, любую iterable) в кортеж с теми же элементами в том же порядке.

Например, кортеж ([1, 2, 3]) дает (1, 2, 3) и кортеж ('abc') дает ('a', 'b', 'c') .Если аргумент является кортежем, он не делает копию но возвращает тот же объект, поэтому вызов tuple () , когда вы не уверены, что объект уже является кортежем.

Конструктор типа list (seq) преобразует любую последовательность или итерацию в список с теми же предметами в том же порядке. Например, list ((1, 2, 3)) возвращает [1, 2, 3] и list ('abc') дает ['a', 'b', 'c'] . Если аргумент является списком, он создает копию точно так же, как seq [:] .

Что такое отрицательный индекс?

последовательности Python индексируются положительными и отрицательными числами. Для положительные числа 0 - это первый индекс, 1 - второй индекс и так далее. Для отрицательные индексы -1 - последний индекс, -2 - предпоследний (предпоследний) index и так далее. Представьте seq [-n] как то же самое, что и seq [len (seq) -n] .

Использование отрицательных индексов может быть очень удобным. Например, S [: - 1] - это все строка, за исключением ее последнего символа, который полезен для удаления завершающий символ новой строки из строки.

Как удалить дубликаты из списка?

См. В Поваренной книге Python подробное обсуждение многих способов сделать это:

Если вы не против переупорядочить список, отсортируйте его, а затем отсканируйте с конца список, удаляя дубликаты по ходу:

, если мой список:
    mylist.sort ()
    last = mylist [-1]
    для i в диапазоне (len (mylist) -2, -1, -1):
        if last == mylist [i]:
            del mylist [я]
        еще:
            last = mylist [i]
 

Если все элементы списка могут использоваться как ключи набора (т.е. они все hashable) это часто быстрее

 mylist = список (набор (мой список))
 

Преобразует список в набор, тем самым удаляя дубликаты, а затем обратно в список.

Как удалить несколько элементов из списка

Как и при удалении дубликатов, явная итерация в обратном порядке с условие удаления - одна из возможностей. Однако так проще и быстрее использовать замену среза с неявной или явной итерацией вперед. Вот три варианта.:

 mylist [:] = фильтр (keep_function, mylist)
mylist [:] = (x вместо x в моем списке, если keep_condition)
mylist [:] = [x вместо x в моем списке, если keep_condition]
 

Понимание списка может быть самым быстрым.

Как создать массив в Python?

Используйте список:

 ["это", 1, "есть", "an", "массив"]
 

Списки эквивалентны массивам C или Pascal по своей временной сложности; Главная разница в том, что список Python может содержать объекты самых разных типов.

Модуль array также предоставляет методы для создания массивов фиксированных типов. с компактными представлениями, но они индексируются медленнее, чем списки. Также обратите внимание, что числовые расширения и другие определяют структуры, подобные массиву, с также различные характеристики.

Чтобы получить связанные списки в стиле Lisp, вы можете эмулировать cons-ячейки с помощью кортежей:

 lisp_list = ("нравится", ("это", ("пример", Нет)))
 

Если требуется изменчивость, вы можете использовать списки вместо кортежей.Здесь аналог машины lisp - lisp_list [0] а аналог cdr - lisp_list [1] . Делайте это только в том случае, если уверены, что вам это действительно нужно, потому что это обычно намного медленнее, чем при использовании списков Python.

Как создать многомерный список?

Вы, наверное, пробовали сделать многомерный массив вот так:

Выглядит правильно, если распечатать:

 >>> А
[[Нет, Нет], [Нет, Нет], [Нет, Нет]]
 

Но когда вы присваиваете значение, оно появляется в нескольких местах:

 >>> A [0] [0] = 5
>>> А
[[5, Нет], [5, Нет], [5, Нет]]
 

Причина в том, что репликация списка с * не создает копии, а только создает ссылки на существующие объекты. * 3 создает список содержащий 3 ссылки на один и тот же список длиной два. Изменения в одной строке будут показывать во всех строках, что почти наверняка не то, что вам нужно.

Предлагаемый подход состоит в том, чтобы сначала создать список желаемой длины, а затем заполните каждый элемент вновь созданным списком:

 A = [Нет] * 3
для i в диапазоне (3):
    A [i] = [Нет] * 2
 

Это генерирует список, содержащий 3 разных списка длиной два. Вы также можете используйте понимание списка:

 Вт, в = 2, 3
A = [[Нет] * w для i в диапазоне (h)]
 

Или вы можете использовать расширение, которое предоставляет тип данных матрица; NumPy - самый известный.

Почему a_tuple [i] + = [‘item’] вызывает исключение, когда добавление работает?

Это связано с тем, что расширенное присваивание операторы присваивания операторов, и разница между изменяемыми и неизменяемые объекты в Python.

Это обсуждение применяется в целом, когда операторы расширенного присваивания применяется к элементам кортежа, указывающим на изменяемые объекты, но мы будем использовать список и + = в качестве нашего образца.

Если вы написали:

 >>> a_tuple = (1, 2)
>>> a_tuple [0] + = 1
Отслеживание (последний вызов последний):
   ...
TypeError: объект 'tuple' не поддерживает назначение элементов
 

Причина исключения должна быть понятна сразу: 1 добавляется в объект a_tuple [0] указывает на ( 1 ), создавая объект результата, 2 , но когда мы пытаемся присвоить результат вычисления 2 элементу 0 кортежа, мы получаем ошибку, потому что не можем изменить элемент кортеж указывает на.

Под обложками то, что делает этот оператор расширенного присваивания, примерно это:

 >>> result = a_tuple [0] + 1
>>> a_tuple [0] = результат
Отслеживание (последний вызов последний):
  ...
TypeError: объект 'tuple' не поддерживает назначение элементов
 

Ошибка - это присваивающая часть операции, которая вызывает ошибку. кортеж неизменен.

Когда вы пишете что-то вроде:

 >>> a_tuple = (['фу'], 'бар')
>>> a_tuple [0] + = ['элемент']
Отслеживание (последний вызов последний):
  ...
TypeError: объект 'tuple' не поддерживает назначение элементов
 

Исключение несколько удивительнее, и еще более удивительным является тот факт, что что даже несмотря на то, что произошла ошибка, приложение работало:

 >>> a_tuple [0]
['фу', 'элемент']
 

Чтобы понять, почему это происходит, вам нужно знать, что (а) если объект реализует __iadd__ магический метод, он вызывается при расширенном назначении + = выполняется, и его возвращаемое значение используется в операторе присваивания; и (б) для списков __iadd__ эквивалентно вызову , расширьте в списке. и возврат списка.Вот почему мы говорим, что для списков + = является «Стенография» для list.extend :

 >>> a_list = []
>>> a_list + = [1]
>>> a_list
[1]
 

Это эквивалент:

 >>> result = a_list .__ iadd __ ([1])
>>> a_list = результат
 

Объект, на который указывает a_list, был изменен, и указатель на Мутировавший объект снова присваивается a_list . Конечный результат присвоение не выполняется, поскольку это указатель на тот же объект, что и a_list ранее указывал на, но присвоение все еще происходит.

Таким образом, в нашем примере с кортежем то, что происходит, эквивалентно:

 >>> result = a_tuple [0] .__ iadd __ (['элемент'])
>>> a_tuple [0] = результат
Отслеживание (последний вызов последний):
  ...
TypeError: объект 'tuple' не поддерживает назначение элементов
 

__iadd__ преуспевает, и, таким образом, список расширяется, но даже если результат указывает на тот же объект, на который уже указывает a_tuple [0] , это последнее присвоение по-прежнему приводит к ошибке, потому что кортежи неизменяемы.

Как отсортировать один список по значениям из другого списка?

Объедините их в итератор кортежей, отсортируйте полученный список, а затем выберите из нужного вам элемента.

 >>> list1 = ["что", "я", "сортировка", "по"]
>>> list2 = ["что-то", "еще", "в", "сортировать"]
>>> пары = zip (список1, список2)
>>> пары = отсортированные (пары)
>>> пары
[("Я", "еще"), ("по", "сортировать"), ("сортировка", "по"), ("что", "что-то")]
>>> result = [x [1] для x в парах]
>>> результат
['else', 'sort', 'to', 'что-то']
 

Что такое класс?

Класс - это особый тип объекта, созданный при выполнении оператора класса.Объекты класса используются в качестве шаблонов для создания экземпляров объектов, которые воплощают как данные (атрибуты), так и код (методы), относящиеся к типу данных.

Класс может быть основан на одном или нескольких других классах, называемых его базовым классом (ами). Это затем наследует атрибуты и методы своих базовых классов. Это позволяет объектная модель, которая будет последовательно уточняться путем наследования. У вас может быть общий класс Mailbox , который предоставляет базовые методы доступа для почтового ящика, и подклассы, такие как MboxMailbox , MaildirMailbox , OutlookMailbox которые обрабатывают различные специфические форматы почтовых ящиков.

Что такое метод?

Метод - это функция некоторого объекта x , который вы обычно вызываете как x.name (аргументы ...) . Методы определяются как функции внутри класса определение:

 класс C:
    def meth (self, arg):
        вернуть arg * 2 + self.attribute
 

Как проверить, является ли объект экземпляром данного класса или его подклассом?

Используйте встроенную функцию isinstance (obj, cls) . Вы можете проверить, есть ли у объекта является экземпляром любого из нескольких классов, предоставляя кортеж вместо одноклассник, эл.г. isinstance (obj, (class1, class2, ...)) , а также может проверьте, является ли объект одним из встроенных типов Python, например isinstance (obj, str) или isinstance (obj, (int, float, complex)) .

Обратите внимание, что isinstance () также проверяет виртуальное наследование от абстрактный базовый класс. Итак, тест вернет True для зарегистрированный класс, даже если он прямо или косвенно не унаследовал от него. К тест на «истинное наследование», просканируйте MRO класса:

 из коллекций.abc import Mapping

класс P:
     проходить

класс C (P):
    проходить

Mapping.register (P)
 
 >>> c = C ()
>>> isinstance (c, C) # прямой
Истинный
>>> isinstance (c, P) # косвенный
Истинный
>>> isinstance (c, Mapping) # виртуальный
Истинный

# Актуальная цепочка наследования
>>> введите (c) .__ mro__
(<класс 'C'>, <класс 'P'>, <класс 'объект'>)

# Тест на "истинное наследование"
>>> Отображение в типе (c) .__ mro__
Ложь
 

Обратите внимание, что большинство программ не используют isinstance () в пользовательских классах. очень часто.Если вы сами разрабатываете классы, более подходящий объектно-ориентированный стиль заключается в определении методов в классах, которые инкапсулируют конкретное поведение, вместо проверки класса объекта и выполнения разные вещи в зависимости от того, к какому классу это относится. Например, если у вас есть функция что-то делает:

 def поиск (объект):
    если isinstance (obj, Mailbox):
        ... # код для поиска в почтовом ящике
    elif isinstance (объект, документ):
        ... # код для поиска в документе
    Элиф...
 

Лучшим подходом является определение метода search () для всех классов и просто позвони:

Почтовый ящик класса
:
    def search (self):
        ... # код для поиска в почтовом ящике

класс Document:
    def search (self):
        ... # код для поиска в документе

obj.search ()
 

Что такое делегирование?

Делегирование - это объектно-ориентированный метод (также называемый шаблоном проектирования). Допустим, у вас есть объект размером x , и вы хотите изменить поведение только одного его методов.Вы можете создать новый класс, который предоставляет новую реализацию метода, который вы хотите изменить, и делегирует все остальные методы соответствующий метод x .

Программисты

Python могут легко реализовать делегирование. Например, следующие class реализует класс, который ведет себя как файл, но преобразует все записанные данные в верхний регистр:

 класс UpperOut:

    def __init __ (self, outfile):
        self._outfile = outfile

    def write (self, s):
        себя._outfile.write (s.upper ())

    def __getattr __ (я, имя):
        вернуть getattr (self._outfile, имя)
 

Здесь класс UpperOut переопределяет метод write () для преобразования строку аргумента в верхний регистр перед вызовом базового self._outfile.write () метод. Все остальные методы делегированы базовый объект self._outfile . Делегирование осуществляется через __getattr__ метод; обратитесь к справочнику по языку для получения дополнительной информации об управлении доступом к атрибутам.

Обратите внимание, что в более общих случаях делегирование может стать сложнее. Когда атрибуты должен быть установлен, а также извлечен, класс должен определять __setattr __ () метод тоже, и он должен делать это осторожно. Базовая реализация __setattr __ () примерно эквивалентно следующему:

 класс X:
    ...
    def __setattr __ (я, имя, значение):
        self .__ dict __ [имя] = значение
    ...
 

Большинство реализаций __setattr __ () должны модифицировать self.__dict__ хранить локальное состояние для себя, не вызывая бесконечной рекурсии.

Как вызвать метод, определенный в базовом классе, из производного класса, который его переопределяет?

Используйте встроенную функцию super () :

 класс, производный (базовый):
    def meth (сам):
        super (производное, собственное) .meth ()
 

Для версии до 3.0 вы можете использовать классические классы: Для класса определение, такое как class Derived (Base): ... вы можете вызвать метод meth () определяется в Base (или одном из базовых классов Base ) как Base.мет (я, Аргументы ...) . Здесь Base.meth - это несвязанный метод, поэтому вам нужно предоставить аргумент self .

Как я могу организовать свой код, чтобы упростить изменение базового класса?

Вы можете назначить базовый класс псевдониму и унаследовать его от псевдонима. Тогда все необходимо изменить значение, присвоенное псевдониму. Между прочим, этот трюк также удобен, если вы хотите принимать решения динамически (например, в зависимости от наличия ресурсов), какой базовый класс использовать.Пример:

 класс Base:
    ...

BaseAlias ​​= База

класс Derived (BaseAlias):
    ...
 

Как создать данные статического класса и методы статического класса?

Поддерживаются как статические данные, так и статические методы (в смысле C ++ или Java). в Python.

Для статических данных просто определите атрибут класса. Чтобы присвоить новое значение атрибут, вы должны явно использовать имя класса в назначении:

 класс C:
    count = 0 # количество раз C.__init__ называется

    def __init __ (сам):
        C.count = C.count + 1

    def getcount (self):
        вернуть C.count # или вернуть self.count
 

c.count также относится к C.count для любого c , так что isinstance (c, C) удерживается, если не отменено самим c или каким-либо классом базового класса путь поиска от c .__ class__ до C .

Осторожно: в методе языка C присваивание типа self.count = 42 создает новый и несвязанный экземпляр с именем «count» в собственном dict self . Переплет имя статических данных класса всегда должно указывать класс, будь то внутри метода или нет:

Возможны статические методы:

 класс C:
    @staticmethod
    def static (arg1, arg2, arg3):
        # Нет параметра "self"!
        ...
 

Однако гораздо более простой способ получить эффект статического метода - это через простую функцию на уровне модуля:

 def getcount ():
    вернуть C.считать
 

Если ваш код структурирован так, чтобы определить один класс (или тесно связанный класс иерархия) на модуль, это обеспечивает желаемую инкапсуляцию.

Как я могу перегрузить конструкторы (или методы) в Python?

Этот ответ действительно применим ко всем методам, но обычно возникает вопрос сначала в контексте конструкторов.

В C ++ вы должны написать

 класс C {
    C () {cout << "Нет аргументов \ n"; }
    C (int i) {cout << "Аргумент:" << i << "\ n"; }
}
 

В Python вам нужно написать единственный конструктор, который ловит все случаи, используя аргументы по умолчанию.Например:

 класс C:
    def __init __ (self, i = None):
        если я Нет:
            print ("Без аргументов")
        еще:
            print ("Аргумент равен", i)
 

Это не полностью эквивалентно, но на практике достаточно близко.

Вы также можете попробовать список аргументов переменной длины, например

 def __init __ (self, * args):
    ...
 

Тот же подход работает для всех определений методов.

Я пытаюсь использовать __spam и получаю сообщение об ошибке _SomeClassName__spam.

Имена переменных с двойным подчеркиванием в начале «искажены» для упрощения но эффективный способ определения частных переменных класса. Любой идентификатор формы __spam (минимум два символа подчеркивания в начале и не более одного символа подчеркивания в конце) текстуально заменяется на _classname__spam , где имя класса - это имя текущего класса без начальных подчеркиваний.

Это не гарантирует конфиденциальность: посторонний пользователь по-прежнему может преднамеренно получить доступ атрибут «_classname__spam», а частные значения видны в __dict__ .Многие программисты Python никогда не утруждают себя использованием закрытых переменных. имена вообще.

Мой класс определяет __del__, но он не вызывается, когда я удаляю объект.

Для этого есть несколько возможных причин.

Оператор del не обязательно вызывает __del __ () - это просто уменьшает счетчик ссылок объекта, и если он достигает нуля __del __ () вызывается.

Если ваши структуры данных содержат циклические ссылки (например, дерево, в котором каждый дочерний элемент имеет родительская ссылка, и у каждого родителя есть список дочерних элементов) количество ссылок никогда не вернется к нулю.Время от времени Python запускает алгоритм для обнаружения таких циклов, но сборщик мусора может запускаться через некоторое время после последнего ссылка на вашу структуру данных исчезает, поэтому ваш метод __del __ () может быть позвонили в неудобное и случайное время. Это неудобно, если вы пытаетесь воспроизвести проблему. Хуже того, порядок, в котором объект __del __ () методы выполняются произвольно. Вы можете запустить gc.collect () , чтобы коллекции, но - это патологических случаев, когда предметы никогда не будут собраны.

Несмотря на сборщик циклов, все же неплохо определить явный close () для объектов, которые будут вызываться всякий раз, когда вы с ними закончите. В Затем метод close () может удалить атрибуты, относящиеся к подобъектам. Не вызовите __del __ () напрямую - __del __ () должен вызвать close () и close () должен убедиться, что он может вызываться более одного раза для одного и того же объект.

Другой способ избежать циклических ссылок - использовать модуль weakref , что позволяет указывать на объекты без увеличения их счетчика ссылок.Например, древовидные структуры данных должны использовать слабые ссылки для своих родительских и ссылки на братьев и сестер (если они им нужны!).

Наконец, если ваш метод __del __ () вызывает исключение, предупреждающее сообщение печатается на sys.stderr .

Почему результат

id () кажется не уникальным?

Встроенная функция id () возвращает целое число, которое гарантированно будет уникальным в течение время жизни объекта. Поскольку в CPython это память объекта адреса, часто бывает, что после удаления объекта из памяти следующий только что созданный объект размещается в той же позиции в памяти.Этот иллюстрируется этим примером:

 >>> id (1000)
13
2 >>> id (2000) 13
2

Два идентификатора принадлежат разным целочисленным объектам, созданным ранее, и удаляется сразу после выполнения вызова id () . Чтобы убедиться, что объекты, идентификатор которых вы хотите изучить, все еще живы, создайте еще одну ссылку до объекта:

 >>> а = 1000; b = 2000
>>> id (а)
13
2 >>> id (b) 138
 

Когда я могу положиться на тесты идентификации с оператором

is ?

Оператор - проверяет идентичность объекта.Тест a is b is эквивалент id (a) == id (b) .

Самым важным свойством проверки идентичности является то, что объект всегда идентично самому себе, a - это , всегда возвращает True . Идентификационные тесты обычно быстрее, чем тесты на равенство. И в отличие от тестов на равенство, тесты идентичности гарантированно возвращают логическое значение True или False .

Тем не менее, проверки идентичности могут быть заменены проверками на равенство только , когда идентичность объекта гарантируется.Как правило, есть три обстоятельства, когда идентичность гарантирована:

1) Назначения создают новые имена, но не изменяют идентичность объекта. После присвоение новый = старый , гарантируется, что новый - старый .

2) Помещение объекта в контейнер, в котором хранятся ссылки на объекты, не изменить идентичность объекта. После присвоения списка s [0] = x , это гарантировано, что s [0] - это x .

3) Если объект синглтон, это означает, что только один экземпляр этого объекта может существовать.После присвоений a = Нет и b = Нет , это гарантировано, что a - это b , потому что None одноэлементный.

В большинстве других обстоятельств тесты идентичности нецелесообразны, а тесты на равенство являются предпочтительными. В частности, не следует использовать тесты личности для проверки такие константы, как int и str , которые не гарантируются одиночные:

 >>> а = 1000
>>> b = 500
>>> c = b + 500
>>> а есть с
Ложь

>>> a = 'Python'
>>> b = 'Py'
>>> c = b + 'тон'
>>> а есть с
Ложь
 

Аналогичным образом, новые экземпляры изменяемых контейнеров никогда не идентичны:

 >>> a = []
>>> b = []
>>> а это б
Ложь
 

В коде стандартной библиотеки вы увидите несколько общих шаблонов для правильно используя тесты личности:

1) В соответствии с рекомендациями PEP 8 , идентификационный тест является предпочтительным способом проверки для Нет .Это читается как простой английский в коде и позволяет избежать путаницы с другие объекты, которые могут иметь логические значения, которые оцениваются как ложные.

2) Обнаружение необязательных аргументов может быть непростым, если Нет является допустимым входом стоимость. В таких ситуациях вы можете создать одноэлементный дозорный объект. гарантированно отличаться от других объектов. Например, вот как реализовать метод, который ведет себя как dict.pop () :

 _sentinel = объект ()

def pop (self, key, default = _sentinel):
    если ввести self:
        значение = сам [ключ]
        дель сам [ключ]
        возвращаемое значение
    если по умолчанию _sentinel:
        поднять KeyError (ключ)
    вернуть по умолчанию
 

3) В реализациях контейнеров иногда требуется дополнять тесты на равенство с помощью тесты личности.Это предохраняет код от путаницы с такими объектами, как float ('NaN') , которые не равны сами себе.

Например, вот реализация collections.abc.Sequence .__ содержит __ () :

 def __contains __ (self, value):
    для v в себе:
        если v - значение или v == значение:
            вернуть True
    вернуть ложь
 

Как создать файл .pyc?

Когда модуль импортируется впервые (или когда исходный файл изменено с момента создания текущего скомпилированного файла) a .pyc файл, содержащий скомпилированный код должен быть создан в подкаталоге __pycache__ каталога каталог, содержащий файл .py . Файл .pyc будет иметь имя файла, которое начинается с того же имени, что и файл .py , и заканчивается на .pyc , со средним компонентом, который зависит от конкретного python двоичный файл, который его создал. (Подробнее см. PEP 3147 .)

Одна из причин, по которой файл .pyc не может быть создан, - это проблема с разрешениями. с каталогом, содержащим исходный файл, что означает, что __pycache__ подкаталог не может быть создан.Это может произойти, например, если вы разрабатываете как один пользователь, но запускается от имени другого, например, если вы тестируете с помощью веб-сервера.

Если не установлена ​​переменная среды PYTHONDONTWRITEBYTECODE , создание файла .pyc происходит автоматически, если вы импортируете модуль и Python имеет возможность (разрешения, свободное пространство и т. д.) для создания __pycache__ подкаталог и запишите скомпилированный модуль в этот подкаталог.

Запуск Python на скрипте верхнего уровня не считается импортом и не .pyc будет создан. Например, если у вас есть модуль верхнего уровня foo.py , который импортирует другой модуль xyz.py , когда вы запускаете foo (by набрав python foo.py в качестве команды оболочки), будет создан .pyc для xyz , потому что xyz импортирован, но файл .pyc не будет создан для foo , поскольку foo.py не импортируется.

Если вам нужно создать файл .pyc для foo , то есть создать .pyc для модуля, который не импортирован - вы можете, используя py_compile и компилируют все модули .

Модуль py_compile может вручную скомпилировать любой модуль. Один из способов - использовать функция compile () в этом модуле интерактивно:

 >>> импортировать py_compile
>>> py_compile.compile ('foo.py')
 

Это приведет к записи .pyc в подкаталог __pycache__ в том же расположение как foo.py (или вы можете переопределить это с помощью необязательного параметра , файл ).

Вы также можете автоматически компилировать все файлы в каталоге или каталогах, используя модуль compileall . Вы можете сделать это из командной строки, запустив compileall.py и указание пути к каталогу, содержащему файлы Python для компиляции:

Как узнать текущее имя модуля?

Модуль может узнать свое собственное имя модуля, посмотрев на предопределенный глобальный переменная __name__ .Если это значение '__main__' , программа работает как скрипт. Многие модули, которые обычно используются, также импортируя их предоставить интерфейс командной строки или самопроверку и выполнять только этот код после проверки __name__ :

 def main ():
    print ('Выполняется тест ...')
    ...

если __name__ == '__main__':
    основной()
 

Как мне получить модули, которые взаимно импортируют друг друга?

Предположим, у вас есть следующие модули:

foo.py:

 из бара импорта bar_var
foo_var = 1
 

бар.py:

 из foo import foo_var
bar_var = 2
 

Проблема в том, что интерпретатор выполнит следующие шаги:

  • основной импорт foo

  • Создаются пустые глобальные объекты для foo

  • foo компилируется и начинает выполнение

  • foo импорт бар

  • Создаются пустые глобалы для бара

  • bar компилируется и начинает выполняться

  • bar импортирует foo (что невозможно, поскольку уже существует модуль с именем foo)

  • бар.foo_var = foo.foo_var

Последний шаг завершился неудачно, потому что Python еще не завершил интерпретацию foo и глобальный словарь символов для foo все еще пуст.

То же самое происходит, когда вы используете import foo , а затем пытаетесь получить доступ foo.foo_var в глобальном коде.

Есть (как минимум) три возможных решения этой проблемы.

Гвидо ван Россум рекомендует избегать любого использования из импорта ... , и размещение всего кода внутри функций. Инициализации глобальных переменных и переменные класса должны использовать только константы или встроенные функции. Это означает все из импортированного модуля обозначается как <модуль>. <имя> .

Джим Роскинд предлагает выполнить шаги в следующем порядке в каждом модуле:

  • экспорта (глобальные объекты, функции и классы, которым не требуется импортированная база классов)

  • импорт выписки

  • активный код (включая глобальные переменные, которые инициализируются из импортированных значений).

ван Россуму не очень нравится такой подход, потому что импорт появляется в странное место, но оно работает.

Маттиас Урлихс рекомендует реструктурировать код так, чтобы рекурсивный импорт в первую очередь не нужно.

Эти решения не исключают друг друга.

Когда я редактирую импортированный модуль и повторно импортирую его, изменения не отображаются. Почему это происходит?

Из соображений эффективности и согласованности Python только читает модуль файл при первом импорте модуля.Если этого не произошло, в программе состоящий из множества модулей, каждый из которых импортирует один и тот же базовый модуль, базовый модуль будет анализироваться и повторно анализироваться много раз. Чтобы заставить перечитать измененный модуль, сделайте так:

 импорт importlib
импортировать имя мода
importlib.reload (имя мода)
 

Предупреждение: этот метод не на 100% надежен. В частности, модули содержащие утверждения типа

 из имени мода import some_objects
 

продолжит работу со старой версией импортированных объектов.Если модуль содержит определения классов, существующие экземпляры классов будут , а не . обновлен для использования нового определения класса. Это может привести к следующему парадоксальное поведение:

 >>> импорт importlib
>>> import cls
>>> c = cls.C () # Создать экземпляр C
>>> importlib.reload (cls)
<модуль cls из cls.py>
>>> isinstance (c, cls.C) # isinstance is false?!?
Ложь
 

Суть проблемы станет ясной, если вы распечатаете «идентичность» объекты класса:

 >>> шестнадцатеричный (id (c.__учебный класс__))
'0x7352a0'
>>> шестнадцатеричный (идентификатор (cls.C))
'0x4198d0'
 
.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *