Self-modifying python code (1)

Python jest językiem który mimo swojej pozornej prostoty potrafi nie raz zaskoczyć swoimi możliwościami. Wiele technik programistycznych które wydawałoby się że mają sens tylko w językach niższego poziomu może być też stosowane tutaj. Tym postem chciałbym rozpocząć krótki cykl paru postów, w którym chciałbym się skupić na technice znanej szerzej jako self-modyfying code. Jest to technika która bardzo często jest stosowana podczas obfuskacji kodu (co powoduje że jest ona bardzo popularna w pisaniu w różnej maści wirusów komputerowych), jednak nie jest to jej jedyne zastosowanie które moim zdaniem warto znać.

Na czym więc polega to self-modyfying code?

Główne założenie sprowadza się do stworzenia kodu który będzie potrafił sam siebie modyfikować w trakcie działania. Bardzo często ta modyfikacja będzie również tworzona poprzez nasz kod (czyli program poprawi swój kod, a potem zastąpi swój stary kod nową wersją), a czasem sprowadza się tylko do podmiany kodu na inną wersję ‘w locie’.

Założmy że chcielibyśmy mieć program który jesteś w stanie modyfikować siebie w trakcie jego działania - chciałbym móc napisać nową wersję kodu i móc zastąpić wersję która właśnie działa.

Oto prosty przykład:

Co się dzieje w tym przykładzie? Program co pięć sekund wczytuje moduł skynet ponownie. Po czym odpala metodę hello.

Co dostaniemy na output jeżeli zmienimy moduł skynet na nową wersję? Prawdę mówiąc, to nie stanie się nic. Dlaczego? Bo nasz stary obiekt s nadal reprezentują nasza starą wersję klasy T800. Musimy jakoś podmienić mu kod na naszą nową wersję.

I tutaj właśnie dochodzimy do napisania kodu który będzie potrafił się sam zmodyfikować. Wystarczy dodać mu tylko:

I dopiero teraz zacznie się prawdziwa ‘magia’ i nasz T800 będzie się zachowywał tak jak chcemy. Co się stało kiedy podmieniliśmy class na skynet.T800 ?

Pole class służy by instancja obiektu trzymała sobie informację czym tak naprawdę jest. Pozwala to im potem odnaleźć odpowiednią metodę której powinny użyć. Nadpisując to pole wymusiliśmy użycie metod z naszej nowej wersji naszej klasy. Podobną rzecz moglibyśmy osiągnąć za pomocą tak zwanego monky patching. Podejście posiada to jednak parę wad - obiekt ciągle jest obiektem starego typu (co może być problemem), i przede wszystkim trzeba by było ręcznie przepinać metody które nas interesują (co może być bardzo problematyczne) .

Jest to oczywiście najprostsza metoda stworzenia kodu który potrafi sam się modyfikować, wydaje mi się jednak że jest to bardzo dobry punkt zaczepienia w temacie. Tym postem chciałem rozpocząć mały mini cykl w którym chciałbym opisać szerzej tą dość mało używaną technikę programowania.

Zapraszam do komentowania!