Walka klas w python3

0

Hej. Jakoś totalnie nie kumam OOP w pythonie, w porównaniu do np cpp to jest totalnie nieczytelne dla mnie i mimo stu obejrzanych tutoriali itp to nadal nie wiem jak mam zrobić prostą rzecz jak przychodzi co do czego, np tutaj chcę by sub klasa miała dostęp do zmiennych _list & _counter z parent klasy, (ale bez inicjowania ich na wejściu jako argument w sub ponieważ potem ma to latać w pętli i w ten sposób będzie mi się tylko zerować przy każdej nowej iteracji) , więc próbuje w poniższy sposób wykombinować z super() ale im więcej o tym pythonowym super() czytam tym mniej rozumiem bo jest wiele sposobów na zrobienie tego samego i mi się to już miesza wszystko:

class Test():
    def __init__(self, _list=[], _counter=0):
        self._list = _list
        self._counter = _counter


class Sub(Test):
    def __init__(self, x):
        self.x = x
        super()._list.append(x)
        super()._counter + 1

    @property
    def __repr__(self):
        return super()._list, super()._counter


something2 = Sub('x')
print(something2.__repr__)

AttributeError: 'super' object has no attribute '_list'

Może mi ktoś pomóc jakoś wyprostować głowę pls?

0

Na przykład wywołaj konstruktor z klasy parent:

class A:
  def __init__(self, a):
    self.a = a

class B(A):
  def __init__(self):
    super().__init__(42)

b = B()

print(b.a)
0

Własnie w ten sposób - > "super().init(42)" przypisywana jest wartość przy każdym użyciu subklasy, a ja bym chciał żeby ten sub wziął daną wartość z parent klasy i żeby móc ją modyfikować, nie wiem może po prostu najlepiej tą zmienną wyjąć z klasy i do globalnych wrzucić?

0

Z tego co rozumiem możesz robić coś w stylu super().__getattr__('_list')

0

W momencie something2 = Sub('x') musi zostać wywołany konstruktor klasy nadrzędnej, bo pola self._list jeszcze w klasie nie ma.

0

Okej, dzięki za odpowiedzi. To może tak - jak najlepiej w pythonie zrobić odpowiednik takiego czegoś z c++:

#include <iostream>
using namespace std;

class Polygon {
    int width, height;
  public:
    void set_values (int,int);
    int area() {return width*height;}
	int counter = 0;
};

void Polygon::set_values (int x, int y) {
  width = x;
  height = y;
}

class Octagon : public Polygon
{
public:
	void printCounter(){
		cout << counter << endl;
	}
};


int main () {

	Polygon rect; Octagon oct;
	rect.set_values (3,4) ; oct.set_values(5, 6);
	cout << "RECT area: " << rect.area() << endl;
	cout << "OCT area: " << oct.area() << endl;
	for (int i = 0 ; i < 10 ; i++){
	--rect.counter ; oct.counter++;
	cout << "RECT COUNTER: " << rect.counter << endl;
	cout << "OCT COUNTER: " << oct.counter << endl;
	}
	return 0;
}

Czyli w skrócie subklasa Octagon dostaje z klasy nadrzędnej Polygon swoją własną instancje pola counter i może sobie z nim robić co chce, nie musi go inicjować jako argument i jego stan nie jest resetowany przy każdym kolejnym wywołaniu.

2

Nie wiem, czy dobrze zrozumialem.

class Test():
    def __init__(self, _list=[], _counter=0):
        self._list = _list
        self._counter = _counter
    
    def set_value(self, x):
        self._counter = x


class Sub(Test):
    def __init__(self, x):
        Test.__init__(self)
        self.x = x
        self._list.append(x)
        self._counter += 1
    
    
test = Test()
sub = Sub(2)

test.set_value(10)
sub.set_value(10)
for x in range(10):
    test._counter -= 1
    sub._counter += 1

print(test._counter, sub._counter)

>>> (0,20)

Klasa Sub podczas dziedziczenia Test tworzy niezalezna instancje i mozna z tymi zmiennymi zrobic co Ci sie tylko podoba nie ingerujac w cialo klasy parent. Jezeli zle cos zrozumialem to prosze o naprostowanie ;p

P.S

1

Czuję się rozczarowany, myślałem, że będzie temat o marksizmie a tu taki klops.

Najprościej to zainicjować ten counter w polu klasy i wystarczy...

class Parent:
    counter = 0

class Sub(Parent):
    pass

p, s = Parent(), Sub()
for i in range(10):
    p.counter -= 1
    s.counter += 1
print(p.counter)
print(s.counter)
$ python test.py 
-10
10
0

Wybaczie, chyba mózg mi się rozpada na starość. Wasze przykłady ofc działają, a mój kod wciąż nie -.-

class ScreenShooter:
    def __init__(self, __epochs_list=None, __epochs_counter=0):
        if __epochs_list is None:
            __epochs_list = [...]
        self.__epochs_list = __epochs_list
        self.__epochs_counter = __epochs_counter


class Shot(ScreenShooter):
    def __init__(self, hwnd):
        ScreenShooter.__init__(self)
        self.__epochs_list.append(hwnd)

    @property
    def __repr__(self):
        return self.__epochs_list


S = Shot('TEST')
print(S.__repr__)

AttributeError: 'Shot' object has no attribute '_Shot__epochs_list'

1

Podwójne podkreślenia wprowadzają ci name mangling, zobacz: https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name/1301369#1301369

Po poprawkach:

class ScreenShooter:
    def __init__(self, epochs_list=None, epochs_counter=0):
        if epochs_list is None:
            epochs_list = []
        self.epochs_list = epochs_list
        self.epochs_counter = epochs_counter

class Shot(ScreenShooter):
    def __init__(self, hwnd):
        super().__init__()
        self.epochs_list.append(hwnd)

    def __str__(self):
        return str(self.epochs_list)


S = Shot('TEST')
print(S)

Nie próbuj w Pythonie przeszczepiać idei składowych publicznych/prywatnych z C++. Nie ten język, nie te idiomy. W Pythonie generalnie większość składowych deklaruje się bez podkreśleń, chyba, że są szczegółem implementacyjnym, wówczas z jednym. Podwójne stosuje się raczej rzadko.

1 użytkowników online, w tym zalogowanych: 0, gości: 1