Pokaż wyniki 1 do 4 z 4

Temat: Python niby podstawa a jakoś nie mam pojęcia

  1. #1
    Zarejestrowany
    Dec 2011
    Skąd
    Mazury
    Postów
    133

    Domyślnie Python niby podstawa a jakoś nie mam pojęcia

    Wydawało mi się, że znam całkiem dobrze pythona, tymczasem czytam manual kivy i aż się zdziwiłem, kiedy składnia prezentowana jako prosty przykład okazała się dla mnie nie zrozumiała.

    Aż mi głupio zadawać tak proste pytanie, ale może ktoś się zlituje i oszczędzi mi kopania ( manual pythona mi tego jakoś nie wyjaśnia ), bo w googlu ciężko będzie znaleźć.

    Mianowicie:

    Kod:
    class MyClass(object):
        def __init__(self):
            super(MyClass, self).__init__()
            self.numeric_var = 1
    definiowanie klasy wiadome. Dziedziczy ona po klasie "object". Metoda init jest metodą wywoływaną bezpośrednio po inicjalizacji obiektu ( z tego co pamiętam, bo chyba właśnie tym się różnił init od konstruktora, że nie wywołuje klasy, tylko konkretyzuje ją, ale dawno w to nie wnikałem ).

    Kolejna linijka jednak jest dla mnie zrozumiała niczym pijany szwab. Rozumiejąc dokładnie tak jak tłumaczy podstawowy samouk pythona z oficjalnej strony. Wywołujemy funkcje __init__() klasy super z argumentami wywołania tejże klasy MyClass i self. Niech będzie, że MyClass to właśnie inicjowana klasa. A raczej definiowana. A self po co?

    No właśnie! Definiowana a nie inicjowana. Heh chyba już wiem. Pisanie dobrze się jeszcze chwilę się zastanowić przed wysłaniem posta .

    Podejrzewam, że self wskazuje, że MyClass ma być bieżącą instancją właśnie inicjowanego ( tzn. konkretyzowanego o ile dobrze pamiętam różnicę pomiędzy __init__ a konstruktorem ) obiektu.

    Jeżeli dobrze rozumuje, to kiedy tego typu kod wykonam bez self, linijka super( MyClass ).__init__() Utworzy nowy obiekt jako argument klasy.

    Da się to sprawdzić doświadczalnie pisząc prosty kod. Zaraz się tym pobawię a tym czasem może ktoś mnie wyprowadzi z błędu, w którym mi się wydaje, że jednak jestem. Bo z tego co mi wiadomo, to co opisałem powinno się robić tak:

    Kod:
    super.__init__( self, MyClass )
    Grrr po ponad dwóch latach obcowania z pythonem mieć problem ze zrozumieniem składni ;/ Jestem wściekły na samego siebie.

    _____________Dopisek po przemyśleniach_____________

    Zanim zabrałem się za eksperymenty jeszcze podukałem nad dobrze znanym mi działaniem zmiennej self. Skoro przyjmuje ona wartość bieżącej instancji. To załóżmy, że tworzymy obiekt "klasa" klasy. MyClass. W tym wypadku self przyjmuje wartość "klasa". Wobec czego można by instancje przedstawić w ten sposób:

    Kod:
    # Instancja klasa klasy MyClass
        def __init__(klasa):
            super(MyClass, klasa).__init__()
            self.numeric_var = 1
    Jeśli rozumieć tak ( a raczej tak, bo argument to tylko argument więc skąd mi przyszło do głowy, że drugi argument decyduje o tym czy pierwszy będzie nową instancją o_O ), to po prostu super jest wywoływana z dwoma argumentami. Z tym, że MyClass nie jest obiektem, tylko jego definicją. Muszę więc sprawdzić, to co miałem sprawdzić już wcześniej. Czy kiedy dam jako argument nazwę klasy, interpreter wywali błąd, czy wywoła funkcje __init__ i poda zainicjowany obiekt jako wartość argumentu. Moim zdaniem tak, bo identycznie robi przy podaniu funkcji jako argument ( najpierw wykonuje a jako argument podaje wartość którą zwraca ). Tylko dlaczego te argumenty nie są podane do funkcji, tylko do klasy? Funkcje da się wywołać bez argumentów tylko jeżeli funkcja nie ma zdefiniowanych parametrów, albo parametry są opcjonalne. Fajnie, tylko, że argumenty wywołania klasy są przekazywane jako parametry funkcji init.... No tak wychodziłoby na to, że zapis z argumentami za nazwą klasy jest równoważny z argumentami do init ( wszak i tak argumenty idą do init ).

    Jestem na 80% pewny, że to będzie tak. Pozostaje sprawdzić doświadczalnie.
    Ostatnio edytowane przez Orb : 05-31-2014 - 21:31
    "Trąba powietrzna moich zepsutych myśli, zrywa ci z karku kołnierz ortopedyczny"

  2. #2
    Zarejestrowany
    Dec 2011
    Skąd
    Mazury
    Postów
    133

    Domyślnie

    Jednak nie działa to tak, jak myślałem. Napisałem klasę:

    Kod:
    class Poligon:
       def __init__( self, a, b )
          self.c = a
          self.d = b
    Następnie klasę:

    Kod:
    class Klasa:
       def ___init___( self )
          Poligon( Klasa, self ).__init__()
    Krzyczało mi, że missing 2 required positional arguments. Z ciekawości dorzuciłem jeszcze jeden argument do poligon zmieniając na Poligon( Klasa, self, x ).__init__(). Tak jak myślałem z dwóch argumentów za mało, zrobił się jeden za dużo.

    Kod:
    class Klasa:
       def ___init___( self )
          Poligon().__init__( Klasa, self )
    Interpreter skomentował o jednym argumentem za mało. usunięcie parametru "b" i zmiennej d przekonało dusiciela do współpracy:

    Kod:
    class Poligon:
       def __init__( self, a )
          self.c = a
    Przy powyższej klasie poligon:

    Kod:
    class Klasa:
       def ___init___( self )
          Poligon().__init__( Klasa, self )
    Odpaliło.
    Wygląda więc na to, że przy wywołaniu przez Poligon.__init__( argumenty ), Interpreter traktuje pierwszy podany argument jako wartość dla "self". Teraz próbujemy wywoływać obiekt poleceniem:

    Kod:
    class Klasa:
       def ___init___( self )
          Poligon ( Klasa, self )
    . Naturalnie Krzyczy o jeden argument za dużo.


    Kod:
    class Klasa:
       def ___init___( self )
          Poligon( Klasa )
    To musi odpalić, jednak dla pewności sprawdzam. Odpala.

    Czyli jedyna znana mi opcja, żeby skrypt zadziałał w sposób zaprezentowany w manualu, to argumenty domyślne w init. Przetestuję jak będzie się zachowywał poligon z parametrami opcjonalnymi a tym czasem może ktoś się zlituje i coś podpowie.

    Naturalnie po zdefiniowaniu klas testowałem skrypt poleceniem:
    Kod:
    Klasa()
    "Trąba powietrzna moich zepsutych myśli, zrywa ci z karku kołnierz ortopedyczny"

  3. #3
    Zarejestrowany
    Dec 2011
    Skąd
    Mazury
    Postów
    133

    Domyślnie

    Z argumentami opcjonalnymi poszło. Pytanie teraz jakie wartości przyjmie __init__ skoro "gubiło" nadawane podczas wywołania Poligon( argumenty ).__init__() W tym celu wyświetliłem wartości parametrów:

    Kod:
    class Poligon:
    	def __init__( self, a=None, b=None ):
    		print ( a )
    		print ( b )
    Kod:
    class Klasa():
    	def __init__( self ):
    		Poligon( Klasa, self ).__init__()
    Interpreter wypluł:

    Kod:
    <class '__main__.Klasa'>
    <__main__.Klasa object at 0x0000000003472240>
    None
    None
    <__main__.Klasa object at 0x0000000003472240>
    Wychodzi na to, że funkcja init jest wywoływana dwa razy. Najpierw inicjuje obiekt z parametrami wywołującymi klasę, a potem wywołuje metodę __init__ należącą do bieżącej instancji. Z parametrami podanymi do funkcji ( w tym wypadku z domyślnymi ). Dopisuje linijki które to sprawdzą:

    Kod:
    class Klasa():
       def __init__( self ):
          Poligon( Klasa, self ).__init__()
          print ( "Wykonano __init__( self ), klasy Klasa" )
    Kod:
    class Poligon:
       def __init__( self, a=None, b=None ):
          print ( a )
          print ( b )
          print ( "Wykonano __init__( self, a=None, b=None ), klasy Poligon" )
    Wężyk potwierdza moje przypuszczenia.

    Kod:
    <class '__main__.Klasa'>
    <__main__.Klasa object at 0x0000000002DDC7F0>
    Wykonano __init__( self, a=None, b=None ), klasy Poligon
    None
    None
    Wykonano __init__( self, a=None, b=None ), klasy Poligon
    Wykonano __init__( self ), klasy Klasa
    <__main__.Klasa object at 0x0000000002DDC7F0>
    Najpierw wykonuje init z parametrami podanymi, a potem z domyślnymi. Pozostaje jedynie sprawdzić czy init z parametrami domyślnymi będzie należało do instancji utworzonej już z podanymi argumentami, czy stworzy nową. Muszę pomyśleć jak to sprawdzić.
    "Trąba powietrzna moich zepsutych myśli, zrywa ci z karku kołnierz ortopedyczny"

  4. #4
    Zarejestrowany
    Dec 2011
    Skąd
    Mazury
    Postów
    133

    Domyślnie

    Teoretycznie nie powinno pisać się postu pod postem, ale moim zdaniem w tym wypadku to dużo czytelniejsze niż dłuuuugi monolog. Muszę przyznać, że to była dla mnie nie lada zagadka jak eksperymentalnie sprawdzić, czy oba wywołania funkcji init nastąpią dla tej samej instancji. Ostatecznie rozwiązałem to tak:

    Kod:
    class Object:
    	def __init__( self ):
    		print ( "Klasa bazowa" )
    		self.i = 0
    
    class Poligon( Object ):
    	def __init__( self, a=None ):
    		print ( "Klasa: Poligon( Object )" )
    		if a != None:
    			print ( "A != None" )
    			Object.__init__( self )
    		else:
    			print ( "A == None" )
    		self.i = self.i + 1
    		print ( "Self.i: ", self.i )
    		self.a = a
    		print ("A:", a )
    		
    class Klasa( Object ):
    	def __init__( self ):
    		print ( "Klasa(Object)" )
    		Poligon( Klasa ).__init__()
    Po wrzuceniu w interpreter wydusiło mi to:

    Kod:
    Klasa(Object)
    Klasa: Poligon( Object )
    A != None
    Klasa bazowa
    Self.i:  1
    A: <class '__main__.Klasa'>
    Klasa: Poligon( Object )
    A == None
    Self.i:  2
    A: None
    <__main__.Klasa object at 0x00000000036C2EF0>
    Gdyby przy drugim wywołaniu funkcji __init__ tworzyła się nowa instancja, to nie byłaby zainicjowana klasa bazowa i kompilator by krzyczał, że w klasie poligon nie ma zmiennej self.i.

    Więc teoretycznie tak by można rozumieć działanie tego skryptu z manuala Kivy.

    Kod:
    class MyClass(object):
    Wiadome klasa "MyClass" dziedzicząca po klasie "object"

    Kod:
    def __init__(self):
    To również oczywiste. Funkcja wywoływana bezpośrednio po utworzeniu obiektu klasy.


    Kod:
    super(MyClass, self).__init__()
    Najpierw utworzy obiekt klasy super o argumentach do __init__ "MyClass" i "self", zaś potem wywoła metodę __init__ w bieżącej instancji klasy z argumentami domyślnymi.

    Kod:
    self.numeric_var = 1
    nadanie wartości zmiennej.

    Tak by niby pasowało, tylko, że po pierwsze:
    Po kiego grzyba by to wgl było?

    Czuje, że tyle się namęczyłem i dalej jestem w ciemnej dupie. Mógłby ktoś mi to wyjaśnić?
    "Trąba powietrzna moich zepsutych myśli, zrywa ci z karku kołnierz ortopedyczny"

Zasady Postowania

  • Nie możesz zakładać nowych tematów
  • Nie możesz pisać wiadomości
  • Nie możesz dodawać załączników
  • Nie możesz edytować swoich postów
  •  
Subskrybuj