Benutzung einer Klasse anstatt eines Dicts

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
ZedsWhatSheSaid
User
Beiträge: 8
Registriert: Donnerstag 12. September 2013, 11:00

So ich habe jetzt eine Klasse geschrieben die für dich warscheinlich keinen sinn ergibt und total blöd ist xD ich habe das jetzt einfach so versucht wie ich denke dass es funktionieren könnte und wollte fragen ob du mir sagen kannst ob es fehler gibt die man beheben kann oder ob der code an sich schrott ist ^^

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import re

class Company(object):
        @staticmethod
        def Companies(self, name, founding_year, number_of_employee):
                self.name = name
                self.founding_year = founding_year
                self.number_of_employee = number_of_employee
                for line in open('/home/ibrahim/Desktop/Test.list'):
                        name, founding_year, number_of_employee = line.split(',')
                        number, comp = name.split(')')
                        Companies[comp] = [comp, founding_year, number_of_employee]
                        print 'Company: %s' % name


print Company.Companies
Edit: Wenn ich mein Programm debugge gibt es sogar was aus :lol: <function Companies at 0x7f107afd85f0>
BlackJack

@ZedsWhatSheSaid: Programmentwicklung funktioniert nicht in dem man irgendetwas hin schreibt und hoffst, dass das dann funktioniert. Die ”Klasse” ist in der Tat völlig sinnlos.

Am besten schreibt man Programme, insbesondere Anfänger, „bottom up”. Also mit den Grundlegenden Datentypen und Funktionen zuerst. So kann man jede einzelne Funktion, Klasse, und Methode testen und erst mit der nächsten weiter machen wenn das bis dahin geschriebene Funktioniert. So baut man ein Programm aus bereits getesteten Bausteinen zusammen. Dafür zerlegt man das Problem in Teilprobleme bis die so klein/einfach sind, dass man sie einfach in Code lösen kann.

An Datentypen gibt es `Company` und `Companies`. Der grundlegendere von beiden ist `Company` denn man kann `Companies` nicht programmieren ohne das man `Company` bereits als Datentyp hat, denn man braucht `Company`-Objekte um sie in `Companies` zu verwalten. Jetzt musst Du Dir überlegen welche Daten ein `Company`-Objekt braucht, und dann kannst Du eine `__init__()`-Methode dafür schreiben, mit der man so ein Objekt erstellen kann. Wenn man es erstellen kann, kann man sich überlegen wie die Ausgabe als Zeichenkette aussehen soll und kann die `__str__()`-Methode entsprechend umsetzen. Jetzt kann man schon mal testen ob das Erstellen eines `Company`-Objekts mit festen Argumenten und die anschliessende Ausgabe mit ``print`` so funktionieren wie man sich das gedacht hat.

Als nächstes möchte man ein `Company`-Objekt nicht aus einzelnen Argumenten erstellen, sondern aus einer Zeile, also Zeichenkette aus der Eingabedatei. Dafür kann man sich eine Funktion schreiben, die so eine Zeile als Argument bekommt, die in ihre Bestandteile zerlegt, die Datentypen umwandelt, und damit dann ein `Company`-Objekt erstellt und das zurück gibt. Das kann man mit einer festen Zeichenkette testen, oder schon mit einer Schleife über die Datei in dem man einfach jede Zeile nimmt, damit die Funktion aufruft, und das zurückgegebene `Company`-Objekt ausgibt.

Wenn das alles bis dahin funktioniert kann man anfangen die `Companies`-Klasse zu entwerfen und dann ebenfalls Stück für Stück zu implementieren und bei jeder Operation zu testen ob das soweit funktioniert wie man das geplant hat.
BlackJack

Ich habe das mal in Clojure umgesetzt, weil ich mir die Sprache gerade anschaue. `Companies` ist dabei eine Abbildung (`hash-map`) geblieben, also das was in Python ein Wörterbuch (`dict()`) wäre, weil das sonst IMHO zu viel unnötiger Aufwand wäre das in eine Klasse (Record) zu stecken.

Code: Alles auswählen

(ns companies
    (:require [clojure.string :as string]
     :require [clojure.data.json :as json]))


(defn input [prompt] (print prompt) (flush) (read-line))


(defrecord Company [name founding-year employee-count]
    Object
    (toString [_] (str name " exists since " founding-year " and has "
        employee-count " employees.")))

(defn parse-company [line]
    (let [[name year count]
            (string/split (subs line (inc (.indexOf line ")"))) #",")]
        (->Company name (read-string year) (read-string count))))


(def ->Companies hash-map)

(defn add-company [companies company] (assoc companies (:name company) company))

(def get-company get)

(defn load-companies [filename]
    (with-open [reader (clojure.java.io/reader filename)]
        (reduce
            add-company (->Companies) (map parse-company (line-seq reader)))))

(defn companies-as-json [companies] (json/write-str (vals companies)))


(defn -main []
    (let [companies (load-companies "test.txt")
          company (get-company companies (input "Enter company name: "))]
        (println (if company (str company) "No company by that name."))
        (newline)
        (println (companies-as-json companies))))
Wenn ich das richtig verstanden habe dann braucht man in Clojure für Klassen zwingend ein Protokoll für die Methoden‽ In Java-sprech also zu jeder Klasse zwingend ein Interface‽ Das fänd ich ja mal krass nervend.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

BlackJack hat geschrieben:Wenn ich das richtig verstanden habe dann braucht man in Clojure für Klassen zwingend ein Protokoll für die Methoden‽ In Java-sprech also zu jeder Klasse zwingend ein Interface‽ Das fänd ich ja mal krass nervend.
In Clojure nutzt man auch Klassen kaum und du kannst dir ja problemlos ein Makro schreiben dass das zusammenfasst, nicht so wie in Java.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@Leonidas: Heisst das man benutzt eine Mischung aus `defrecord` und Methoden darauf um dem zum Beispiel eine Zeichenkettendarstellung beizubringen oder eine Vergleichsfunktion zu definieren und Funktionen auf der anderen Seite oder nutzt man auch `defrecord` schon nicht, und hat damit kein polymorphes `.toString` was mit `str` verwendbar ist. `defrecord` erstellt ja letztlich eine Klasse.

Das man sich ja ein Makro schreiben kann finde ich oft ein schwaches Argument für Sachen die „selbstverständlich” sind, weil sich dann jeder Programmierer Makros für die gleichen Sachen schreibt, aber alle unterschiedlich heissen und geringfügig anders funktionieren. Dabei könnte man das leicht lösen wenn man zusätzlich zu den Protokollen und Klassen auch `nil` erlauben würde wo man dann Methoden schreiben kann, die ausschliesslich zu dem Objekt gehören. Oder man erlaubt auch ein Keyword, damit es lesbarer und erweiterbar bleibt.
BlackJack

Ich hoffe es kommt nicht gleich wieder ein erboster Dozent vorbei, aber so könnte man das in Python und OOP schreiben:

Code: Alles auswählen

#!/usr/bin/env python
import json
from itertools import imap


class Company(object):
    
    def __init__(self, name, founding_year, employee_count):
        self.name = name
        self.founding_year = founding_year
        self.employee_count = employee_count
    
    def __str__(self):
        return (
            '{0.name} exists since {0.founding_year:d}'
            ' and has {0.employee_count:d} employees'.format(self)
        )

    def __cmp__(self, other):
        return cmp(self.name, other.name)

    def __hash__(self):
        return hash(self.name)

    def as_dict(self):
        return {
            'name': self.name,
            'foundingYear': self.founding_year,
            'employeeCount': self.employee_count
        }

    @classmethod
    def parse(cls, line):
        _number, row = line.split(')')
        name, founding_year, employee_count = row.split(',')
        return cls(name, int(founding_year), int(employee_count))


class Companies(object):
    
    def __init__(self):
        self.name2company = dict()

    def __len__(self):
        return len(self.name2company)

    def __iter__(self):
        return self.name2company.itervalues()

    def __getitem__(self, name):
        return self.name2company[name]

    def add(self, company):
        self.name2company[company.name] = company

    def as_json(self):
        return json.dumps([c.as_dict() for c in sorted(self)], indent=2)

    @classmethod
    def load(cls, filename):
        result = cls()
        with open(filename) as lines:
            for company in imap(Company.parse, lines):
                result.add(company)
        return result


def main():
    companies = Companies.load('test.txt')

    company_name = raw_input('Enter company name: ')
    try:
        company = companies[company_name]
    except KeyError:
        print 'No company by that name.'
    else:
        print company
    
    print companies.as_json()


if __name__ == '__main__':
    main()
Antworten