Авторы фреймворка советуют описаться на базовый класс:
Продолжить чтение
Категория "Программирование":
Screen Manager
kivy.uix.screenmanage
kivy.app.App
class kivy.app.App(**kwargs)
Базовый класс kivy.event.EventDispatcher
.
Класс приложения. События:
- on_start — Запускается при запуске приложения (перед вызовом
runTouchApp()
) - on_stop — Происходит, когда приложение останавливается
- on_pause — Происходит, когда операционная система останавливает (дословно — ставит на паузу) выполнение приложения
- on_resume — Срабатывает, когда приложение возобновляется с паузы ОС. Будьте осторожны: у вас нет гарантии, что это событие будет запущено после вызова события on_pause
Примечание: добавлен в версии 1.7.0 параметр kv_file.
Методы и атрибуты:
build() — Инициализирует приложение; оно будет вызвано только один раз. Если этот метод возвращает виджет (дерево), он будет использоваться в качестве корневого виджета и добавлен в окно. Возвращает экземпляр корневого виджета, если не задан self.root
.
build_config(config) — Этот метод вызывается до инициализации приложения для создания объекта ConfigParser. Здесь вы можете поместить любой раздел / ключ / значение по умолчанию для вашей конфигурации. Если что-то установлено, конфигурация будет автоматически сохранена в файле, возвращенном get_application_config().
build_settings(settings) — Этот метод вызывается, когда пользователь (или вы) хотите показать параметры приложения. Он вызывается один раз при первом открытии панели настроек, после чего панель кэшируется. Он может быть вызван снова, если панель кэшированных настроек удаляется destroy_settings().
Вы можете использовать этот метод для добавления панелей настроек и настройки виджета настроек, например, путем изменения ширины боковой панели. Аргумент — экземпляр объекта Settings для добавления на панель
close_settings(*largs) — закрывает ранее открытую панель настроек. Вернет True, если панель будет закрыта.
config = None — Возвращает экземпляр ConfigParser для конфигурации приложения. Это можно использовать для запроса некоторых токенов конфигурации в методе build()
create_settings() — Создает панель настроек. Этот метод обычно вызывается только один раз за время жизни приложения, и результат кэшируется внутри, но он может быть вызван снова, если кэшированная панель удаляется через destroy_settings()
.
По умолчанию он построит панель настроек в соответствии с settings_cls
, вызовет build_settings()
, добавит панель Kivy, если use_kivy_settings
имеет значение True
, и свяжет с on_close
/on_config_change
.
Если вы хотите подключить свой собственный способ выполнения настроек, без панели Kivy или событий закрытия/изменения конфигурации, это метод, который вы хотите перегрузить.
display_settings(settings) — Откройте панель настроек. По умолчанию панель отображается непосредственно в верхней части окна. Вы можете определить другое поведение, переопределив этот метод, например, добавив его в ScreenManager или Popup.
Вы должны вернуть True, если отображение успешно, в противном случае False. Аргумент settings вы можете изменить для отображения.
get_application_config(defaultpath=’%(appdir)s/%(appname)s.ini’) — Возвращает имя файла конфигурации приложения. В зависимости от платформы, файл приложения будет храниться в разных местах:
- на iOS: <appdir>/Documents/.<appname>.ini
- на Android: <user_data_dir>/.<appname>.ini
- на других: <appdir>/<appname>.ini
При распространении приложения на настольных компьютерах обратите внимание, что если приложение предназначено для установки на всей системе, пользователь может не иметь доступа на запись в каталог приложения. Если вы хотите сохранить пользовательские настройки, следует перегрузить этот метод и изменить поведение по умолчанию, чтобы сохранить файл конфигурации в каталоге пользователя.
class TestApp(App): def get_application_config(self): return super(TestApp, self).get_application_config( '~/.%(appname)s.ini')
Шпаргалки:
- The tilda ‘~’ will be expanded to the user directory.
- %(appdir)s will be replaced with the application
directory
- %(appname)s will be replaced with the application
name
get_application_icon() — вернет иконку приложения
get_application_name() — вернет имя программы
static get_running_app() — вернет экземпляр текущего запущенного приложения
icon — иконка (логотип) текущего приложения. Значок может быть расположен в том же каталоге, что и ваш основной файл. Вы можете установить это следующим образом:
class MyApp(App): def build(self): self.icon = 'myicon.png'
Рекомендуется не меньше, чем 256х256 либо 1024х1024
kv_directory — Путь к каталогу, в котором хранится приложение kv, по умолчанию равен None. Если задан каталог kv_directory, он будет использоваться для получения исходного файла kv. По умолчанию предполагается, что файл находится в том же каталоге, что и текущий файл определения приложения (см метод load_kv).
kv_file — Имя файла Kv для загрузки, по умолчанию нет. Если kv_file установлен, он будет загружен при запуске приложения. Загрузка файла kv «по умолчанию» будет предотвращена.
load_config() — (внутренний) эта функция возвращает ConfigParser с конфигурацией приложения. Она делает 3 вещи:
- Создание экземпляра ConfigParser
- Загрузка конфигурации по умолчанию путем вызова
build_config()
, затем - Если он существует, он загружает файл конфигурации приложения, в противном случае он создает его.
Возвращает: экземпляр ConfigParser
load_kv(filename=None) — Этот метод вызывается при первом запуске приложения, если дерево виджетов не было создано ранее для этого приложения. Затем этот метод ищет соответствующий файл kv в том же каталоге, что и файл, содержащий класс приложения.
Например, скажем, у вас есть файл с именем main.py что содержит:
class ShowcaseApp(App): pass
Этот метод будет искать файл с именем showcase.kv в каталоге, который содержит main.py. имя файла kv должно быть строчным именем класса, без постфикса » App » В конце, если он существует.
Вы можете определить правила и корневой виджет в своем файле kv:
<ClassName>: # this is a rule ... ClassName: # this is a root widget ...
Должен быть только один корневой виджет. Для получения дополнительной информации читайте документацию по языку kivy. Если ваш файл kv содержит корневой виджет, он будет использоваться как self.корень, корневой виджет для приложения.
name — вернет имя приложения, основанное на имени класса приложения.
on_config_change(config, section, key, value) — выполняется, когда маркер конфигурации был изменен на странице настроек.
open_settings(*largs)— открывает панель настроек приложения. Она будет создан в самый первый раз или воссоздана, если ранее кэшированная панель была удалена destroy_settings()
. Панель настроек будет отображаться с помощью метода display_settings (), который по умолчанию добавляет панель настроек в окно, прикрепленное к вашему приложению. Вы должны переопределить этот метод, если вы хотите отобразить панель настроек по-другому. True вернет, если настройки будут открыты.
root = None — Корневой виджет, возвращаемый методом build() или методом load_kv (), если файл kv содержит корневой виджет.
root_window — Возвращает корневой экземпляр окна, используемый run()
.
run() — запускает приложение в единственном экземпляре (синглтон)
settings_cls — Класс, используемый для построения панели настроек и экземпляра, передаваемого в build_config(). Вы должны использовать либо настройки, либо один из предоставленных подклассов с различными макетами (настройки с боковой панелью, SettingsWithSpinner, SettingsWithTabbedPanel, SettingsWithNoMenu). Вы также можете создать свой собственный подкласс настроек. Дополнительную информацию см. В документации по настройкам.
settings_cls является ObjectProperty и по умолчанию настройки с Spinner, который отображает панели настроек с spinner для переключения между ними. Если вы зададите строку, фабрика будет использоваться для разрешения класса.
stop(*largs) — останавливает приложение. Если вы используете этот метод, все приложение остановится, выполнив вызов stopTouchApp()
.
title — Заголовок приложения, с которым можно работать так:
class MyApp(App): def build(self): self.title = 'Hello world'
use_kivy_settings
= True — Если True, то настройки приложения также будут включать настройки Kivy.
Если вы не хотите, чтобы пользователь изменял какие-либо настройки kivy из вашего пользовательского интерфейса
настроек, измените это на False.
user_data_dir — Возвращает путь к каталогу в файловой системе пользователей, который приложение может использовать для хранения дополнительных данных.
Различные платформы имеют различные соглашения в отношении того, где пользователь может хранить данные, такие как предпочтения, сохраненные игры и настройки. Эта функция реализует эти соглашения. Каталог <имя_приложения > создается при вызове свойства, если оно еще не существует.
В iOS возвращается ~/Documents / <app_name> (который находится внутри песочницы приложения).
В Windows возвращается %APPDATA% / <имя_приложения>.
В OS X возвращается ~/Library/Application Support / <app_name>.
В Linux возвращается $XDG_CONFIG_HOME/<app_name>.
На Android, Контекст.Возвращается GetFilesDir.
Kivy Base
Этот модуль содержит основные функциональные возможности Kivy и не предназначен для конечных пользователей. Не стесняйтесь просматривать его, но имейте в виду, что вызов любого из этих методов напрямую может привести к непредсказуемому поведению, поскольку вызовы напрямую обращаются к циклу событий приложения.
API
kivy.base.runTouchApp(widget=None, slave=False)
Статическая основная функция, которая запускает цикл приложения. Вы можете получить доступ к некоторой магии с помощью следующих аргументов:
- <empty> — для выполнения диспетчерской работы необходим хотя бы один прослушиватель (например, окно) ввода. Если его нет, то программа завершится. (MTWindow работают как раз как прослушиватели ввода)
- widget — Если вы передадите только виджет, будет создано окно, и ваш виджет будет добавлен в окно в качестве корневого виджета.
- slave — отправка встроенных событий не совершается. Вам необходимо написать ее самостоятельно.
- widget + slave — отправка встроенных событий не совершается. Вам необходимо написать ее самостоятельно, ,но программа постарается получить окно (должно быть создано вами заранее) и добавить виджет к нему. Очень полезно для встраивания Kivy в другой инструментарий. (как и Qt, проверьте kivy-designed)
kivy.base.stopTouchApp()
Останавливает текущее приложение, выходя из основного цикла событий.
ScrollView
Модуль: kivy.uix.scrollview
Added in 1.0.4
Элемент ScrollView
обеспечивает прокрутку для возможности просмотра области, выходящей за его пределы.
ScrollView принимает только один дочерний элемент и применяет к нему область просмотра в соответствии со свойствами scroll_x
и scroll_y
. Прикосновения анализируются, чтобы определить, хочет ли пользователь прокручивать или управлять дочерним элементом каким-либо другим способом: вы не можете делать и то, и то одновременно. Чтобы определить, является ли взаимодействие жестом прокрутки, используются следующие свойства:
scroll_distance
: минимальное расстояние для перемещения, по умолчанию 20 пикселейscroll_timeout
: максимальный период времени, по умолчанию 55 миллисекунд
Если касание перемещает пиксели scroll_distance
в течение периода scroll_timeout
, оно распознается как жест прокрутки, и начнется перевод (прокрутка/панорамирование). Если тайм-аут происходит, событие касания вниз отправляется дочернему элементу.
Значение по умолчанию для этих параметров можно изменить в файле конфигурации:
[widgets] scroll_timeout = 250 scroll_distance = 20
Начиная с версии 1.1.1, ScrollView
теперь анимирует прокрутку в Y при использовании колесика мыши.
Ограничение прокрутки по оси X или Y:
По умолчанию ScrollView позволяет прокручивать как по оси X, так и по оси Y. Вы можете явно отключить прокрутку по оси, установив свойства do_scroll_x
или do_scroll_y
в значение False
.
Управление размером и положением контента:
ScrollView управляет положением своих дочерних элементов аналогично RelativeLayout, но не использует size_hint
. Вы должны тщательно указать размер вашего контента, чтобы получить желаемый эффект прокрутки/панорамирования.
По умолчанию size_hint
равен (1, 1)
, поэтому размер содержимого будет точно соответствовать вашему ScrollView (вам нечего будет прокручивать). Для включения прокрутки необходимо деактивировать хотя бы одну из инструкций size_hint
(x или y) дочернего элемента. Установка значения size_hint_mine
равным None также позволит выполнить прокрутку для этого измерения, если размер ScrollView меньше минимального размера.
Чтобы прокрутить GridLayout по его оси Y / вертикали, установите ширину дочернего элемента в ширину ScrollView (size_hint_x=1
) и установите свойство size_hint_y
равным None
:
from kivy.uix.gridlayout import GridLayout from kivy.uix.button import Button from kivy.uix.scrollview import ScrollView from kivy.core.window import Window from kivy.app import runTouchApp layout = GridLayout(cols=1, spacing=10, size_hint_y=None) # убеждаемся, что высота такая, что есть место для прокрутки: layout.bind(minimum_height=layout.setter('height')) for i in range(100): btn = Button(text=str(i), size_hint_y=None, height=40) layout.add_widget(btn) root = ScrollView(size_hint=(1, None), size=(Window.width, Window.height)) root.add_widget(layout) runTouchApp(root)
Аналогичный пример kv-language:
ScrollView: do_scroll_x: False do_scroll_y: True Label: size_hint_y: None height: self.texture_size[1] text_size: self.width padding: 10, 10 text: 'really some amazing text\n' * 100
Описание API класса ScrollView:
- class
kivy.uix.scrollview.
ScrollView
(**kwargs)
События:
- on_scroll_start — генерирует событие, когда прокрутка начинается с касания
- on_scroll_move — генерирует событие во время прокрутки
- on_scroll_stop — генерирует событие, когда прокрутка остановлена касанием
Каждое из этих событий принимает аргумент touch типа MotionEvent и возвращает булево значение. Аргумент touch содержит координаты касания в родительской системе координат. Возвращаемое значение в случае True остановит отправку события касания, False — продолжит.
Методы и атрибуты:
- add_widget(widget, index=0)
- Метод в неизменном виде унаследован от Widget и добавляет новый виджет как дочерний элемент в наш ScrollView. Параметры:
- widget:
Widget
- виджет для добавления
- index:
int
, по умолчанию 0 - Индекс для вставки виджета в список. Обратите внимание, что значение по умолчанию 0 означает, что виджет вставляется в начале списка и, таким образом, будет отображаться поверх других родственных виджетов.
- canvas:
str
, по умолчанию None - Добавлен в версии 1.9.0. — объект
Canvas
для добавления холста для виджета. Может иметь значения ‘before’, ‘after’ или None. (последнее является значением по умолчанию)
- widget:
- bar_width=2
- Устанавливает ширину скроллбара вертикальной/горизонтальной прокрутки. Ширина для горизонтального понимается как его высота. Является NumericProperty и по умолчанию имеет значение 2
- remove_widget(widget)
- Удаляет виджет из списка дочерних элементов ScrollView
- scroll_distance=20
- NumericProperty. Задает расстояние для перемещения перед прокруткой ScrollView, в пикселях. Как только расстояние будет пройдено, ScrollView начнет прокручиваться, и никакое событие касания не перейдет к дочерним элементам. Желательно, чтобы вы основывали это значение на dpi экрана вашего целевого устройства
- scroll_timeout=55
- Тайм-аут, разрешенный для запуска scroll_distance, в миллисекундах. Если пользователь не переместил scroll_distance в течение таймаута, прокрутка будет отключена, и событие касания перейдет к дочерним элементам.
- scroll_to(widget, padding=10, animate=True)
- Прокручивает видовой экран, чтобы убедиться, что данный виджет виден, при необходимости с дополнением и анимацией. Если animate имеет значение True (по умолчанию), то будут использоваться параметры анимации по умолчанию. В противном случае это должен быть дикт, содержащий аргументы для передачи конструктору анимации.
- scroll_type=[‘content’]
- OptionProperty. Задает тип прокрутки, используемый для содержимого scrollview. Доступные опции: [‘content‘], [’bars‘], [’bars‘,’content’]. [‘content’] означает, что содержимое прокручивается путем перетаскивания или прокрутки содержимого напрямую, [‘bars’] — прокрутки скроллбара, [’bars‘,’content’] — оба варианта..
- scroll_x=0
- NumericProperty. X значение прокрутки, между 0 и 1. Если 0, то левая сторона содержимого будет касаться левой стороны ScrollView. Если 1, правая сторона содержимого будет касаться правой стороны.
- scroll_y=0
- NumericProperty. То же самое, но для Y ординат
- smooth_scroll_end=None
- Следует ли использовать плавный конец прокрутки при прокрутке колесиком мыши и коэффициент преобразования расстояния прокрутки в скорость. Эта опция также включает значение добавления скорости, если вы прокручиваете больше, вы будете прокручивать быстрее и дальше. Рекомендуемое значение-10. Скорость рассчитывается как scroll_wheel_distance * smooth_scroll_end.
- to_local(x, y, **k)
- Преобразование родительских координат в локальные координаты. Измените значение на True, если вы хотите перевести координаты в относительные координаты виджета.
- to_parent(x, y, **k)
- Преобразование локальных координат в родительские координаты. Измените значение на True, если вы хотите перевести координаты в относительные координаты родителя.
- update_from_scroll(*largs)
- Провоцирует перемещение содержания контента в соответствии с текущим значением scroll_x и scroll_your.
Этот метод подобно событию автоматически вызывается при изменении одного из свойств scroll_x, scroll_y, pos или size или при изменении размера содержимого. - vbar
- Возвращает кортеж (pos, size) вертикальной полосы прокрутки. Положение и размер являются дробным числом между 0-1 и представляют собой процент от текущей высоты прокрутки. Это свойство используется внутренне для рисования небольшой вертикальной полосы при прокрутке. Только для чтения
- viewport_size
- (внутренний) размер внутреннего видового экрана. Это размер вашего единственного дочернего элемента в scrollview.
Англоязычный источник тут. Исходники тут. На момент написания статьи недоступны без vpn.
Си-строки и массивы C++
Если вы пришли в мир C++ из других миров со статической типизацией, то первое, что необходимо себе уяснить, что массивы в C++ — это не просто тип, это семейство типов. В этой статье постараемся наиболее полно охватить понятие си-массивов. И для большей наглядности рассмотрим работу с массивами на примере c-style строк, которые представляют собой простые символьные массивы.
Поскольку это статья рассчитана больше на начинающих, то начнем с самого начала, а именно с объявления и инициализации их:
Объявление:
Строки в си стиле — они же массивы типа char — можно объявить разными способами.
Способ 1:
Явно задать размерность:
char a2[7] = "a1";
— таким образом мы объявили и инициализировали массив размерностью 7 байт; первые три байта будут заполнены заданными в коде программе символами
'a'
и '1'
и символом конца с-строки '\0'
. И у нас остается про запас 4 символа с неинициализированными значениями, которые могут иметь любые значения*.
Способ 2:
Мы можем не задавать размер массива явно:
char a1[] = "a1234";
— таким образом автоматически будет создан массив размерностью 6 байт, заполненный 5-ю заданными символами + 1 символом конца строки.
Лирическое отступление:
В обоих случаях для строк будет выделена память в куче, которая будет аннулирована после того, как функция, в которой они объявлены, не завершит свою работу. Для иллюстрации вышесказанного рассмотрим следующий код:
#include <iostream> using namespace std; void ViewArray(char* arr){ cout<<endl<< "ViewArray:" << endl; int i=0; while(arr[i]!='\0'){ cout << arr[i++] << endl ; } cout << (int)*(arr+i) << endl ; cout<< endl; } char* CreateArray(){ char a1[7] = "a11111"; cout << "Created:" << &a1; return (char*)&a1; } int main(int argc, char** argv) { char a2[7] = "a11111"; ViewArray(a2); char* c= CreateArray(); ViewArray(c); }
Здесь мы объявили функцию ViewArray, которая посимвольно выводит в консоль содержание любой си-строки, переданной ей в качестве параметра. Обращу ваше внимание, что в C++ нельзя просто так передать значение голого массива по значению в функцию, но об этом чуть позже.
Помимо ViewArray мы так же объявили функцию CreateArray, которая инициализирует строку-массив `a11111` и возвращает указатель на него.
В функции main мы так же создаем строку-массив `a11111`, а так же записываем результат выполнения CreateArray в переменную c
и выводим их обе на экран через ViewArray.
—
И как видите, получаем несколько странный результат. Дело в том, что после завершения выполнения CreateArray память, выделенная на стэке, уничтожается перестает быть валидной и может быть перезаписана другими значениями, а может — и нет. В C/C++ это называется UB (undefined behavior) — неопределенное поведение.
Как же это преодолеть?
Чтобы вернуть массив из функции, необходимо выделить для него память в куче. Для этого перепишем нашу функцию CreateArray таким образом:
char* CreateArray(){ char *a1 = new char[7]{'a','1','1','1','1','1','\0'}; return a1; }
Здесь внутри CreateArray мы выделяем в куче память размером 7 байт и посимвольно заполняем ее. Обратите внимание на последний элемент a1[6]='\0';
— это символ признака конца строки. В случае такой инициализации его следует задать явно. На выходе мы получим точно такую же строку, как и при инициализации a11111
.
К сожалению, в C++ нет способа инициализировать память в куче с си-строкой через обычную строку, как на стеке. Согласитесь, что такая посимвольная инициализация массива все-таки менее удобна, нежели стековая:
char a1[] = "a11111";
Но другого способа нет: если вы хотите заполнить строку в куче без перечисления каждого символа в отдельной кавычке, можно, например, скопировать си-строку со стека и вернуть ее:
char a2[7] = "a11111"; char *a1 = new char[7]; return (char*)memcpy (a1, a2, sizeof(a2));
Хотя этот код будет несколько избыточен, он позволяет работать с обычной строкой для заполнения си-строк в куче.
Думаю, с undefined behavior на стеке мы разобрались. Это было лирическое отступление, и мы переходим к следующему способу:
Способ 3:
char* a2 = "a11111";
На данный момент такой способ не поддерживается стандартом. Но мы не можем его пропустить, поскольку именно его, как правило, используют новички, не понимая, что происходит после его компиляции. Тем более, что их код в большинстве случаев не работает, как нужно.
В целом, я бы не сказал, что этот подход неправильный, он скорее нерекомендуемый. Но если вы знаете что делаете, то… Дело в том, что undefined behavior для C++ в целом, может быть вполне себе defined для конкретного компилятора под конкретную платформу. И вышеприведенная строчка кода будет скомпилирована большинством компиляторов, которые мне известны, но, но как правило, с предупреждениями.
Если вникать в подробности, несмотря на схожее поведение с предыдущими способами инициализации, этот работает совсем не так: для большинства известных компиляторов строка «a11111» станет константой компиляции и будет загружена в память вместе с образом программы. А указатель `char* a2` будет инициализирован адресом хранения этой строки. И казалось бы, все здорово: мы имеем валидную си-строку, точнее указатель на нее. Но противоречие заключается в том, что эту строку нельзя изменить и если вы попытаетесь это сделать, С++ не предупредит вас при компиляции — вы получите ошибку о попытке записи в защищенную память уже на этапе выполнения. И именно поэтому делать так не рекомендуется.
Как правильно?
По сути такая запись эквивалентна:
const char *c= "a11111";
В отличие от первой последняя проверяет, чтобы не было попыток записи по адресу через константный указатель на этапе компиляции, и следовательно способствует более быстрому устранению ошибок и предотвращению их попаданию в продакшн. Если хотите проверить:
const char *c= "a11111"; c[0]='b';
не откомпилируется и вам выдаст ошибку о попытке записи в readonly-память. Конструкция const char*
говорит о том, что указатель указывает на readonly память, которую нельзя менять в процессе выполнения программы.
Передача массивов в качестве аргументов
Существует несколько способов передать массив в качестве аргумента в функцию. Выше мы использовали для этого указатель. Но это не единственный способ. Рассмотрим, как у нас есть варианты:
void ViewArray(char arr[]);
void ViewArray(char *arr);
void ViewArray(char (&arr)[7]);
Первые два способа практически идентичны. В обоих случаях в функцию передается указатель, несмотря на то, что в первом объявлении мы указали массив в качестве аргумента. Даже если мы вставим первой строчкой проверку typeid для первого объявления ViewArray, на выходе получим всего лишь указатель. Здесь, я думаю, стоит коснуться темы про различие указателей и массивов. Дело в том, что новички из-за неявного преобразования массивов в указатели думают, что это одно и то же.
Массивы и указатели
Это очень важная и непростая тема для новичков. Для начала запустим небольшой код:
#include <iostream> #include <typeinfo> using namespace std; int main(int argc, char** argv) { char b2[] = "b2"; char *b1 = b2; cout << typeid(b2).name() << endl; cout << typeid(b1).name() << endl; }
И мы увидим, что b1 и b2 — разные типы. b1
— указатель, Pc
, а b2
— это массив, A3_c
. 3
в названии обозначает размер массива, c
— тип char
. Но тем не менее, передав любой из них в ViewArray, мы получим одинаковое поведение. Потому что при передаче массива в качестве аргумента он всегда преобразуется в указатель на первый его элемент. Это вызывает путаницу. Но не только это. Массив — это уникальный тип данных в C++. Он преобразуется к указателю на первый свой элемент почти при любых операциях с ним. Для иллюстрации этого изменим код выше на:
char b2[] = "b2"; char *b1 = b2; cout << typeid(b2+0).name() << endl; cout << typeid(b1).name() << endl;
И запустим. В итоге мы получим два указателя. Что? Всего лишь добавили нуль к массиву и получили указатель на его первый элемент.
Среди операций, которые неявно преобразуют массив к указателю на 1й элемент, можно отметить
- арифметические операторы сложения и вычитания
+
,-
, - Операторы разыменования
[]
, * - Операторы сравнения:
==
, <, > , - Передача в качестве аргумента в функцию
Есть и исключения — проще запомнить исключения — например, оператор взятия адреса & вернет указатель не на первый элемент массива и, как ожидалось бы, не на указатель на указатель на 1-й элемент массива, а на весь массив:
char (*b3)[3] = &b2;
Попытка же сделать char* b3 = &b2
приведет вас к ошибке. Кроме того, отличать массив от указателя умеют такие функции, как sizeof()
и typeid()
.
Но есть и запретные операции, которые не преобразуют массив к указателю неявно и не работают с массивом напрямую — это возврат из функции и конструктор копирования (оператор =
). Это делает массивы в С++ особым типом данных.
На этом маленький экскурс по различию указателей от массивов закончим и если есть желание углубиться в эту тему, рекомендую почитать вот эту статью с комментариями к ней. Так же буду рад комментариям и замечаниям по данному вопросу к этой статье. А теперь вернемся к третьему объявлению функции:
Возможности рефлексии. Часть 2
Дополнительные возможности рефлексии python:
__setattr__
__setattribute__
__getattr__
__metaclass__ (metaclass)
__new__
__call__
callable
incpect
__mro__
Атрибут, который содержит список (точнее, кортеж) классов-родителей в порядке их наследования предком (а точнее в порядке вызова их методов согласно цепочке наследования). Обратите внимание, что цепочка наследования обрывается, если вы не переопределяете метод родителя через super([<class>,self]).method()
.
Основные команды машинного кода
Ассемблер для Windows X86 (MASM):
- b8 — mov приемник, источник — например:
mov edx, ecx
— копирует содержимое ecx в edx, иначе говоря — edx = ec - e8 — call <абсолютный адрес> — вызов функции по адресу и запись текущего адреса в стек
- e9 — jmp <относительный адрес> — прыжок на целевой адрес, который вычисляется adr = jmp_addr + sizeof(jmp) + sizeof(<относительный адрес>) = jmp_addr + 1 + 4 = jmp_addr + 5
- c3 — ret — извлекает адрес из вершины стека (сдвигает ESP) и осуществляет переход EIP (управления) на этот адрес
- c2 — retn <значение> — извлекает адрес из вершины стека (сдвигает ESP), осуществляет переход EIP (управления) на этот адрес (- то же, что и C3 )
+вычитает <значение> из ESP (вроде бы) - 74 — jz (je) <1-байтовый сдвиг> — условный переход/ Инструкция JE проверяет флаг ZF. Если этот флаг равен 1, то выполняется переход к МЕТКЕ.
- 0x0F84 —
- lea <регистр, значение> — помещает в регистр адрес через относительное смещение. Например, `lea eax, <значение>` аналогично команде `mov eax, offset <значение>`.
- sub <приемник,источник> — Вычитание двух целочисленных двоичных операндов.
приёмник = приёмник — источник. - 6A, 68 — push <arg> — где arg=1byte и 4byte соответственно. Добавляет 1 байт и 4 байта в стэк соответственно
- 90 — nop — пустая команда, просто пропускается
Назначение регистров в Си:
EAX — возвращает результат выполнения функции (значения либо указателя на объект), а так же может передавать первый параметр функции при fastcall-соглашении. В самой ф-ии может использоваться без ограничений
EBP — хранит начальное значение вершины стека (на момент старта ф-ии) на всем протяжении выполнения ф-ии. Служит базой для вычисления адресов локальных переменных (на стеке).
ESP — хранит текущее значение вершины стека
ECX, EDX — хранят значения переданных функции параметров при вызове fastcall (Microsoft)
EIP — выполняемая инструкция
Флаги:
P — Parity Flag — флаг четности. Устанавливается в 1, если младший байт результата предыдущей команды содержит чётное количество битов, равных 1
A — Auxiliary Carry Flag
Z — Флаг нуля. Устанавливается 1, если результат предыдущей команды равен 0
Полезные ссылки:
Интерфейсы в питоне
В питоне нет понятия интерфейса как такового, но начиная с 2.6 появилось понятие ABC. Понятие довольно интересное, но как оказалось, оно имеет ряд ограничений.Как вы знаете, понятие интерфейсов пришло из статически типизированных языков, таких, как Java и C#. Там интерфейсы — это некоторые абстрактные декларации, которые не могут иметь инстанса. Они так же могут наследоваться, как и обычные классы.
ABC в питоне — это абстрактный класс. Абстрактные классы так же не могут иметь инстанса, но в отличие от интерфейсов абстрактные классы могут иметь дефолтные реализации для наследников (в последних версиях java, начиная с 2014г, и C#, начиная с 8-й версии, интерфейсы так же могут содержать дефолтные реализации). Рассмотрим его на примере на класса IMovable:
from abc import ABCMeta, abstractmethod, abstractproperty class IMovable(): __metaclass__=ABCMeta Продолжить чтение
Рефлексия в python
Всем привет! Здесь я хотел бы скомпоновать все основные приемы и особенности python-Reflection. В программировании reflection (с англ. «осмысление») означает процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения. Ниже описаны наиболее важные атрибуты и функции языка для работы с рефлексией: