Re: Übernahme der Eingabefelder
Verfasst: Sonntag 10. Oktober 2021, 20:13
Verstehe nur Bahnhof.
Und was ist OOP?
Und was ist OOP?
Seit 2002 Diskussionen rund um die Programmiersprache Python
https://www.python-forum.de/
Code: Alles auswählen
foo = bar(spam, ham, eggs)
Das wäre dann eine Datenklasse, die ja auch die Methode "bar" enthalten könnte. So etwas gibt es natürlich auch in Python und das macht sicher auch in manchen Fällen Sinn.--> hier sollte man eben aus spam, ham und eggs eine Klasse machen und dann das entsprechende Objekt übergeben
Das halte ich fur fast schon groben Unfug. Es ist überhaupt nichts gewonnen, 3 Argumente durch eine Klasse mit 3 Attributen zu ersetzen. Außer es für die Programmiererin komplizierter zu machen.Buchfink hat geschrieben: Sonntag 10. Oktober 2021, 20:31 Hinsichtlich Verbundthematik gibt's dort einen Passus, in dem es z.B. heißt, dass Methoden mit mehr als zwei Übergabeparametern Refactoring-bedürftig sind:--> hier sollte man eben aus spam, ham und eggs eine Klasse machen und dann das entsprechende Objekt übergebenCode: Alles auswählen
foo = bar(spam, ham, eggs)
Natürlich muss man das situationsbezogen anwenden. Wenn es z. B. semantisch nicht sinnvoll ist, dann muss man davon abweichen.Das halte ich fur fast schon groben Unfug. Es ist überhaupt nichts gewonnen, 3 Argumente durch eine Klasse mit 3 Attributen zu ersetzen. Außer es für die Programmiererin komplizierter zu machen.
Ich sehe den Zugriffsschutz allerdings auch z.B. als Kommunikationsmöglichkeit zwischen z.B. Framework- und Produkt-Entwickler.Dazu reicht es wenn man einfach nicht auf Sachen zugreift, die zu Interna gehören. Die kann man einfach mit einem Unterstrich als solche kenntlich machen.
Da gebe ich Dir vollkommen Recht. Triviale Getter/Setter machen aus dem bereits oben genannten Grunde keine Sinn.Und in vielen einfachen Einstiegsbeispielen gibt es dann in Sprachen wie Java triviale Getter und Setter, womit die Attribute de fakto doch wieder öffentlich sind. Das ist dann keine Kapselung beziehungsweise ist das nichts anderes als in Python direkt auf Attribute zuzugreifen. Die Argumentation bei Java ist dann, dass man die Interna beim Zugriff jederzeit ändern kann, was beim direkten Zugriff nicht geht.
Ich kenne jetzt natürlich nicht den konkreten Fall. Aber es ist natürlich durchaus vorstellbar, dass in einigen Fällen der Unterschied im Design mit RECORD oder CLASS gering ist.Datenkapselung habe ich das erste mal mit Pascal beigebracht bekommen, und zwar mit klassischem Pascal mit RECORD und Units, ohne OBJECT oder CLASS,.
”OOP” habe ich auch das erste mal mit Pascal gezeigt bekommen — und nicht verstanden warum das jetzt besser sein sollte, weil mir in dem Zusammenhang nichts gezeigt wurde, was das wirklich besser gemacht hat, als die prozedurale Lösung, die wir davor für das gestellte Problem entwickelt hatten.
Ja das gefällt mir an Python auch sehr gut. Also dass da, wo es eben Sinn macht auch der Funktionale Part zum Tragen kommt. (Oder habe ich da was missverstanden?)In Python ist da wahrscheinlich `__str__()` eines der einfachsten Beispiele, weil selbst bei POD-Klassen oft eine eigene Zeichenkettendarstellung Sinn macht, und `print()` eine sehr einfache und zu dem Zeitpunkt sicher bekannte Funktion ist, die das dann nutzen kann, dass man eine für den Benutzer sinnvolle Darstellung als Zeichenkette ausgeben kann, in dem man ganz einfach das Objekt an `print()` übergibt.
ja, das ist korrekt. Es gibt aber eben auch Fälle, wo endlos lange Parameterlisten, die vielleicht noch Gott-weiß-wohin "durchgereicht" werden, zu unwartbarem Code führen.Die Argumentanzahl generell so drastisch zu reduzieren wie das von Martin vorgeschlagen wird, verschiebt das Problem IMHO auch nur zu immer mehr und immer verschachtelteren Argument-Objekten.
Hast Du eine Empfehlung, was man da so mal alternativ lesen könnte?Mit Büchern zu statisch typisierten Sprachen wäre ich bei Python (und anderen dynamischen Sprachen) vorsichtig.
Code: Alles auswählen
$ ./day18_fb -h
Usage: ./day18_fb -h | [-s steps] [-d] [filename]
-h print help and exit
-s steps set number of steps (default 100)
-d print debug output
The default filename is input.txt.
$ ./day18_fb -s 5 -d test_input.txt
Initial state:
.#.#.#
...##.
#....#
..#...
#.#..#
####..
[Brightness: 15]
After 1 step:
..##..
..##.#
...##.
......
#.....
#.##..
[Brightness: 11]
After 2 steps:
..###.
......
..###.
......
.#....
.#....
[Brightness: 8]
After 3 steps:
...#..
......
...#..
..##..
......
......
[Brightness: 4]
After 4 steps:
......
......
..##..
..##..
......
......
[Brightness: 4]
After 5 steps:
......
......
..##..
..##..
......
......
[Brightness: 4]
Brightness after 5 steps without stuck corners: 4
Initial state:
##.#.#
...##.
#....#
..#...
#.#..#
####.#
[Brightness: 17]
After 1 step:
#.##.#
####.#
...##.
......
#...#.
#.####
[Brightness: 18]
After 2 steps:
#..#.#
#....#
.#.##.
...##.
.#..##
##.###
[Brightness: 18]
After 3 steps:
#...##
####.#
..##.#
......
##....
####.#
[Brightness: 18]
After 4 steps:
#.####
#....#
...#..
.##...
#.....
#.#..#
[Brightness: 14]
After 5 steps:
##.###
.##..#
.##...
.##...
#.#...
##...#
[Brightness: 17]
Brightness after 5 steps with stuck corners: 17
Code: Alles auswählen
'
' Advent of Code 2015 - day 18
'
' Basic light type with boolean state and readonly brightness properties. The
' state can be set with a string and the object can be cast to a suitable
' string.
Type TBaseLight Extends Object
Const ON = "#"
Const OFF = "."
Declare Const Operator Cast() As String
Declare Const Abstract Property state As Boolean
Declare Abstract Property state(value As Boolean)
Declare Const Property brightness As Integer
' Set state from given string. Returns TRUE if the string is a valid state
' representation, FALSE otherwise.
Declare Function SetFromString(value As Const String) As Boolean
End Type
Const Operator TBaseLight.Cast() As String
Return IIf(state, ON, OFF)
End Operator
Const Property TBaseLight.brightness As Integer
Return IIf(state, 1, 0)
End Property
Function TBaseLight.SetFromString(value As Const String) As Boolean
Dim ok As Boolean
ok = TRUE
Select Case value
Case ON
state = TRUE
Case OFF
state = FALSE
Case Else
ok = FALSE
End Select
Return ok
End Function
' Normal light.
Type TLight Extends TBaseLight
Declare Const Property state As Boolean Override
Declare Property state(value As Boolean) Override
Private:
_state As Boolean
End Type
Const Property TLight.state As Boolean
Return _state
End Property
Property TLight.state(value As Boolean)
_state = value
End Property
' A stuck light. Reading the state is always TRUE, writing it has no effect.
Type TStuckLight Extends TBaseLight
Declare Const Property state As Boolean Override
Declare Property state(value As Boolean) Override
End Type
Const Property TStuckLight.state As Boolean
Return TRUE
End Property
Property TStuckLight.state(value As Boolean)
' Setting the state has no effect on a stuck light.
End Property
' A square grid of lights.
'
' The file format is one line per row with "." for a light in off state and "#"
' for a light in on state. Such a file can be loaded with the `Load` method.
'
Type TLightGrid
Declare Destructor
' Cast the this into a string of the format that `Load` expects in a file.
Declare Const Operator Cast() As String
' Load the state from given `filename`. If `hasStuckCorners` is TRUE then the
' lights in the four corners are always on, regardless of the value in the
' file.
Declare Sub Load(filename As Const String, hasStuckCorners As Boolean = FALSE)
' Advance the grid state one step.
'
' The rules are:
'
' * A light that is on, stays on if 2 or 3 neighbours are on,
' otherwise it goes off.
' * A light that is off, goes on if exactly 3 neighbours are on,
' otherwise it stays off.
'
' These rules are applied simultaneously to all lights.
Declare Sub DoStep
' The overall brightness of the light grid.
Declare Const Property brightness As Integer
Private:
size As Integer
lights(Any, Any) As TBaseLight Ptr
' Free the array/memory of the lights. Pulled into an own method because the
' destructor and `Load` need this.
Declare Sub Reset
' Get the light state at given coordinates. If coordinates are outside the
' grid, return FALSE.
Declare Const Function GetStateAt(i As Integer, j As Integer) As Boolean
' Test wether the given coordinates are a corner of the grid.
Declare Const Function IsCorner(i As Integer, j As Integer) As Boolean
' Count the neighbouring lights that are on. This considers all eight
' neighbours around the given coordinates. Off grid positions are
' considered being off.
Declare Const Function CountLitNeightbours(i As Integer, j As Integer) As Integer
End Type
Sub TLightGrid.Reset
Dim i As Integer, j As Integer
If size > 0 Then
For i = 1 To size
For j = 1 To size: Delete lights(i, j): Next
Next
End If
size = 0: Erase lights
End Sub
Destructor TLightGrid
Reset
End Destructor
Const Operator TLightGrid.Cast() As String
Dim result As String, i As Integer, j As Integer, k As Integer
' Reserve space for a `size` by `size` character grid with a line ending
' character at the end of each row.
result = Space(size * (size + 1))
k = 1
For i = 1 To size
For j = 1 To size
Mid(result, k) = *lights(i, j)
k = k + 1
Next
Mid(result, k) = Chr(10)
k = k + 1
Next
Return result
End Operator
Const Function TLightGrid.GetStateAt(i As Integer, j As Integer) As Boolean
If 1 <= i And i <= size And 1 <= j And j <= size Then
Return lights(i, j)->state
Else
Return FALSE
End If
End Function
Const Function TLightGrid.IsCorner(i As Integer, j As Integer) As Boolean
Return i = 1 And j = 1 _
Or i = 1 And j = size _
Or i = size And j = 1 _
Or i = size And j = size
End Function
Sub TLightGrid.Load(filename As Const String, hasStuckCorners As Boolean)
Dim f As Long, row As String, i As Integer, j As Integer, c As String
Dim light As TBaseLight Ptr
If size > 0 Then Reset
f = FreeFile
Open filename For Input As #f
Line Input #f, row
size = Len(row)
ReDim lights(1 To size, 1 To size)
For i = 1 To size
For j = 1 To size
If hasStuckCorners And IsCorner(i, j) Then
light = New TStuckLight
Else
light = New TLight
End If
c = Mid(row, j, 1)
If Not light->SetFromString(c) Then
Print row
Print Spc(j - 1); "^"
Print "Unexpected ";
If c = "" Then
Print "end of file";
Else
Print "character '"; c; "'";
End If
Print " at line"; i
End 1
End If
lights(i, j) = light
Next
Line Input #f, row
Next
Close #f
End Sub
Const Function TLightGrid.CountLitNeightbours(i As Integer, j As Integer) As Integer
Dim result As Integer, di As Integer, dj As Integer
result = 0
If size > 0 Then
For di = -1 To 1
For dj = -1 To 1
If Not (di = 0 And dj = 0) Then
If GetStateAt(i + di, j + dj) Then result = result + 1
End If
Next
Next
End If
Return result
End Function
Sub TLightGrid.DoStep
Dim newStates(1 To size, 1 To size) As Boolean
Dim i As Integer, j As Integer, count As Integer
If size > 0 Then
' Calculate new states.
For i = 1 To size
For j = 1 To size
count = CountLitNeightbours(i, j)
If GetStateAt(i, j) Then
newStates(i, j) = count = 2 Or count = 3
Else
newStates(i, j) = count = 3
End If
Next
Next
' Set new states.
For i = 1 To size
For j = 1 To size
lights(i, j)->state = newStates(i, j)
Next
Next
End If
End Sub
Const Property TLightGrid.brightness As Integer
Dim i As Integer, j As Integer, result As Integer
result = 0
If size > 0 Then
For i = 1 To size
For j = 1 To size
result = result + lights(i, j)->brightness
Next
Next
End If
Return result
End Property
' Print the step number, the grid state, and the grid's brightness for debugging
' purposes.
Sub PrintLights(lights As Const TLightGrid, stepNumber As Integer = 0)
Print
If stepNumber = 0 Then
Print "Initial state:"
Else
Print "After"; stepNumber; " step"; IIf(stepNumber > 1, "s", ""); ":"
End If
Print lights;
Print "[Brightness:"; lights.brightness; "]"
End Sub
'
' The main program.
'
Const DEFAULT_STEP_COUNT = 100, DEFAULT_FILENAME = "input.txt"
Dim filename As String, stepCount As Integer, debug As Boolean
filename = DEFAULT_FILENAME
stepCount = DEFAULT_STEP_COUNT
debug = FALSE
Scope
Dim i As Integer
i = 1
Do While Command(i) <> ""
Select Case Command(i)
Case "-h"
Print "Usage: "; Command(0); " -h | [-s steps] [-d] [filename]"
Print
Print " -h print help and exit"
Print "-s steps set number of steps (default"; DEFAULT_STEP_COUNT; ")"
Print " -d print debug output"
Print
Print "The default filename is "; DEFAULT_FILENAME; "."
End 0
Case "-s"
i = i + 1
stepCount = Val(Command(i))
Case "-d"
debug = TRUE
Case Else
If Left(Command(i), 1) = "-" Then
Print "Unknown option: "; Command(i); "."
Print "Try -h for help."
End 1
End If
filename = Command(i)
End Select
i = i + 1
Loop
End Scope
Scope
Dim lights As TLightGrid, i As Integer, hasStuckCorners As Integer
For hasStuckCorners = 0 To 1
lights.Load filename, hasStuckCorners
If debug Then PrintLights lights
If stepCount > 0 Then
For i = 1 To stepCount
lights.DoStep
If debug Then PrintLights lights, i
Next
End If
Print "Brightness after"; stepCount; " steps "; _
IIf(hasStuckCorners, "with", "without"); " stuck corners:"; _
lights.brightness
Next
End Scope
Code: Alles auswählen
class Something:
def __call__(self, argument):
...
something = Something()
# statt einfach nur
def something(argument):
...
Der Erfolge von Python gibt dem ja bereits Recht. Davon abgesehen scheitern Softwareprojekte sicher nicht an "private" bzw. den Eigenschaften einer Programmiersprache, sondern an soziologischen Aspekten. Das sei jedoch nur am Rande bemerkt.Es wird schlicht nur nicht so ein Gewese drum gemacht.
Dieser Vorteil ist so naheliegend, dass er mir glatt entgangen ist. Manchmal sieht man ja den Wald vor lauter Bäumen nicht.Bei der Implementierung ist mir noch ein Vorteil aufgefallen, der einfacher als Polymorphie ist: Klassen/Typen/Objekte sind Namensräume. Man muss nicht mehr so stark aufpassen eindeutige Prozedur oder Funktionsnamen zu wählen, weil `TBaseLight.brightness` eine andere Funktion als `TLightGrid.brightness` ist, man sich beim Aufruf aber auf `brightness` für beide beschränken kann, weil der Compiler aus dem Aufrufkontext weiss was gemeint ist.
Ich persönlich habe mit C angefangen.Konkreter Fall beim Erstkontakt mit ”OOP” war bei mir Informatikunterricht mit Turbo Pascal. Der Lehrplan sah die Entwicklung einer Adressverwaltung mit Units und RECORDs vor. Und das haben wir auch so durchgezogen. Und ganz am Ende hat uns der Lehrer dann die tollen neuen OOP-Konstrukte in Turbo Pascal 5.x gezeigt, in dem er das Program ”objectorientiert” umgeschrieben hat. Also letztlich aus den RECORDs halt Objekte gemacht, was syntaktisch halt ein kleines bisschen anders aussah, aber ich hatte so überhaupt nicht verstanden warum der so aus dem Häusschen war, denn so hat man natürlich nicht wirklich einen Vorteil gesehen, denn letztendlich war es ja das gleiche Programm.
Das ist ein interessanter Aspekt. Das habe ich aus den Tutorials bisher noch nicht mitgenommen. Es gibt noch so viel zu viel zuWenn es ``def`` für Funktionen nicht gäbe, sondern nur für Methoden, würde man halt mehr Boilerplate schreiben:
Ich sage es mal so:Ist der erste Code jetzt irgendwie objektorientierter, nur weil man da den Boilerplate mit der Klasse schreiben muss? Und wird es plötzlich funktional, wenn man den Boilerplate weglassen kann?
Interessehalber habe ich das mal für PEP 8 (https://www.python.org/dev/peps/pep-0008/#id14) ausprobiert und bin zum Ergebnis gekommen, dass DeepL (wie von @Dennis89 vorgeschlagen) oft die besseren Übersetzungen liefert.Edge übersetzt bei Bedarf auch automatisch. (Ist konfigurierbar)
LGContinuation lines should align wrapped elements either vertically using Python's implicit line joining inside parentheses, brackets and braces, or using a hanging indent [6]. When using a hanging indent the following should be considered; there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line: