Hallo zusammen,
habe dieses WE mit Python angefangen und bin bisher begeistert, wie einfach bestimmte Probleme dort gehandhabt werden.
Bisher habe ich unter VBA programmiert, möchte in Zukunft jedoch den größten Teil der Programme in Python schreiben.
Ist es möglich unter VBA Python aufzurufen, Probleme dort lösen zu lassen und den Rückgabewert wieder an VBA zu übergeben?
Habe ein bissel gegoogelt und dort ist das Modul "win32com" des Öfteren aufgetaucht. Bei mir scheint es jedoch nicht installiert zu sein. Wo lassen sich denn benötigte Module finden?
Gruß,
Jean
PS: Arbeite unter WinXP und Office 2003
VBA --> Python --> VBA?
- MoR4euZ
- User
- Beiträge: 34
- Registriert: Mittwoch 18. Oktober 2006, 21:21
- Wohnort: Essen
- Kontaktdaten:
das ist sicher dieses packet hier
http://sourceforge.net/projects/pywin32/
irgentwo gibt es auch ne online doku dazu
finde die nur nicht auf die schnelle
nach der instalation haste aufjeden fall eine doku
man kann COM objekts damit ansprechen
und viel spass noch mit python ich bin auch seit einigen wochen infiziert
http://sourceforge.net/projects/pywin32/
irgentwo gibt es auch ne online doku dazu
finde die nur nicht auf die schnelle
nach der instalation haste aufjeden fall eine doku
man kann COM objekts damit ansprechen
und viel spass noch mit python ich bin auch seit einigen wochen infiziert
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi JeanCantos!JeanCantos hat geschrieben:Ist es möglich unter VBA Python aufzurufen, Probleme dort lösen zu lassen und den Rückgabewert wieder an VBA zu übergeben?
Willkommen im Python-Forum!
Unter VBS (=Visual Basic Script) kannst du jedes Programm mit ``WScript.Shell.Exec`` aufrufen und die Rückgabe des Programms, also alles was in Python z.B. mit ``print`` ausgegeben wird, verwenden.
Siehe: http://www.microsoft.com/technet/commun ... g1002.mspx
Suche nach "WshScriptExec".
Unter VBA (=Visual Basic for Applications) und "Visual Basic 6" kannst du mit ``ShellWait`` ein Programm aufrufen und warten, bis es abgearbeite ist.
Siehe: http://www.aboutvb.de/khw/artikel/khwshell.htm
Du rufst also einfach vom VB aus das Python-Programm auf. Dabei kannst du Parameter übergeben, die du im Python mit dem Modul ``optparse`` auswerten kannst. Die Rückgabe des Python-Programms (``print``) leitest du in eine Datei um und liest diese Datei danach im VB-Programm aus. Das ist eine einfache Lösung, die ich schon hunderte mal in meinen Programmen eingesetzt habe.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ich würde es eher wie MoR4euZ vorschlägt mit COM versuchen, dass ist zwar etwas komplizierter, integriert sich aber viel besser in VB.gerold hat geschrieben:Du rufst also einfach vom VB aus das Python-Programm auf.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
-
- User
- Beiträge: 25
- Registriert: Sonntag 26. November 2006, 17:08
Hallo zusammen,
vielen Dank für eure Antworten. Für welche Methode ich mich entscheiden wäre, weiß ich noch nicht.
gerold, Danke für die Links. Ist n e Menge zeug. Magst Du mir den wichtigsten Code hier posten, wie ich aus VBA Python aufrufe und die Paramter übergebe und Rückgabewerte verwerte.
Gruß,
Jean
vielen Dank für eure Antworten. Für welche Methode ich mich entscheiden wäre, weiß ich noch nicht.
gerold, Danke für die Links. Ist n e Menge zeug. Magst Du mir den wichtigsten Code hier posten, wie ich aus VBA Python aufrufe und die Paramter übergebe und Rückgabewerte verwerte.
Gruß,
Jean
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi Jean!JeanCantos hat geschrieben:den wichtigsten Code hier posten
Hier schon mal der Python-Part:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
from optparse import OptionParser
import operator
import sys
def parse_options():
"""
Wertet die Argumente aus und gibt diese zurück
"""
# Usage-Text angeben und Parser-Objekt erzeugen
usage = (
u"%prog [--addieren | --subtrahieren] NUM [NUM] [...] [-d]\n\n"
u" Addiert oder subtrahiert die uebergebenen Nummern.\n\n"
u"Beispiel: %prog --addieren 100 200"
)
parser = OptionParser(usage = usage)
# Optionen hinzufuegen
parser.add_option(
"--addieren",
dest = "addieren",
action = "store_true",
default = True,
help = "Gibt an, dass die Zahlen addiert werden sollen (Standard)."
)
parser.add_option(
"--subtrahieren",
dest = "addieren",
action = "store_false",
help = "Gibt an, dass die Zahlen subtrahiert werden sollen."
)
parser.add_option(
"-d", "--debug",
dest = "debug",
action = "store_true",
default = False,
help = "show debug messages"
)
# Optionen parsen
(options, args) = parser.parse_args()
# Optionen und Argumente anzeigen
if options.debug:
print "Options:"
print options
print "-"*70
print "Arguments:"
for item in args:
print item
print "-"*70
# Rueckgabe
return (options, args)
def main():
# Optionen und Argumente parsen
(options, args) = parse_options()
args = [ float(arg) for arg in args ]
if options.addieren:
sys.stdout.write(str(reduce(operator.add, args)))
else:
sys.stdout.write(str(reduce(operator.sub, args)))
if __name__ == "__main__":
main()
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- User
- Beiträge: 25
- Registriert: Sonntag 26. November 2006, 17:08
Hallo zusammen,
habe mich heute etwas mit der Richtung "Python -> VBA" auseinander gesetzt und muss sagen, dass es bisher mehr oder weniger erfolgreich war. Habe den Code eines Users hier genommen, ein bissel rumgespielt und versucht zu verstehen.
Am Letzteren happert es noch ein bissel, aber ich bin guter Hoffnung.
Leider wird meine Excelanwendung mit DTCExcel.close nicht geschlossen. Mag mir jemand erklären, warum nicht.
Gruß,
Jean
PS: gerold, danke für den Code. Der sieht ja mächtig aus und ich irgendwie verstehe ich dort nur Bahnhof. Aber mir reicht es auch erst einmal, wenn ich ihn so übernehmen kann und mit meinem Code ergänzen kann, sodass ich die Probleme, die ich bisher unter VBA gelöst habe, nun mittels Python löse.
habe mich heute etwas mit der Richtung "Python -> VBA" auseinander gesetzt und muss sagen, dass es bisher mehr oder weniger erfolgreich war. Habe den Code eines Users hier genommen, ein bissel rumgespielt und versucht zu verstehen.
Am Letzteren happert es noch ein bissel, aber ich bin guter Hoffnung.
Code: Alles auswählen
import win32com.client
## Klassendefinition
class Excel:
def __init__(self,excelpath,Sheet):
self.excelobj = win32com.client.Dispatch("Excel.Application")
self.excelobj.Visible = False
self.wb = self.excelobj.Workbooks.Open(Filename = excelpath, ReadOnly = True)
self.ws = self.wb.Sheets(Sheet)
def ReturnValue(self,StartRange,EndRange):
return self.ws.Range(StartRange,EndRange)
def close(self):
del excelobj
## Hauptprogramm
#Oeffnet Excel Datei excel("Pfad und Dateiname mit / und nicht \!!!!,Auswahl des Sheet)
DTCExcel = Excel("D:\Test.xls", "Tabelle1")
Daten = DTCExcel.ReturnValue("A1","B2")
for item in range(0,len(Daten)):
print item,': ', Daten[item]
##Schließen von Excel
DTCExcel.close
Gruß,
Jean
PS: gerold, danke für den Code. Der sieht ja mächtig aus und ich irgendwie verstehe ich dort nur Bahnhof. Aber mir reicht es auch erst einmal, wenn ich ihn so übernehmen kann und mit meinem Code ergänzen kann, sodass ich die Probleme, die ich bisher unter VBA gelöst habe, nun mittels Python löse.
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hier wäre der "Visual Basic 6"-Teil des Codes.
- Neues Formular erstellen
- Quellcode des Formulars ersetzen
- Ausführen
Ich weiß, das ist eine harte Nuss.
Für die Verwendung in einem VBA-Programm braucht es nur ein paar kleine Änderungen.
mfg
Gerold
- Neues Formular erstellen
- Quellcode des Formulars ersetzen
- Ausführen
Code: Alles auswählen
Option Explicit
'************************************************************************
'Deklarationen um den Pfad zu einer temporären Datei heraus zu finden
'************************************************************************
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" ( _
ByVal nBufferLength As Long, _
ByVal lpBuffer As String _
) As Long
Private Declare Function GetTempFilename Lib "kernel32" Alias "GetTempFileNameA" ( _
ByVal lpszPath As String, _
ByVal lpPrefixString As String, _
ByVal wUnique As Long, _
ByVal lpTempFileName As String _
) As Long
'************************************************************************
'Deklarationen für ShellWait
'************************************************************************
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" ( _
ByVal hProcess As Long, ExitCode As Long _
) As Long
Private Declare Function OpenProcess Lib "kernel32" ( _
ByVal DesiredAccess As Long, ByVal InheritHandle As Long, ByVal ProcessId As Long _
) As Long
Public Sub Addiere()
Dim sPythonExe As String
Dim sFilename As String
Dim sParams As String
Dim sCommand As String
Dim sTempFilename As String
Dim sResult As String
sPythonExe = "J:\Python24\python.exe"
sFilename = App.Path & "\rechner.py"
sParams = "--addieren 10 20 30.5"
sTempFilename = GetTempFilenameVB()
sCommand = "%COMSPEC% /C " & sPythonExe & " """ & sFilename & """ " & sParams & " > """ & sTempFilename & """"
' Ausführen (unsichtbar)
Call ShellWait(sCommand, vbHide)
' Temp-File auslesen und das Ergebnis anzeigen
If FileExist(sTempFilename) Then
Open sTempFilename For Input As #1
Do While Not EOF(1)
sResult = sResult & Input(1, #1)
Loop
Close #1
If sResult = "" Then
MsgBox "Keine Daten als Ergebnis.", vbInformation, "Kein Ergebnis"
Else
Print sResult
End If
Else
MsgBox "Keine Daten als Ergebnis.", vbInformation, "Kein Ergebnis"
End If
' Temp-File löschen
If sTempFilename <> "" Then
If FileExist(sTempFilename) Then
Kill sTempFilename
End If
End If
End Sub
'****************************************************************************
'* Erstellt von: Gerold Penz Am: 28.05.1998 05:49:29
'* Beschreibung: Prüft ob eine Datei existiert
'****************************************************************************
Public Function FileExist(sDateiname As String) As Boolean
On Error GoTo FileExist_Fehler
FileExist = Dir$(sDateiname) <> ""
FileExist_Exit:
Exit Function
FileExist_Fehler:
FileExist = False
Resume Next
End Function
'***************************************************************************************************
'* Erstellt von: Gerold Penz Am: 10.06.2005 15:19:26
'* Beschreibung: Wie Shell, wartet aber bis der Prozess zuende ist und gibt
'* den Rückgabewert zurück
'* Rückgabe: Errorlevel des aufgerufenen Prozesses
'* Parameter: sExec = Programmaufruf
'* WindowStyle = Maximiert, Normal im Vordergrund, ...
'***************************************************************************************************
Public Function ShellWait( _
ByVal sExec As String, _
Optional ByVal WindowStyle As VbAppWinStyle = vbMinimizedFocus _
) As Long
Dim nTaskId As Long
Dim nHProcess As Long
Dim nExitCode As Long
Dim objRE As Object 'VBScript_RegExp_55.RegExp
Dim L As Long
Dim MCol As Object 'VBScript_RegExp_55.MatchCollection
Const STILL_ACTIVE = &H103
Const PROCESS_QUERY_INFORMATION = &H400
'*******************************************************************************
'Umgebungsvariablen ersetzen
'*******************************************************************************
Set objRE = CreateObject("VBScript.RegExp")
objRE.IgnoreCase = True
objRE.MultiLine = True
objRE.Global = True
If objRE.Test(sExec) Then
objRE.Pattern = "\%.*?\%"
Set MCol = objRE.Execute(sExec)
If MCol.Count > 0 Then
For L = 0 To MCol.Count - 1
Set objRE = CreateObject("VBScript.RegExp")
objRE.IgnoreCase = True
objRE.MultiLine = True
objRE.Global = True
objRE.Pattern = Replace(MCol(L), "%", "\%")
sExec = objRE.Replace( _
sExec, _
Environ$( _
Right(Left(MCol(L), Len(MCol(L)) - 1), Len(MCol(L)) - 2) _
) _
)
Next L
End If
End If
'*******************************************************************************
'Ausführen
'*******************************************************************************
nTaskId = Shell(sExec, WindowStyle)
nHProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, nTaskId)
Do
DoEvents
GetExitCodeProcess nHProcess, nExitCode
Loop While nExitCode = STILL_ACTIVE
CloseHandle nHProcess
ShellWait = nExitCode
Exitbereich:
On Error Resume Next
Set MCol = Nothing
Set objRE = Nothing
Exit Function
End Function
'***************************************************************************************************
'* Erstellt von: Gerold Penz Am: 22.04.2001 21:14:50
'* Beschreibung: Gibt einen freien Dateinamen für eine temporäre Datei zurück
'* Rückgabe: Dateiname
'***************************************************************************************************
Public Function GetTempFilenameVB() As String
Dim sTempPath_ As String * 256
Dim sTempPath As String
Dim sTempFile_ As String * 256
Dim sTempFile As String
Dim L As Long
Dim sRandom As String
'************************************************************************
'Temporäre Datei herausfinden
'************************************************************************
Randomize
sRandom = CStr(Int((9999 * Rnd) + 1000)) ' Zufallszahl im Bereich von 1000 bis 9999 generieren.
L = GetTempPath(255, sTempPath_)
sTempPath = Left(sTempPath_, InStr(1, sTempPath_, Chr$(0)) - 1)
L = GetTempFilename(sTempPath, sRandom, 1, sTempFile_)
GetTempFilenameVB = Left(sTempFile_, InStr(1, sTempFile_, Chr$(0)) - 1)
End Function
Private Sub Form_Activate()
Static B As Boolean
If Not (B) Then
B = True
Call Addiere
End If
End Sub
Für die Verwendung in einem VBA-Programm braucht es nur ein paar kleine Änderungen.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
-
- User
- Beiträge: 25
- Registriert: Sonntag 26. November 2006, 17:08
Hallo gerold,
danke erst einmal für deine Hilfe und den Code.
Im Augenblick werde ich jedoch von ihm erschlagen und weiß nicht so recht, ob ich mein Anliegen eventuell missverständlich ausgedrückt habe.
Ich habe eher an folgende Vorgehensweise gedacht:
- Ich übergebe in einer Zelle (z.B. "B3) an ein Makro.
- In dem Makro übergebe ich den Inhalt von B3 nun an Python.
- Python bearbeitet den Inhalt von B3
- Python gibt das Resultat der Bearbeitung an mein Makro zurück
- Das Makro schreib das Ergebnis in eine entsprechende Spalte
Ich versuche es einmal an einem einfachen Beispiel zu verdeutlichen:
Stell Dir vor, ich möchte die Zellen B3 bis B26 jeweils mit 5 muliplizieren und in Zelle C3 bis C26 schreiben. Also schreibe ich in Zelle C3 meine Formel "=MultiBlaBla(B3)" auf und ziehe diese Zelle in Excel nun bis C26.
In Python möchte ich nun diese Multiplikation erledigen lassen.
Wie sieht das Prozedere hierbei nun aus?
Wenn ich es anhand dieses einfachen Beispiels verstanden habe, denke ich, dass ich auch komplexere Probleme lösen kann.
Gruß,
Jean
danke erst einmal für deine Hilfe und den Code.
Im Augenblick werde ich jedoch von ihm erschlagen und weiß nicht so recht, ob ich mein Anliegen eventuell missverständlich ausgedrückt habe.
Ich habe eher an folgende Vorgehensweise gedacht:
- Ich übergebe in einer Zelle (z.B. "B3) an ein Makro.
- In dem Makro übergebe ich den Inhalt von B3 nun an Python.
- Python bearbeitet den Inhalt von B3
- Python gibt das Resultat der Bearbeitung an mein Makro zurück
- Das Makro schreib das Ergebnis in eine entsprechende Spalte
Ich versuche es einmal an einem einfachen Beispiel zu verdeutlichen:
Stell Dir vor, ich möchte die Zellen B3 bis B26 jeweils mit 5 muliplizieren und in Zelle C3 bis C26 schreiben. Also schreibe ich in Zelle C3 meine Formel "=MultiBlaBla(B3)" auf und ziehe diese Zelle in Excel nun bis C26.
In Python möchte ich nun diese Multiplikation erledigen lassen.
Wie sieht das Prozedere hierbei nun aus?
Wenn ich es anhand dieses einfachen Beispiels verstanden habe, denke ich, dass ich auch komplexere Probleme lösen kann.
Gruß,
Jean
Ungetestet, aber so sollte es funktionieren.JeanCantos hat geschrieben:Leider wird meine Excelanwendung mit DTCExcel.close nicht geschlossen. Mag mir jemand erklären, warum nicht.
Code: Alles auswählen
import win32com.client
## Klassendefinition
class Excel:
def __init__(self,excelpath,Sheet):
self.excelobj = win32com.client.Dispatch("Excel.Application")
self.excelobj.Visible = False
self.wb = self.excelobj.Workbooks.Open(Filename = excelpath, ReadOnly = True)
self.ws = self.wb.Sheets(Sheet)
def ReturnValue(self,StartRange,EndRange):
return self.ws.Range(StartRange,EndRange)
def close(self):
self.excelobj.Quit()
del self.excelobj
## Hauptprogramm
#Oeffnet Excel Datei excel("Pfad und Dateiname mit / und nicht \!!!!,Auswahl des Sheet)
DTCExcel = Excel("D:\Test.xls", "Tabelle1")
Daten = DTCExcel.ReturnValue("A1","B2")
for item in range(0,len(Daten)):
print item,': ', Daten[item]
##Schließen von Excel
DTCExcel.close()
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.
Wie man Fragen richtig stellt
Außerdem gibt es eine irrationale.
Wie man Fragen richtig stellt
-
- User
- Beiträge: 25
- Registriert: Sonntag 26. November 2006, 17:08
Hi MoR4euZ,
lässt sich denn das Modul win32.client auch einbinden, ohne das komplette Paket PyWin zu installieren?
Welcher Entwicklungsumgebung ist denn für Python zu empfehlen. Der PyWin Editor gefällt mir irgendwie nicht.
Gruß,
Jean
lässt sich denn das Modul win32.client auch einbinden, ohne das komplette Paket PyWin zu installieren?
Welcher Entwicklungsumgebung ist denn für Python zu empfehlen. Der PyWin Editor gefällt mir irgendwie nicht.
Gruß,
Jean
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Nein.JeanCantos hat geschrieben:lässt sich denn das Modul win32.client auch einbinden, ohne das komplette Paket PyWin zu installieren?
vim, SciTE, etc. Aber such mal im Forum, denn sowas wird wirklich oft gefragt und es macht keinen Sinn das immer neu auszudiskutieren.JeanCantos hat geschrieben:Welcher Entwicklungsumgebung ist denn für Python zu empfehlen. Der PyWin Editor gefällt mir irgendwie nicht.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
- gerold
- Python-Forum Veteran
- Beiträge: 5555
- Registriert: Samstag 28. Februar 2004, 22:04
- Wohnort: Oberhofen im Inntal (Tirol)
- Kontaktdaten:
Hi Jean!JeanCantos hat geschrieben:Stell Dir vor, ich möchte die Zellen B3 bis B26 jeweils mit 5 muliplizieren und in Zelle C3 bis C26 schreiben. Also schreibe ich in Zelle C3 meine Formel "=MultiBlaBla(B3)" auf und ziehe diese Zelle in Excel nun bis C26.
In Python möchte ich nun diese Multiplikation erledigen lassen.
Wie sieht das Prozedere hierbei nun aus?
Schwierige Sache!!! Es ist nämlich so, dass du dir ziemlich schnell die Geschwindigkeit von Excel zusammen hauen kannst.
Die Methode, die ich vorgeschlagen habe, läuft ja so, dass jedes Kommandozeilenprogamm (nicht nur Python-Programme) damit aufgerufen werden kann. Allerdings ist jeder Aufruf ein neuer Prozess. Zuerst wird also Python gestartet und dann das Python-Skript abgearbeitet. Wenn du eine Funktion in ein paar hundert Excel-Zellen drinnen hast, dann wird die Neuberechnung der Zellen quälend langsam.
Die schnellere Methode wäre, wenn du dir ein COM-Serverprogramm schreiben würdest. Wie das funktioniert, findest du in der Hilfe zu "pywin32" (Suche nach "COM"; nur Titel). Ohne "pywin32" bist du unter Windows sowiso aufgeschmissen. Das musst du sowiso installieren. -- Ist also kein Nachteil! COM hat den faden Beigeschmack, dass es nur unter Windows funktioniert. -- Excel funktioniert auch "nur" unter Windows, also ist das kein so großes Problem.
Der (für mich) größte Nachteil ist, dass ein COM-Serverprogramm in der Registry registriert werden muss. Das ist zwar sehr einfach, aber es katapultiert dich wieder in die DLL-Hell zurück. Man weiß nie, welche DLL jetzt gerade aktuell registriert ist... Du musst also sicher stellen, dass die gewünschte Python-Datei zuerst registriert wird, bevor du damit korrekt arbeiten kannst.
Allerdings ist es dadurch möglich, das Python-Programm nur einmal zu laden und die Funktionen mehrfach auszuführen. Das ist wesentlich schneller als der Aufruf über die Kommandozeile.
Wenn du also eine Python-Funktion *oft* aufrufen musst, dann kommst du um COM nicht herum. Die Kommandozeilen-Schnittstelle, die ich weiter oben aufgezeigt habe, verwende ich nur in reinen "Visual Basic 6"-Programmen und nur zum Aufrufen von Tools, Berichten, Auswahldialogen, usw. Da kommt es nicht auf Geschwindigkeit an.
mfg
Gerold
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.