Hallo Python Forum, erstmals ein herzliches Hallo an alle
Ich habe folgendes Problem, ich habe ein bestehenden Weihnachts und Neujahr Countdown ein bisschen umgebaut zu einem Geburtstags-Countdown.
Dieser Countdown wird auf einer TV Box betrieben.
Jetzt hätte ich gerne das der Countdown auch am 25.02 des Jahres neu beginnt, so wie es jetzt ist scheint der Countdown erst am 01.01. des Jahres zu beginnen.
Und vielleicht währe es noch möglich die umlaute richtig darzustellen (naechsten als nächsten) und (Tschuess als Tschüss)
Ich danke jetzt schon mal für eure Hilfe.
Liebe Grüße Highlander062
<------ Hier noch die CountdownToBirthday.py Datei ----->
from Converter import Converter
from Components.Element import cached
from datetime import datetime, time
class CountdownToBirthday(Converter, object):
DAYS = 0
TIME = 1
def __init__(self, type):
Converter.__init__(self, type)
if type == "Birthday":
self.type = self.DAYS
else:
self.type = self.TIME
@cached
def getText(self):
time = self.source.time
if time is None:
return ""
if self.type == self.DAYS:
return self.calculate()
elif self.type == self.TIME:
return self.calculate(False)
else:
return "???"
text = property(getText)
def calculate(self,what=True):
now = datetime.now()
if what:
birthday = datetime(now.year, 2, 25)
delta = birthday - now
final= delta.days
if final > 0:
return str(final) + " Tage bis zum Geburtstag von Highlander"
elif final == 0:
return "Alles gute zum Geburtstag, Highlander"
elif final < 0:
return "Dein Geburtstag ist nun vorbei, Tschuess bis zum naechsten"
else:
leaving_date = datetime.strptime('%s-02-25 00:00:00' % str(int(now.year)+1),'%Y-%m-%d %H:%M:%S')
return '%d Tage, %d Std. %d Min. %d Sek.' % self.daysHoursMinutesSecondsFromSeconds(self.dateDiffInSeconds(now,leaving_date)) + " bis zum naechsten Geburtstag"
def dateDiffInSeconds(self,date1, date2):
timedelta = date2 - date1
return timedelta.days * 24 * 3600 + timedelta.seconds
def daysHoursMinutesSecondsFromSeconds(self,seconds):
(minutes, seconds) = divmod(seconds, 60)
(hours, minutes) = divmod(minutes, 60)
(days, hours) = divmod(hours, 24)
return (days, hours, minutes, seconds)
Geburtstags Countdown
Was ist denn das für ein Framework? `Converter`?
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, keine Tabs.
Von `object` muß man nicht explizit erben, vor allem nicht bei Mehrfachvererbung.
Statt `property` als Funktion benutzt man `@property` als Decorator.
Die Funktion `calculate` hat ein Argument `what`, das entweder True oder False ist? Das ist sehr kryptisch, was denn nun what=True im gegensatz zu what=False bedeutet. Da die beiden Werte zu völlig unterschiedlichen Abläufen führt, wären hier zwei getrennte Funktionen sinnvoll.
Warum gibst Du im einen Fall den Geburtstag als `datetime` direkt an, und im anderen Fall parst Du einen String?
`dateDiffInSeconds` ist einfach timedelta.total_seconds und braucht keine eigene Methode.
Und zum eigentlichen Problem: Du darfst halt nicht ungesehen mit now.year oder now.year+1 rechnen, sondern je nachdem ob der Tag schon vorbei ist, ins nächste Jahr gehen.
Eingerückt wird immer mit 4 Leerzeichen pro Ebene, keine Tabs.
Von `object` muß man nicht explizit erben, vor allem nicht bei Mehrfachvererbung.
Statt `property` als Funktion benutzt man `@property` als Decorator.
Die Funktion `calculate` hat ein Argument `what`, das entweder True oder False ist? Das ist sehr kryptisch, was denn nun what=True im gegensatz zu what=False bedeutet. Da die beiden Werte zu völlig unterschiedlichen Abläufen führt, wären hier zwei getrennte Funktionen sinnvoll.
Warum gibst Du im einen Fall den Geburtstag als `datetime` direkt an, und im anderen Fall parst Du einen String?
`dateDiffInSeconds` ist einfach timedelta.total_seconds und braucht keine eigene Methode.
Und zum eigentlichen Problem: Du darfst halt nicht ungesehen mit now.year oder now.year+1 rechnen, sondern je nachdem ob der Tag schon vorbei ist, ins nächste Jahr gehen.
Code: Alles auswählen
from Converter import Converter
from Components.Element import cached
from datetime import datetime, time
class CountdownToBirthday(Converter):
DAYS = 0
TIME = 1
def __init__(self, type):
Converter.__init__(self, type)
if type == "Birthday":
self.type = self.DAYS
else:
self.type = self.TIME
@property
@cached
def text(self):
time = self.source.time
if time is None:
return ""
if self.type == self.DAYS:
return self.calculate_days()
elif self.type == self.TIME:
return self.calculate_time()
else:
return "???"
def calculate_days(self):
now = datetime.now()
birthday = datetime(now.year, 2, 25)
days = (birthday - now).days
if days > 0:
return "%d Tage bis zum Geburtstag von Highlander" % days
elif days == 0:
return "Alles gute zum Geburtstag, Highlander"
else:
return "Dein Geburtstag ist nun vorbei, Tschuess bis zum naechsten"
def calculate_time(self):
now = datetime.now()
birthday = datetime(now.year, 2, 25)
if now > birthday:
birthday = datetime(now.year + 1, 2, 25)
seconds = (now - birthday).total_seconds()
(minutes, seconds) = divmod(seconds, 60)
(hours, minutes) = divmod(minutes, 60)
(days, hours) = divmod(hours, 24)
return '%d Tage, %d Std. %d Min. %.0f Sek. bis zum naechsten Geburtstag' % (days, hours, minutes, hours)
-
- User
- Beiträge: 10
- Registriert: Mittwoch 7. Juli 2021, 11:55
Hallo Sirius3
Danke für die schnelle Antwort.
Um deine Frage (Was ist denn das für ein Framework? `Converter`?) zu beantworten.
Ehrlich gesagt bin ich erst am lernen und weis noch nicht sehr viel über die Python Programmierung.
Ich benutze das Programm auf einer Vu+ Uno 4K se TV-Box mit dem VTi Image 15.0
Das Programm läuft einwandfrei so wie ich es habe, bis auf die Countdown Nullstellung zum gewünschten Tag und eben die Umlaute funktionieren nicht.
Ich werde auf jeden Fall das von dir berichtigte Programm ausprobieren.
Danke für die schnelle Antwort.
Um deine Frage (Was ist denn das für ein Framework? `Converter`?) zu beantworten.
Ehrlich gesagt bin ich erst am lernen und weis noch nicht sehr viel über die Python Programmierung.
Ich benutze das Programm auf einer Vu+ Uno 4K se TV-Box mit dem VTi Image 15.0
Das Programm läuft einwandfrei so wie ich es habe, bis auf die Countdown Nullstellung zum gewünschten Tag und eben die Umlaute funktionieren nicht.
Ich werde auf jeden Fall das von dir berichtigte Programm ausprobieren.
Naja, Du importierst da eine Klasse "Converter" aus einem Modul namens "Converter". Da die Python-Standarddistribution aber kein Modul dieses Namens enthält und es wohl auch sonst nicht sehr gebräuchlich zu sein scheint, kennen wir dieses Modul natürlich nicht. Gibt es dazu irgendwo eine Dokumentation, die Du uns verlinken könntest?Highlander062 hat geschrieben: Mittwoch 7. Juli 2021, 14:51 Um deine Frage (Was ist denn das für ein Framework? `Converter`?) zu beantworten.
Bitte versteh' mich nicht falsch, aber... Du machst es Dir unnötig schwer, wenn Du gleich mit "echten Projekten" anfängst, anstatt Dich erst einmal mit den Grundlagen der Sprache und ihrer Bibliotheken vertraut zu machen. Ich weiß ja, die Ungeduld ist groß, das verstehe ich -- aber es ist keine gute Idee, einfach von irgendwoher Code zu kopieren und auf einem Deiner Geräte einzusetzen, ohne vorher verstanden zu haben, was der Code genau tut. Im schlimmsten Fall kannst Du Dir auf diese Weise nämlich prima einen Schädling (Virus, Trojaner, ...) einfangen, Dein System oder womöglich sogar Deine Hardware beschädigen.Highlander062 hat geschrieben: Mittwoch 7. Juli 2021, 14:51 Ehrlich gesagt bin ich erst am lernen und weis noch nicht sehr viel über die Python Programmierung.
Deswegen möchte ich Dir wärmstens empfehlen, ein Python-Tutorial durchzuarbeiten -- und zwar auch praktisch, mit Ausprobieren (am Besten nicht auf der SetTop-Box, sondern auf einem anderen System, etwa einem ganz normalen PC). Links auf englischsprachige Tutorials findest Du ganz unten unter [1,2] und deutschsprachige unter [3,4,5]. Viel Spaß und Erfolg!
Auch diese Umgebung werden die wenigsten von uns kennen. Gibt es dazu irgendwo eine Dokumentation, die Du uns verlinken könntest?Highlander062 hat geschrieben: Mittwoch 7. Juli 2021, 14:51 Ich benutze das Programm auf einer Vu+ Uno 4K se TV-Box mit dem VTi Image 15.0
Wie dem auch sei: ich hab' das Gewünschte mal in eine kleine Funktion verbaut -- wie Du das am Ende in eine Klasse umbaust, die von Converter.Converter erbt, ist dann Dein Job:
Code: Alles auswählen
#!/usr/bin/env python
import sys
import datetime
from typing import Union
from argparse import ArgumentParser, ArgumentTypeError
from dateutil.parser import parse as dateparse, parserinfo
def birthday_counter(birthday: Union[datetime.date, datetime.datetime]) -> int:
"""calculate difference in days between "birthday" and now
:param birthday the birthday
:type birthday datetime.date or datetime.datetime
:return days until next birthday
:rtype int
if return value == 0: yay, your bday! Party on, Wayne!
if return value > 0: days until this year's birthday
if return value < 0: days until next year's birthday
"""
if not isinstance(birthday, (datetime.date, datetime.datetime)):
raise ValueError('birthday_counter(): "birthday" argument must be a datetime.date '
'but {!r} is of type {}'.format(birthday, type(birthday).__name__))
today = datetime.datetime.now().date()
this_years_birthday = datetime.date(today.year, birthday.month, birthday.day)
difference = (this_years_birthday - today).days
if difference < 0: # this year's bday is over, calc next year's
next_years_birthday = datetime.date(today.year + 1, birthday.month, birthday.day)
difference = (today - next_years_birthday).days # trick! ;-)
return difference
if __name__ == '__main__':
def date_from_str(date_str):
try:
return dateparse(date_str, parserinfo(dayfirst=True)).date()
except ValueError as e:
raise ArgumentTypeError(
'Cannot parse {!r} into a date'.format(date_str))
parser = ArgumentParser(description='calculate countdown to birthday')
parser.add_argument('birthday', type=date_from_str, nargs='?',
default='18.5.1971', help='the birthday')
args = parser.parse_args()
diff = birthday_counter(args.birthday)
if diff > 0:
print('this year\'s birthday is {} days ahead'.format(diff))
elif diff < 0:
print('next year\'s birthday is {} days ahead'.format(abs(diff)))
else:
print('congratulations!')
[1] https://docs.python.org/3/tutorial/
[2] https://www.w3schools.com/python/
[3] https://py-tutorial-de.readthedocs.io/de/python-3.3/
[4] https://www.python-lernen.de/
[5] https://www.python-kurs.eu/kurs.php
@LukeNukem: Typprüfungen sind in Python unüblich. Zumal Du ja Typannotationen einsetzt. Funktionen werden nicht innerhalb von if-Blöcken definiert, das macht das Testen einzelner Funktionen unmöglich. Alles was unter `if __name__ == "__main__"` steht gehört in eine Funktion, die man üblicherweise main nennt.
Warum wandelst Du die aussagekräftigen Fehlermeldungen von dateparse in ein nichtssagendes `cannot parse` um?
Python kennt vier Varianten, wie man literale Strings definiert, deshalb ist das Escapen von Anführungszeichen eigentlich nie nötig.
Der Trick mit positiven und negativen Zahlen ist das, als was Du es bezeichnest, ein Trick, und Tricks mögen Programmierer gar nicht, weil sie den Code unleserlich machen und ein großer Quell an Fehlern. Wenn Du eine Unterscheidung zwischen zwei Zuständen haben möchtest, gib ein Tuple zurück.
Statt .format würde ich hier f-Strings benutzen.
Damit kommen wir zu:
Warum wandelst Du die aussagekräftigen Fehlermeldungen von dateparse in ein nichtssagendes `cannot parse` um?
Python kennt vier Varianten, wie man literale Strings definiert, deshalb ist das Escapen von Anführungszeichen eigentlich nie nötig.
Der Trick mit positiven und negativen Zahlen ist das, als was Du es bezeichnest, ein Trick, und Tricks mögen Programmierer gar nicht, weil sie den Code unleserlich machen und ein großer Quell an Fehlern. Wenn Du eine Unterscheidung zwischen zwei Zuständen haben möchtest, gib ein Tuple zurück.
Statt .format würde ich hier f-Strings benutzen.
Damit kommen wir zu:
Code: Alles auswählen
import sys
import datetime
from typing import Union, Tuple
from argparse import ArgumentParser
from dateutil.parser import parse as dateparse
def birthday_counter(birthday: Union[datetime.date, datetime.datetime]) -> Tuple[int, bool]:
"""calculate difference in days between "birthday" and now
:param birthday the birthday
:type birthday datetime.date or datetime.datetime
:return days until next birthday, and a flag whether the birthday is this or next year
:rtype (int, bool)
"""
today = datetime.date.today()
this_years_birthday = datetime.date(today.year, birthday.month, birthday.day)
difference = (this_years_birthday - today).days
if difference < 0: # this year's bday is over, calc next year's
next_years_birthday = datetime.date(today.year + 1, birthday.month, birthday.day)
difference = (next_years_birthday - today).days
is_this_year = False
else:
is_this_year = True
return difference, is_this_year
def date_from_str(date_str):
return dateparse(date_str, dayfirst=True).date()
def main():
parser = ArgumentParser(description='calculate countdown to birthday')
parser.add_argument('birthday', type=date_from_str, nargs='?',
default='18.5.1971', help='the birthday')
args = parser.parse_args()
diff, is_this_year = birthday_counter(args.birthday)
if diff != 0:
print(f"{'this' if is_this_year else 'next'} year's birthday is {diff} days ahead")
else:
print('congratulations!')
if __name__ == '__main__':
main()
-
- User
- Beiträge: 10
- Registriert: Mittwoch 7. Juli 2021, 11:55
Hallo Sirius3
Nochmals vielen Dank für deine Hilfe.
Das erste Programm von dir hat einwandfrei funktioniert, bis auf einen kleinen Fehler (nun hat er die Tage als Minustage gezählt) bsp. -233 Tage bis zum Geburtstag.
Die anderen zwei funktionieren nicht aufgrund des Converter Aufruf fehlt.
Also zum verständnis, was die TV-Box alles machen soll wie zum bsp. Menu aufrufe, Uhrzeit, Einstellungen usw.
Sie liest eine Datei namens (skin.xml) aus und in der steht jetzt mal der befehl
<widget source="global.CurrentTime" render="Label" position="55,23" size="1180,50" font="Regular; 36" halign="left" valign="left" foregroundColor="green" backgroundColor="background" transparent="1">
<convert type="CountdownToBirthday">Birthday</convert>
Wird die taste für den Aufruf des Countdowns gedrückt, erscheint dann auf dem TV Bildschirm an gewünschter Position der Countdown (170 Tage noch bis zu deinem Geburtstag)
In der TV-Box Root ist der Ordner Converter, Renderer oder Components zu finden in diesen dann je nach Aufgabe die xxxxxxxxx.py aufgerufen werden.
Und wie gesagt das funktioniert fehlerfrei.
Also nochmals vielen Dank für deine Hilfe
Ich werde mich höchstwahrscheinlich in den TV-Boxen Foren schlau machen müssen.
Highlander062
Nochmals vielen Dank für deine Hilfe.
Das erste Programm von dir hat einwandfrei funktioniert, bis auf einen kleinen Fehler (nun hat er die Tage als Minustage gezählt) bsp. -233 Tage bis zum Geburtstag.
Die anderen zwei funktionieren nicht aufgrund des Converter Aufruf fehlt.
Also zum verständnis, was die TV-Box alles machen soll wie zum bsp. Menu aufrufe, Uhrzeit, Einstellungen usw.
Sie liest eine Datei namens (skin.xml) aus und in der steht jetzt mal der befehl
<widget source="global.CurrentTime" render="Label" position="55,23" size="1180,50" font="Regular; 36" halign="left" valign="left" foregroundColor="green" backgroundColor="background" transparent="1">
<convert type="CountdownToBirthday">Birthday</convert>
Wird die taste für den Aufruf des Countdowns gedrückt, erscheint dann auf dem TV Bildschirm an gewünschter Position der Countdown (170 Tage noch bis zu deinem Geburtstag)
In der TV-Box Root ist der Ordner Converter, Renderer oder Components zu finden in diesen dann je nach Aufgabe die xxxxxxxxx.py aufgerufen werden.
Und wie gesagt das funktioniert fehlerfrei.
Also nochmals vielen Dank für deine Hilfe
Ich werde mich höchstwahrscheinlich in den TV-Boxen Foren schlau machen müssen.
Highlander062
Sirius3 hat geschrieben: Donnerstag 8. Juli 2021, 07:40 @LukeNukem: Typprüfungen sind in Python unüblich.
Code: Alles auswählen
$ grep -ri 'isinstance(' /usr/lib/python3.8/ | grep -v 'Übereinstimmungen in Binärdatei' | wc -l
1592
ArgumentTypeError...Sirius3 hat geschrieben: Donnerstag 8. Juli 2021, 07:40 Warum wandelst Du die aussagekräftigen Fehlermeldungen von dateparse in ein nichtssagendes `cannot parse` um?
Dokumentation.Sirius3 hat geschrieben: Donnerstag 8. Juli 2021, 07:40 Der Trick mit positiven und negativen Zahlen ist das, als was Du es bezeichnest, ein Trick, und Tricks mögen Programmierer gar nicht, weil sie den Code unleserlich machen und ein großer Quell an Fehlern.
Nö.Sirius3 hat geschrieben: Donnerstag 8. Juli 2021, 07:40 Wenn Du eine Unterscheidung zwischen zwei Zuständen haben möchtest, gib ein Tuple zurück.
- __blackjack__
- User
- Beiträge: 14056
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@LukeNukem: Es ist trotzdem unüblich auch wenn Du Beispiele findest. Man sollte das nicht machen, weil man damit „duck typing“ unterläuft.
Es gibt unter den Treffern einige ``assert``\s. Viele prüfen auf `str` oder `bytes`/`bytearray` zum Beispiel weil die API beides nimmt aber entweder enkodieren oder dekodieren muss um einheitlich damit weiter zu arbeiten. An anderen Stellen will man Zeichenketten explizit nicht als iterierbar behandeln. Das JSON-Modul muss auf Typen testen weil es ja Typen auf JSON-Konstrukte abbilden muss. In Unit-Tests ist das manchmal nützlich. Es gibt Code der Typen als ”Marker” verwendet und da dann je nach Typ was anderes gemacht wird. Zum Beispiel das `ast`-Modul. Das `inspect`-Modul benutzt viel `isinstance()` — das ist ja aber auch explizit dazu da mit solchen (Meta-)Informationen zu arbeiten. Es gibt (einige wenige) Gründe Typprüfungen zu machen — statische Typprüfung nachzubasteln gehört eher nicht dazu.
Es gibt unter den Treffern einige ``assert``\s. Viele prüfen auf `str` oder `bytes`/`bytearray` zum Beispiel weil die API beides nimmt aber entweder enkodieren oder dekodieren muss um einheitlich damit weiter zu arbeiten. An anderen Stellen will man Zeichenketten explizit nicht als iterierbar behandeln. Das JSON-Modul muss auf Typen testen weil es ja Typen auf JSON-Konstrukte abbilden muss. In Unit-Tests ist das manchmal nützlich. Es gibt Code der Typen als ”Marker” verwendet und da dann je nach Typ was anderes gemacht wird. Zum Beispiel das `ast`-Modul. Das `inspect`-Modul benutzt viel `isinstance()` — das ist ja aber auch explizit dazu da mit solchen (Meta-)Informationen zu arbeiten. Es gibt (einige wenige) Gründe Typprüfungen zu machen — statische Typprüfung nachzubasteln gehört eher nicht dazu.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Daß das unüblich sein soll, halte ich für ein Gerücht. Alleine im Standard-Modul "datetime" wird in 1544 Zeilen Code (ermittelt mit David A. Wheeler's 'SLOCCount') insgesamt ohne Asserts 79 und mit Asserts 93 Mal die Builtin-Funktion isinstance() aufgerufen. Das sind 5,1 bis 6,0 Prozent der Codezeilen! Unüblich? Gerade im Zusammenhang mit dem "datetime"-Modul? Und daß isinstance() nicht einmal in irgendeine Standardbibliothek -- inspect böte sich vielleicht an -- ausgelagert wurde, sondern ein Builtin ist... also für so unüblich scheinen die Python-Entwickler das nicht zu halten, würde ich vermuten. Vielleicht solltet Ihr den Python-Entwicklern mal erzählen, was Ihr für üblich haltet, bitte schickt mir ein Video von ihrer Reaktion.__blackjack__ hat geschrieben: Donnerstag 8. Juli 2021, 21:19 @LukeNukem: Es ist trotzdem unüblich auch wenn Du Beispiele findest.

Zudem ist mir auch keine Regel, Vorschrift, oder auch nur Empfehlung bekannt, daß man nur Dinge tun darf, die "üblich" sind. Gibt es eine? Wenn ja, wo steht die?
Aber nehmen wir doch einmal hypothetisch an, es sei a) unüblich und b) verboten oder zumindest schlecht, unübliche Dinge zu tun. In diesem Fall ist es trotzdem vernünftig, um eine sinnvolle, lesbare und verständliche Fehlermeldung zu erzeugen. Wenn ich meinem Benutzer mit einer sinnvollen und verständlichen Fehlermeldung sagen kann, was genau schiefgelaufen ist und wie er es korrigieren kann -- und zwar ohne, daß er vorher meinen Code lesen und nachvollziehen muß -- dann mache ich das. Und halte das für klug, gut und richtig! Und dann ist da, nebenbei bemerkt, noch ein zweiter Grund: meine Funktion verwendet intern ihrerseits ein datetime.date() für Subtraktionen, und deswegen hat Duck Typing an dieser Stelle überhaupt keinen Sinn. Ein datetime.date() funktioniert in diesem Fall nämlich nur mit einem datetime.date(), einem datetime.datetime(), oder etwas, das von einer dieser Klassen erbt.
Insofern -- und da das ja nicht unsere erste Diskussion über derartige Geschmacks- und Stilfragen ist -- schlage ich vor, daß Ihr Eure hochwichtigen Regeln in Zukunft einfach mal vergeßt und ignoriert, wenn Ihr meinen Code lest. Anscheinend denke ich anders als Ihr, arbeite anders als Ihr, und halte es für eine viel bessere Idee, meine Benutzer anständig zu unterstützen, statt sie wegen eingebildeter Regeln zu nerven.
Wenn Ihr schon unbedingt etwas kritisieren wollt, dann kritisiert doch wenigstens etwas Kritikwürdiges. Zum Beispiel, daß ein TypeError hier natürlich sinnvoller wäre als ein ValueError.
Ich halte das `datetime`-Modul insgesamt nicht für sehr gelungen. Wahrscheinlich ein Grund dafür, dass es so viele Konkurrenz-Module gibt, die ähnliches machen. Vieles in der Standardbibliothek ist über Generationen hinweg entstanden und enthalten Dinge, die man bei einem neuen Modul anders lösen würde.
Wenn man jemandem anderen Programmieren erklären will, dann sollte man schon darauf achten, wie etwas üblicherweise gemacht wird. Du kannst jedem zur Begrüßung auch die Zunge rausstrecken, es gibt ja keine Vorschrift, die Dir das verbietet.
Und nochmal, ich schreibe hier nichts für Dich, dazu ist mir die Zeit zu schade, sondern für die anderen.
Wenn man jemandem anderen Programmieren erklären will, dann sollte man schon darauf achten, wie etwas üblicherweise gemacht wird. Du kannst jedem zur Begrüßung auch die Zunge rausstrecken, es gibt ja keine Vorschrift, die Dir das verbietet.
Und nochmal, ich schreibe hier nichts für Dich, dazu ist mir die Zeit zu schade, sondern für die anderen.
- DeaD_EyE
- User
- Beiträge: 1240
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Schau ins logging Modul rein. Daran sieht man, dass diejenigen, die das implementiert haben, aus der Java-Welt kommen und ihr Paradigma auf Python übertragen haben. Sich dann aber danach zu richten, ist falsch. Es verschlimmert die Situation.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Könntest Du Deine Kritikpunkte vielleicht etwas genauer ausführen?DeaD_EyE hat geschrieben: Freitag 9. Juli 2021, 13:27 Schau ins logging Modul rein. Daran sieht man, dass diejenigen, die das implementiert haben, aus der Java-Welt kommen und ihr Paradigma auf Python übertragen haben. Sich dann aber danach zu richten, ist falsch. Es verschlimmert die Situation.
- DeaD_EyE
- User
- Beiträge: 1240
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Code: Alles auswählen
import logging
log = logging.getLogger()
Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized. run();
runFast();
getBackground();
Python
Wenn der Entwickler sich an PEP8 gehalten hätte, würde die Methode get_logger heißen und nicht getLogger.Use the function naming rules: lowercase with words separated by underscores as necessary to improve readability.
Use one leading underscore only for non-public methods and instance variables.
Das sind Module gewesen, die ziemlich früh implementiert worden sind und am Anfang ist vieles einfach akzeptiert worden, was man jetzt nicht mehr so einfach loswerden kann.
D.h. wir werden wahrscheinlich bis in alle Ewigkeiten mit den Inkonsistenzen leben müssen. Ändern kann man das nicht einfach, da sonst der existierende Code nicht mehr funktioniert.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Auzug aus PEP 282 -- A Logging System
https://www.python.org/dev/peps/pep-0282/#id19Influences
This proposal was put together after having studied the following logging packages:
java.util.logging in JDK 1.4 (a.k.a. JSR047) [1]
log4j [2]
the Syslog package from the Protomatter project [3]
MAL's mx.Log package [4]
Vielen lieben Dank für Deine Antwort, mit der ich allerdings, entschuldige... gewisse Schwierigkeiten habe.
Darüber hinaus, ich weiß ja nicht... es erscheint mir ein bisschen hart, auf der Basis von Benamungen zu sagen, daß "diejenigen, die das implementiert haben, aus der Java-Welt kommen und ihr Paradigma auf Python übertragen haben". Sorry, aber eine Namenskonvention ist jetzt im Kontext von Programmiersprachen nicht gerade das, was ich unter dem Begriff "Paradigma" verstehe. Deswegen und in diesem speziellen Fall erscheint es mir mit Verweis auf das zuvor Gesagte allerdings sogar mehr als nur (zu) hart. Die Entwickler des Paketes waren von java.util.logging und log4j beeinflußt -- und sagen das auch ganz eindeutig. Man muß -- wie ich -- Java nicht mögen, aber wenn man fair bleiben will, muß man sagen: verglichen mit anderen Sprachen haben die wenigstens ein Logging, und sie haben ihr Loggingzeug auch vergleichsweise gut hinbekommen. Und wenn ich mir zum Beispiel die Konfiguration und solche Dinge anschaue, empfinde ich das "logging"-Package in Python sogar noch als deutliche Verbesserung. Da hätte es Python viel schlechter treffen und sich die Autoren des "logging"-Package viel schlechtere Vorbilder suchen können, finde ich...
Letzten Endes ist den Autoren des "logging"-Package also IMHO rein gar nichts vorzuwerfen, denn sie haben sich an die Konventionen gehalten. Daß die Autoren von PEP 8 mehrere Jahre später ihre Präferenzen geändert haben, liegt nicht an den Autoren des "logging"-Package.

Bitte entschuldige meinen Einwurf, aber die Entwickler HABEN sich an PEP 8 gehalten. Dort stand nämlich in Version a37771e3cb255950122f2294ac14b012d591c9f6 noch das Folgende:DeaD_EyE hat geschrieben: Montag 12. Juli 2021, 15:42 Wenn der Entwickler sich an PEP8 gehalten hätte, würde die Methode get_logger heißen und nicht getLogger.
Das sind Module gewesen, die ziemlich früh implementiert worden sind und am Anfang ist vieles einfach akzeptiert worden, was man jetzt nicht mehr so einfach loswerden kann.
Genau daran haben sich die Autoren des "logging"-Package auch präzise gehalten: "major functionality" wie logging.getLogger() in CapWords, '"utility" functions' wie logging.config.BaseConfigurator.cfg_convert() in Lowercase mit Underscores. Erst in Commit fef61c2a3911ffe08ad45ecc7da9f29c84475baa vom 20. März 2004 wurde diese Passage geändert in:Function Names
Plain functions exported by a module can either use the CapWords
style or lowercase (or lower_case_with_underscores). There is
no strong preference, but it seems that the CapWords style is
used for functions that provide major functionality
(e.g. nstools.WorldOpen()), while lowercase is used more for
"utility" functions (e.g. pathhack.kos_root()).
Nun, das "logging"-Package stammt von 2001, und eine der von Dir zitierten Formulierung ähnliche Aussage findet sich in PEP 8 erst seit 2004. Da finde ich es, mit Verlaub, ein wenig überzogen -- ehrlich gesagt, sogar unfair --, den Autoren des "logging"-Package vorzuwerfen, daß ihre Glaskugeln beschlagen waren und sie deswegen nicht in die Zukunft blicken konnten, sondern sich an die zur Entstehungszeit dokumentierten und empfohlenen Konventionen gehalten haben.Function Names
Function names should be lowercase, possibly with underscores to
improve readability. mixedCase is allowed only in contexts where
that's already the prevailing style (e.g. threading.py), to retain
backwards compatibility.
Darüber hinaus, ich weiß ja nicht... es erscheint mir ein bisschen hart, auf der Basis von Benamungen zu sagen, daß "diejenigen, die das implementiert haben, aus der Java-Welt kommen und ihr Paradigma auf Python übertragen haben". Sorry, aber eine Namenskonvention ist jetzt im Kontext von Programmiersprachen nicht gerade das, was ich unter dem Begriff "Paradigma" verstehe. Deswegen und in diesem speziellen Fall erscheint es mir mit Verweis auf das zuvor Gesagte allerdings sogar mehr als nur (zu) hart. Die Entwickler des Paketes waren von java.util.logging und log4j beeinflußt -- und sagen das auch ganz eindeutig. Man muß -- wie ich -- Java nicht mögen, aber wenn man fair bleiben will, muß man sagen: verglichen mit anderen Sprachen haben die wenigstens ein Logging, und sie haben ihr Loggingzeug auch vergleichsweise gut hinbekommen. Und wenn ich mir zum Beispiel die Konfiguration und solche Dinge anschaue, empfinde ich das "logging"-Package in Python sogar noch als deutliche Verbesserung. Da hätte es Python viel schlechter treffen und sich die Autoren des "logging"-Package viel schlechtere Vorbilder suchen können, finde ich...

Letzten Endes ist den Autoren des "logging"-Package also IMHO rein gar nichts vorzuwerfen, denn sie haben sich an die Konventionen gehalten. Daß die Autoren von PEP 8 mehrere Jahre später ihre Präferenzen geändert haben, liegt nicht an den Autoren des "logging"-Package.
Ach, ich weiß nicht... der Übergang von Python2 zu Python3 hätte vielleicht die Möglichkeit geboten, PEP 8 konsistent auch durch die Standardbibliotheken zu schleifen und die Abwärtskompatibilität dadurch zu erhalten, daß die alten, nicht PEP 8-konformen Namen als Aliasse der umbenannten Namen einstweilen erhalten bleiben und -- womöglich zunächst nur in Abhängigkeit von Kommandozeilenschaltern, bestimmten Runtime-Settings (think: "# -*- coding -*-" in Python oder "use strict;" in Perl) oder vielleicht auch nur in den Lintern -- eine DeprecationWarning werfen oder es zumindest in der Dokumentation als "deprecated" auszuzeichnen. Letzteres haben die Entwickler des oben in meinem zweiten Zitat aus PEP 8 genannten Moduls "threading" bereits genau so gemacht: die alten Methoden wie "Thread.isAlive()" sind als "deprecated" dokumentiert und als neuer Name wurde "Thread.is_alive()" eingeführt. Naja, wer weiß, vielleicht kommt das ja dann mit Python4.DeaD_EyE hat geschrieben: Montag 12. Juli 2021, 15:42 D.h. wir werden wahrscheinlich bis in alle Ewigkeiten mit den Inkonsistenzen leben müssen. Ändern kann man das nicht einfach, da sonst der existierende Code nicht mehr funktioniert.

- DeaD_EyE
- User
- Beiträge: 1240
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Nun, das "logging"-Package stammt von 2001, und eine der von Dir zitierten Formulierung ähnliche Aussage findet sich in PEP 8 erst seit 2004.
So etwas hatte ich bereits vermutet, aber nicht nachgesehen.Letzten Endes ist den Autoren des "logging"-Package also IMHO rein gar nichts vorzuwerfen, denn sie haben sich an die Konventionen gehalten. Daß die Autoren von PEP 8 mehrere Jahre später ihre Präferenzen geändert haben, liegt nicht an den Autoren des "logging"-Package.
Sie haben das Paradigma der Namensgebung mitgeschleppt. Die Namensgebung ist ein Hinweis darauf.Darüber hinaus, ich weiß ja nicht... es erscheint mir ein bisschen hart, auf der Basis von Benamungen zu sagen, daß "diejenigen, die das implementiert haben, aus der Java-Welt kommen und ihr Paradigma auf Python übertragen haben".
Die Möglichkeit hat man teilweise genutzt, indem man die Module umbenannt und zusammengefasst hat.Ach, ich weiß nicht... der Übergang von Python2 zu Python3 hätte vielleicht die Möglichkeit geboten, PEP 8 konsistent auch durch die Standardbibliotheken zu schleifen und die Abwärtskompatibilität dadurch zu erhalten, daß die alten, nicht PEP 8-konformen Namen als Aliasse der umbenannten Namen einstweilen erhalten bleiben und
Die hätten noch mehr machen können, wenn sie vorher gewusst hätten, wie lange der Wechsel dauert.
Sie sind von einer schnelleren Adaption ausgegangen.
Hinterher ist man immer schlauer.
Übrigens bin ich schon etwas länger dabei und Python gehört zu meiner Lieblingssprache.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Äh, die Namensgebung ist ein Hinweis auf die Namensgebung? Okaaayyy...DeaD_EyE hat geschrieben: Dienstag 13. Juli 2021, 12:51 Sie haben das Paradigma der Namensgebung mitgeschleppt. Die Namensgebung ist ein Hinweis darauf.

Und, naja... als sie das geschrieben haben, war das die empfohlene Namensgebung in PEP 8. Daß sie sich daran gehalten haben, hat wohl weniger mit irgendeinem Paradigma als mit der Einhaltung der damals geltenden Empfehlungen zu tun -- was man auch sehr schön daran erkennen kann, daß sie bei "utility functions" eben nicht irgendwelchen "Paradigmen" gefolgt sind und die Java-Konvention benutzt haben, sondern die heute in PEP 8 allgemein und damals für ebensolche Funktionen empfohlene Underscore-Konvention.
Ja, da hast Du natürlich Recht. Die Widerstände waren enorm, und bis heute sehe ich in verschiedenen Bereichen -- etwa im Mikrocontroller-Forum -- immer noch Leute, die Python2 benutzen und auf den Hinweis, daß das schon seit geraumer Zeit EOL ist und sie updaten sollten, mit schroffer Ablehnung reagieren. Angeblich seien immer noch nicht alle Libraries portiert (wobei auf die Frage, welche dieser Libraries sie denn benutzen und ob es dafür keinen Ersatz gibt, dann entweder nichts oder manchmal sogar ein Wutausbruch kommt), und diese schrecklichen "Inkonsistenzen"... Oh Mann.DeaD_EyE hat geschrieben: Dienstag 13. Juli 2021, 12:51 Die Möglichkeit hat man teilweise genutzt, indem man die Module umbenannt und zusammengefasst hat.
Die hätten noch mehr machen können, wenn sie vorher gewusst hätten, wie lange der Wechsel dauert.
Sie sind von einer schnelleren Adaption ausgegangen.
Hinterher ist man immer schlauer.
Same with me.DeaD_EyE hat geschrieben: Dienstag 13. Juli 2021, 12:51 Übrigens bin ich schon etwas länger dabei und Python gehört zu meiner Lieblingssprache.

- DeaD_EyE
- User
- Beiträge: 1240
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Ich meinte, dass die Namensgebung von Java im Python-Code ein Hinweis darauf ist, dass der Entwickler Java im Hinterkopf hatte.Äh, die Namensgebung ist ein Hinweis auf die Namensgebung? Okaaayyy...![]()
Das geschieht ganz unbewusst.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Naja, ich bin immer noch nicht so recht überzeugt, ob das unbedingt was mit Java zu tun haben muß... CamelCase hab' ich schon in Pascal, Smalltalk und C++ benutzt und manchmal sogar in C gesehen, da gab es noch gar kein Java. Nicht alles Böse auf der Welt ist von Java beeinflußt.DeaD_EyE hat geschrieben: Dienstag 13. Juli 2021, 17:33Ich meinte, dass die Namensgebung von Java im Python-Code ein Hinweis darauf ist, dass der Entwickler Java im Hinterkopf hatte.Äh, die Namensgebung ist ein Hinweis auf die Namensgebung? Okaaayyy...![]()
Das geschieht ganz unbewusst.
