Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Metaklasy w Pythonie

63 views
Skip to first unread message

pr

unread,
Jan 3, 2010, 5:40:22 PM1/3/10
to
Witam,

Czy da się tak zrobić aby "metaklasa była lazy", to znaczy, aby
wywołanie metody __new__ w MyMeta nastąpiło w wyniku świadomego
odwołania do klasy B (patrz kod niżej), czyli, np kiedy zrobię tak:
print B.myattr
print B().myattr
a nie w chwili gdy interpreter napotka już tylko samą definicję klasy
(czyli za każdym razem, niezależnie czy jej używam):
class B(A): pass
?

Z góry dzięki za odpoweidź.

class MyMeta(type):

def __new__(cls, name, bases, attrs):
print "Metaclass"
super_new = super(MyMetal, cls).__new__
parents = [b for b in bases if isinstance(b, MyMeta)]
if not parents:
return super_new(cls, name, bases, attrs)

module = attrs.pop('__module__')
new_class = super_new(cls, name, bases, {'__module__':
module})
...
...
return new_class


class A(object):

__metaclass__ = MyMeta

class B(A):
pass

Łukasz Rekucki

unread,
Jan 3, 2010, 9:23:44 PM1/3/10
to
On Jan 3, 11:40 pm, pr <crico...@gmail.com> wrote:
> Witam,
>
> Czy da się tak zrobić aby "metaklasa była lazy", to znaczy, aby
> wywołanie metody __new__ w MyMeta nastąpiło w wyniku świadomego
> odwołania do klasy B (patrz kod niżej), czyli, np kiedy zrobię tak:
Do pewnego stopnia tak, tylko nie bardzo wiem po co. Coś jako to B
wstawić musisz. Zresztą są prostsze sposoby zrobienia fabryki.

> print B.myattr
> print B().myattr
> a nie w chwili gdy interpreter napotka już tylko samą definicję klasy
> (czyli za każdym razem, niezależnie czy jej używam):
> class B(A): pass
> ?

Definicja klasy, to też jej utworzenie.
>>> class K(object): pass
jest równoznaczne z:
>>> K = type('K', (object,), {})
Metaklasa sprawia jedynie, że to się zamienia w:
>>> K = my_meta('K', (object,), {})


>
> Z góry dzięki za odpoweidź.
>
> class MyMeta(type):
>
>     def __new__(cls, name, bases, attrs):
>         print "Metaclass"

>         super_new = super(MyMeta, cls).__new__


>         parents = [b for b in bases if isinstance(b, MyMeta)]

O ile nie zadeklarujesz podklasy MyMeta z MyMeta jako jej metaklasą,
to raczej nie ma szans na spełnienie tego warunku.

Jan Kaliszewski

unread,
Jan 3, 2010, 10:04:01 PM1/3/10
to
2010-01-03 o 23:40 pr <cric...@gmail.com> napisał:

> Czy da się tak zrobić aby "metaklasa była lazy", to znaczy, aby
> wywołanie metody __new__ w MyMeta nastąpiło w wyniku świadomego
> odwołania do klasy B (patrz kod niżej), czyli, np kiedy zrobię tak:
> print B.myattr
> print B().myattr
> a nie w chwili gdy interpreter napotka już tylko samą definicję klasy
> (czyli za każdym razem, niezależnie czy jej używam):
> class B(A): pass
> ?

Tak wprost się nie da.

Ale możesz w ramach lub niezależnie od Twojej metaklasy utworzyć
taki mechanizm, że z chwilą stworzenia danej klasy tak naprawdę
utworzona zostanie jedynie "pusta" klasa-wrapper, która będzie się
zachowywać tak, że dopiero z chwilą pierwszego pobrania
jakiegokolwiek jej atrybutu będzie ona tworzyć właściwą klasę.
(Jak będę miał chwilę, to naszkicuję, jak to mogłoby wyglądać).

Pytanie tylko, w czym Ci przeszkadza utworzona a niewykorzystana
klasa?

pozdr.
*j

pr

unread,
Jan 4, 2010, 7:03:24 AM1/4/10
to
> Definicja klasy, to też jej utworzenie.>>> class K(object): pass
Tak jestem tego świadom, dlatego pytam o rozwiązanie typu lazy
load :-)

> O ile nie zadeklarujesz podklasy MyMeta z MyMeta jako jej metaklasą,
> to raczej nie ma szans na spełnienie tego warunku.

Właśnie tylko pytanie, czy to jest takie w "stylu Pythona" i co z
działaniem takiego rozwiązania (tzn. czy można się potem spodziewać
jakiś pułapek manipulując klasą jej atrybutami i obiekatmi).


> Ale możesz w ramach lub niezależnie od Twojej metaklasy utworzyć
> taki mechanizm, że z chwilą stworzenia danej klasy tak naprawdę
> utworzona zostanie jedynie "pusta" klasa-wrapper, która będzie się
> zachowywać tak, że dopiero z chwilą pierwszego pobrania
> jakiegokolwiek jej atrybutu będzie ona tworzyć właściwą klasę.
> (Jak będę miał chwilę, to naszkicuję, jak to mogłoby wyglądać).

Też myślałem nad czymś podobnym, problem w tym, że to ładnie
wychodziło podczas tworzenia samej instacji ( B().myattr), natmiast
gdzieś się pogubiłem podczas wywołania typu B.myattr (w zasadzie to
były tylko rozważania, nie implmentowałem tego rozwiązania jeszcze)

> Pytanie tylko, w czym Ci przeszkadza utworzona a niewykorzystana
> klasa?

W cały problem nie będę wchodził bo jest dość skomplikowany (min.
wykorzystywany zew. aplikacja, która na wejściu przyjmuje klasę
określonego typu z określonymi atrybutami etc..), natmoast wartości
atrybutów tejże klasy są wynikiem dość kosztownych obliczeń. Dlatego
jeśli bedę miał 100 klas, a wykorzystam tylko 10 (może tak się
zdarzyć) to 90 razy wykonam zbędne obliczenia. Natmoast wołanie na
każdej instacji np. funkcji obliczającej mi te parametry na żądanie,
typu: obj.clc_param() nie wchodzi w grę.. Korzystanie z klasy ma się
ograniczyć do B.myattr i B().myattr (korzysta z tego automat nie
programista).

Dzięki.
Pozdrawiam.

Łukasz Rekucki

unread,
Jan 4, 2010, 7:24:50 AM1/4/10
to
> W cały problem nie będę wchodził bo jest dość skomplikowany (min.
> wykorzystywany zew. aplikacja, która na wejściu przyjmuje klasę
> określonego typu z określonymi atrybutami etc..),
Szczerze mówiąc jeszcze nie widziałem aplikacji przyjmującej klasę
pythonową jako wejście. Próbowałeś użyć zwykłego obiektu ? Jeśli musi
być wołalny, to w jego klasię dajesz __call__().

> natomiast wartości


> atrybutów tejże klasy są wynikiem dość kosztownych obliczeń. Dlatego

A nie wystarczy, że atrybuty będą leniwie wyliczane ? Patrz @property.

zbr...@tlen.pl

unread,
Jan 4, 2010, 7:48:06 AM1/4/10
to
pr wrote:
> W ca�y problem nie b�d� wchodzi� bo jest do�� skomplikowany (min.
> wykorzystywany zew. aplikacja, kt�ra na wej�ciu przyjmuje klas�
> okre�lonego typu z okre�lonymi atrybutami etc..), natmoast warto�ci
> atrybut�w tej�e klasy s� wynikiem do�� kosztownych oblicze�. Dlatego
> je�li bed� mia� 100 klas, a wykorzystam tylko 10 (mo�e tak si�
> zdarzy�) to 90 razy wykonam zb�dne obliczenia. Natmoast wo�anie na
> ka�dej instacji np. funkcji obliczaj�cej mi te parametry na ��danie,
> typu: obj.clc_param() nie wchodzi w grďż˝.. Korzystanie z klasy ma siďż˝
> ograniczyďż˝ do B.myattr i B().myattr (korzysta z tego automat nie
> programista).

Je�li tylko o to chodzi to mo�e podej�� do problemu od innej strony i
u�y� mechanizmu properties?

Wtedy de facto wywo�ywana jest metoda, kt�ra mo�e zrobi� czasoch�onne
obliczenia, ale z punktu widzenia "klienta" tej klasy wygl�da to jak
dost�p do atrybutu.

Metoda wykona si� dopiero w momencie odwo�ania do atrybutu wi�c
"nieu�ywane" obiekty oblicze� nie wykonaj�.

Nnie wiem czy to jest to o co Ci chodzi bo Tw�j opis jest dosy�
enigmatyczny ;).

Pzdr J.

0 new messages