Klasse zur Primfactor-zerlegung und zum primzahlen errechnen

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Samstag 20. September 2008, 00:05

Hio, ich hab ne Klasse für Primfactor-zerlegung und Primzahlen-errechnung
geschrieben, die ich mal publizieren wollte :)

Code: Alles auswählen

#!/usr/bin/python
# Author [Editiert]
# License noch keine aber auf jedenfall GPL kompatibel :)
# Object, das primzahlen generieren, 
# und/oder zahlen in ihre primfactoren zerlegen kann
# keine ahnung was man noch so schreibt, viel Spaß ;)

class Primops(object):
	"""
		handles two prim-operations
	"""
	counter = 0
	def __init__(self, prims = [2]):
        self.prims = prims
		if self.prims[-1] > 2: self._proof = self.prims[-1]  +2
        else: self._proof = 3
	
	def generate(self):
		"""
			tests if _proof is a prim
		"""
		for prim in self.prims:
			if ( self._proof % prim ) == 0:
				self._proof += 2
				return False
			elif ( self._proof / prim ) < prim:
				self.prims.append(self._proof)
				self._proof += 2
				return True

	def loop(self, max = 1):
		"""
			generates new prim's
		"""
		if max == 1:
			while max:
				if self.generate(): print self.prims[-1]
		elif max > self._proof:
			while max > self._proof:
				if self.generate(): print self.prims[-1]

	
	def aktuell(self):
		"""
			returns the aktuell used prim

			is used by split only
		"""
		return self.prims[self.counter]

	def count(self):
		"""
			next prim

			is used by split only
		"""
		self.counter += 1
	
	def cycle(self):
		"""
			begin with the first prime

			is used by split only
		"""
		self.counter = 0

	def split(self, number):
		"""
			splits a number into its factors
			and returns all factors
		"""
		self._number = number
		self.splits = []
		while 1:
			try: self.prim = self.aktuell()
			except:
				self.generate()
				continue
			if ( self._number % self.prim ) == 0:
				self.splits.append(self.prim)
				self._number /= self.prim
				self.cycle()
			elif ( self._number / self.prim ) < self.prim:
				if self._number != 1: self.splits.append(self._number)
				self.cycle()
				return self.splits
			else: self.count()
Zuletzt geändert von Leonidas am Freitag 16. Mai 2014, 12:55, insgesamt 1-mal geändert.
Grund: Name auf verlangen editiert.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Samstag 20. September 2008, 07:22

Ein paar Anmerkungen dazu:

Die von dir gewählten Bezeichner für die einzelnen Methoden sind überwiegend nicht geglückt. Dass "loop" Primzahlen erzeugt und ausgibt, legt die Bezeichnung nicht nahe. Vielleicht solltest du es mal mit deutschen Bezeichnern versuchen. (Primzahl heißt im engl. übrigens prime)

Hilfreich ist es auch, wenn man aus dem Methodennamen erschließen kann, ob die Methode z.B. Werte ausgibt (so wie loop) oder etwas zurückliefert (so wie split). Also z.B. print_primes() und get_factorlist().

Du solltest die Methoden kennzeichnen nach privaten Methoden und öffentlichen Methoden, indem du die privaten mit einem führenden Unterstrich beginnst. So braucht man nicht lange zu überlegen, ob, wofür und wann man z.B. generate() aufrufen muss (nämlich gar nicht, weil es eine private Methode ist).

Zwar ist es zulässig, nach einem Doppelpunkt in der gleichen Zeile fortzufahren, aber es ist unüblich und trägt nicht zur besseren Lesbarkeit eines Quelltextes bei.

Die Variable counter in Zeile 14 wird nicht verwendet. Wenn du sie außerhalb einer Methode innerhalb der Klasse definierst, ist es eine Klassenmethode, die über den Klassennamen angesprochen wird. Mit der Objektvariablen self.counter hat die nichts zu tun - die wird bei dir erstmals in cycle() definiert.

Methoden, deren Rumpf nur aus einer einzigen Anweisung bestehen, sind in aller Regel überflüssig (es sei denn, man beabsichtigt, noch weitere Funktionalität hinzuzufügen). Also: cycle(), count() und aktuell() können weg.

Die Klammern bei deinen bedingten Anweisungen sind nicht nötig.

Ein allgemeines except ohne Angabe des Ausnahmetyps sollte man vermeiden. In deinem Fall wäre es ein IndexError beim Zugriff auf die Liste.

Statt "while 1:" sollte man "while True:" schreiben. Das liest sich besser.
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Samstag 20. September 2008, 13:38

Danke für Verbesserungen, ich habe das Programm so weit wie möglich verändert,
damit es lesbarer wird. Das variablen die außerhalb von Funktionen deklariert werden
ausschließlich über den Klassennamen angesprochen werden können war mir bis jetzt
auch nicht bewusst, erklärt aber einige Fehler in anderen Programmen ^^ thx

hier die überarbeitete version:

Code: Alles auswählen

#!/usr/bin/python
# Author [Editiert]
# License noch keine aber auf jedenfall GPL kompatibel :)
# Object, das primzahlen generieren, 
# und/oder zahlen in ihre primfactoren zerlegen kann
# keine ahnung was man noch so schreibt, viel Spass ;)

class Primops(object):
	"""
		handles two prim-operations
	"""
	def __init__(self, primes = [2]):
		self.primes = primes
		
		if self.primes[-1] > 2:
			self._proof = self.primes[-1] +2
		
		else: 
			self._proof = 3


	def _test(self):
		"""
			tests if _proof is a prim
		"""
		for prime in self.primes:
			
			if self._proof % prime == 0:
				self._proof += 2
				return False
			
			elif self._proof / prime < prime:
				self.primes.append(self._proof)
				self._proof += 2
				return True


	def generate_primes(self, max = 1):
		"""
			generates new primes
		"""
		
		if max == 1:
			while max:
				if self._test(): 
					print self.primes[-1]
		
		elif max > self._proof:
			while max > self._proof:
				if self._test(): 
					print self.primes[-1]


	def get_factors(self, number):
		"""
			splits a number into its factors
			and returns all factors
		"""
		
		self._counter = 0
		self._number = number
		self._splits = []
		
		while True:
			
			try: 
				self._prime = self.primes[self._counter]
			
			except: # index_error in self.primes
				self._test()
				continue
			
			if self._number % self._prime == 0:
				self._splits.append(self._prime)
				self._number /= self._prime
				self._counter = 0
			
			elif self._number / self._prime < self._prime:
				if self._number != 1: 
					self._splits.append(self._number)
				return self._splits
			
			else:
				self._counter += 1
Zuletzt geändert von Leonidas am Freitag 16. Mai 2014, 12:55, insgesamt 1-mal geändert.
Grund: Name auf verlangen editiert.
lunar

Samstag 20. September 2008, 13:54

Betreffend: Zeile 70

Code: Alles auswählen

except: # index_error in self.primes
"except IndexError:", dann weiß auch der Interpreter, dass hier nur IndexError abgefangen werden soll.

Ob die Primfaktorzerlegung nun ein geeignetes Beispiel für eine Klasse ist, sei mal dahingestellt ...
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Samstag 20. September 2008, 14:40

@lunar ahh ok :) ist ja praktisch dass man auch einzelne Fehler abfangen kann.
iss ne Klasse, weil man auf Klassen so schön aufbauen kann, ohne den quältext neu zu schreiben, müsste mal ausprobieren, wie viel schneller der ist wenner "glatt" runtergeschrieben wird. Allgemein bin ich mit der geschwindigkeit aber ganz zufrieden.
Jetzt wird noch eine Funktion hinzugefügt, um einzelne zahlen zu prüfen ;)
lunar

Samstag 20. September 2008, 15:27

nuss hat geschrieben:@lunar ahh ok :) ist ja praktisch dass man auch einzelne Fehler abfangen kann.
Das steht unter anderem auch im Tutorial ...
iss ne Klasse, weil man auf Klassen so schön aufbauen kann, ohne den quältext neu zu schreiben
Man kann auch Funktionen mehrfach aufrufen ...
müsste mal ausprobieren, wie viel schneller der ist wenner "glatt" runtergeschrieben wird. Allgemein bin ich mit der geschwindigkeit aber ganz zufrieden.
Das hat nichts mit der Ausführungsgeschwindigkeit zu tun, sondern einfach damit, dass eine Primfaktorzerlegung auch wunderbar als Funktion geschrieben werden kann, da braucht es keine Klasse. Im "math"-Modul liegen schließlich auch Funktionen ...
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Dienstag 28. Oktober 2008, 16:46

hey hey ich meld mich nochmal nach laengerem ;)

hab den ganzen generator nochmal ueberarbeitet und mit funktionen geschrieben.
http://paste.pocoo.org/show/89307/
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Dienstag 28. Oktober 2008, 17:23

Hab jetzt auch mal was probiert: http://paste.pocoo.org/show/89313/. Wenn das Argument eine Primzahl ist, wird True zurückgegeben, sonst wird eine Liste mit den Faktoren zurückgegeben.
Zuletzt geändert von derdon am Dienstag 28. Oktober 2008, 20:57, insgesamt 1-mal geändert.
DasIch
User
Beiträge: 2465
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Dienstag 28. Oktober 2008, 17:50

nuss hat geschrieben:hab den ganzen generator nochmal ueberarbeitet und mit funktionen geschrieben.
http://paste.pocoo.org/show/89307/
Da kommen mindest 8 `global`s zu viel drin vor.
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Mittwoch 29. Oktober 2008, 09:50

DasIch hat folgendes geschrieben:
nuss hat folgendes geschrieben:
hab den ganzen generator nochmal ueberarbeitet und mit funktionen geschrieben.
http://paste.pocoo.org/show/89307/

Da kommen mindest 8 `global`s zu viel drin vor.
Da kommt genau 8 mal global drin vor ;)
Was iss den so schlecht an global ?
cache und proof sind ja instanzen von dem modul aus dem ich get_factors etc. importiere.
Sprich ich kann in einem anderen programm trotzdem noch
ein cache definieren, ohne mit dem cache aus dem modul in konflikt zu kommen.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 29. Oktober 2008, 09:58

nuss hat geschrieben:Da kommt genau 8 mal global drin vor ;)
Was iss den so schlecht an global ?
Es führt zu schlecht verständlichen Spaghetticode der zudem auch noch die tollsten Probleme mit Threading verursachen kann. Es gibt fast keinen Code wo man nicht mit Rückgabewerten arbeiten kann statt der globals. Das es die gibt, vergisst du am besten gleich wieder.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Mittwoch 29. Oktober 2008, 13:33

ok ok überzeugt :cry:
habs angepasst.
http://paste.pocoo.org/show/89398/
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 29. Oktober 2008, 13:40

nuss hat geschrieben:habs angepasst.
So, und nun PEP8 lesen und anwenden ;)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
nuss
User
Beiträge: 53
Registriert: Donnerstag 28. August 2008, 11:36

Mittwoch 29. Oktober 2008, 16:11

sooo..... ich hab gerade PEP8 gelesen und den Code angepasst.
Ich hoffe das der jetzt größtenteils kompatibel ist.
Vor allem hoffe ich dass die Docstrings auch für Engländer halbwegs verständlich sind.
http://paste.pocoo.org/show/89415/

Was mir eben noch aufgefallen ist, ist dass die funktionen anscheinend die bereits errechneten primzahlen speichern.... wie kommt das ? :shock:
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Mittwoch 29. Oktober 2008, 16:18

nuss hat geschrieben:Was mir eben noch aufgefallen ist, ist dass die funktionen anscheinend die bereits errechneten primzahlen speichern.... wie kommt das ? :shock:
Das liegt daran, dass die default-Werte für "cache" alle mutable sind. Da diese nur einmal erzeugt werden arbeitest du immer auf der selben liste. Lösen kannst du das, indem du als Parameter "cache=None" verwendest und in der Funktion "if cache ist None: cache=[2]" hinzufügst.

"get_factors" und "isprime" sehen so aus, als könnte man sie in Teilen zusammenfassen.

Deine Einrückung ist ein wenig in Mitleidenschaft gezogen. Du solltest nicht Leerzeichen mit Tabs vermischen.
Antworten