Python: Unterschied zwischen den Versionen

Aus Info-Theke
Zur Navigation springen Zur Suche springen
(36 dazwischenliegende Versionen von 7 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
[[Kategorie:Sprache]]
[[Kategorie:Sprache]]
= Links =
* [[Jupyter]]
* https://www.python.org/downloads/windows/
= Exception =
= Exception =
<pre>
<syntaxhighlight lang="python">
try:
try:
   raise Exception("not allowed")
   raise Exception("not allowed")
Zeile 14: Zeile 18:
finally:
finally:
   closeIt()
   closeIt()
</pre>
</syntaxhighlight>


= Regular Expression =
= Regular Expression =
<pre>
<syntaxhighlight lang="python">
import re
import re
rexpr = re.compile(r"([\da-z]+)")
rexpr = re.compile(r"([\da-z]+)")
Zeile 23: Zeile 27:
if match != None:
if match != None:
   number = (int) rexpr.group(1)
   number = (int) rexpr.group(1)
</pre>
# Replacement:
regex = re.compile(r"A\d+", re.IGNORECASE)
for line in some_file:
    other = regex.sub('<Id>', line)
# Replacement mit Referenzen:
s = 'aaa@xxx.com bbb@yyy.net ccc@zzz.org'
re.sub('([a-z]+)@([a-z]+)', r'\2@\1', s)
</syntaxhighlight>


= Datentypen =
= Datentypen =
== String ==
== String ==
* "x" und 'x' sind gleichwertig
* "x" und 'x' sind gleichwertig
* Formatierung
=== Formatierung ===
<pre>
* f-String
<syntaxhighlight lang="python">
# Gleitpunktzahl mit 3 Stellen ausgeben:
f'{self.floatValue:.3f}'
# 2-stellig mit führender 0 ausgeben:
f'{sec//3600}:{sec%3600//60:02}:{sec%60:02}'
# String linksbündig:
f'{data:<10}'
# String rechtsbündig:
f'{data:>10}'
</syntaxhighlight>
* str.format()
<syntaxhighlight lang="python">
"{:3.7f} {:s} {:07d}".format(3.14, "hello", 100)
"{:3.7f} {:s} {:07d}".format(3.14, "hello", 100)
"{0:d} / {0:x}".format(714)
"{0:d} / {0:x}".format(714)
"{}-{}: {}".format('abc.txt', 9, 7.99)
"{}-{}: {}".format('abc.txt', 9, 7.99)
</pre>
precision=2
'{:.Pf}'.replace('P', str(precision)).format(value)
</syntaxhighlight>
* Bytes -> String: b'data'.decode("utf-8")
* Bytes -> String: b'data'.decode("utf-8")
* String -> Bytes: "string".encode("utf-8")
* String -> Bytes: "string".encode("utf-8")
* capitalize() count() endswith() find() index()
* isalnum() isalpha() isascii() isdecimal() isidentifier() islower() isnumeric() isprintable() isspace() isupper()
* join() partition() rfind() rindex() rpartition() rsplit() split() splitlines() startswith()
* strip() swapcase() title() translate() upper() zfill()
== Bytes ==
<syntaxhighlight lang="python">
text = b"abcde".decode("utf-8")
binary = "abc123".encode("utf-8")
</syntaxhighlight>


== Container (List) ==
== Container (List) ==
* List: ['a', 1]; x[1] = 5; x.insert(0, 'firstItem'); x.remove('a'); ix=x.index('a'); del x[0];
* List: ['a', 1]; x[1] = 5; x.insert(0, 'firstItem'); x.remove('a'); ix=x.index('a'); del x[0];
** x.append(99)
** list1 = list1 + list2
** list1 = list1 + list2
* Tupel: t = ('a', 1); l = list(t)
* Tupel: t = ('a', 1); l = list(t)
* list2 = [x for x in range(3)]
* list2 = [x for x in range(3)]
* contains99 = 99 in x


== Dictionary==
== Dictionary==
<pre>
<syntaxhighlight lang="python">
x = { 'key' : 'val', 'xyz': 3 }
x = { 'key' : 'val', 'xyz': 3 }
x['key'] = value
x['key'] = value
Zeile 50: Zeile 87:
contains = 'key' in x and 'key2' not in x
contains = 'key' in x and 'key2' not in x
size = len(x)
size = len(x)
for pair in x.iteritems():
for key, value in x.items():
   key = pair[0]
   print(key, value)
for key in x.iterkeys():
for key in x:
   print key
   print key
</pre>
</syntaxhighlight>
* x.itervalues()
* x.itervalues()
* x.setdefault(key[, value]): setzt Wert nur, wenn noch nicht gesetzt
* x.setdefault(key[, value]): setzt Wert nur, wenn noch nicht gesetzt
Zeile 62: Zeile 99:


== Mengen ==
== Mengen ==
<pre>
<syntaxhighlight lang="python">
s = set(['y', 3]) ; f = frozenset(['y', 3])  
s = {3, 'sjoerd'}
s = {c for c in 'abracadabra' if c not in 'abc'}
assertEquals(s, {'d', 'r'})
iterable = ['y', 3];
s = set(iterable) ;  
f = frozenset(iterable)
s.add(9)
s.remove(9)  
for elem in s:
for elem in s:
   print elem
   print elem
Zeile 72: Zeile 116:
isPartOf = s <= f
isPartOf = s <= f
diff = s - f
diff = s - f
</pre>
</syntaxhighlight>


== Datum/Zeit ==
== Datum/Zeit ==
<pre>import datetime, time
<syntaxhighlight lang="python">
import datetime, time
# ab hour optional:
# ab hour optional:
date1 = datetime.datetime(2019, 4, 1, 22, 44, 12, 123456)
date1 = datetime.datetime(2019, 4, 1, 22, 44, 12, 123456)
Zeile 98: Zeile 143:
#  calendar.timegm()¶ interpretiert GM-Time
#  calendar.timegm()¶ interpretiert GM-Time
time3 = calendar.timegm(timeTuple)
time3 = calendar.timegm(timeTuple)
</pre>
date5 = datetime.datetime.fromtimestamp(time.time() - 86400));
 
# Zeitdifferenz
 
date = date + datetime.timedelta(days=50, seconds=27, microseconds=10, milliseconds=29000, minutes=5, hours=8, weeks=2)
diffSec = (date1 - date2).total_seconds()
diffDays = (date1 - date2).days
</syntaxhighlight>
 
=== Leistungsmessung ===
<syntaxhighlight lang="python">
import timeit
body = '''text = 'abcdefg'
s = list(text)
s[6] = 'W'
''.join(s)
'''
print(timeit.timeit(body, number=1000000))
</syntaxhighlight>


== Enum ==
== Enum ==
<pre>from enum import Enum
<syntaxhighlight lang="python">
from enum import Enum
class TokenType(Enum):
class TokenType(Enum):
   digit = 1 ; string = 2 ; id = 3 ; operator = 4
   digit = 1 ; string = 2 ; id = 3 ; operator = 4


x = TokenType.id
x = TokenType.id
</pre>
for item in TokenType:
  print(item.name)
</syntaxhighlight>


== Typcheck ==
== Typcheck ==
<pre>
<syntaxhighlight lang="python">
isStringOrSubclass = isinstance(aVariable, str)
isStringOrSubclass = isinstance(aVariable, str)
isString = type(aVariable) is str
isString = type(aVariable) is str
isList = type([1, 2]) is list
isList = type([1, 2]) is list
isDict = type({ 0:"a", 1:"b" }) is dict
isDict = type({ 0:"a", 1:"b" }) is dict
</pre>
</syntaxhighlight>


== Spezielle Methoden/Attribute ==
== Spezielle Methoden/Attribute ==
* Statische Methoden:
* Statische Methoden:
<pre>
<syntaxhighlight lang="python">
class X:
class X:
   # statische Variable
   # statische Variable
Zeile 127: Zeile 193:


X.add("new")
X.add("new")
</pre>
</syntaxhighlight>
* Feststellen, ob Attribut existiert: hasattr(instance, nameOfAttribute)
* Feststellen, ob Attribut existiert: hasattr(instance, nameOfAttribute)
* dynamischer Code:
* dynamischer Code:
<pre>
<syntaxhighlight lang="python">
exec 'import ' + module
exec 'import ' + module
</pre>
</syntaxhighlight>
* Vollständige Kopie (deep copy):
* Vollständige Kopie (deep copy):
<pre>
<syntaxhighlight lang="python">
import copy
import copy
x = [1, 2]
x = [1, 2]
y = copy.deepcopy(x)
y = copy.deepcopy(x)
</pre>
</syntaxhighlight>
* Superclass-Konstruktor:
* Superclass-Konstruktor:
<pre>
<syntaxhighlight lang="python">
class Parent:
class Parent:
   def __init__(self, name)
   def __init__(self, name)
Zeile 147: Zeile 213:
   def __init__(self, name):
   def __init__(self, name):
       Parser.__init__(self, name)
       Parser.__init__(self, name)
</pre>
</syntaxhighlight>


== Funktionale Programmierung ==
== Funktionale Programmierung ==
<pre>
<syntaxhighlight lang="python">
import functools, math
import functools, math
array = [ 1, 9, 7, 5 ]
array = [ 1, 9, 7, 5 ]
Zeile 156: Zeile 222:
squares = list(map(lambda x: x*x, array))
squares = list(map(lambda x: x*x, array))
squares2 = list(filter(lambda x: int(math.sqrt(x)) == math.sqrt(x), array))
squares2 = list(filter(lambda x: int(math.sqrt(x)) == math.sqrt(x), array))
</pre>
</syntaxhighlight>


= Typische Situationen =
= Typische Situationen =
== Division Integer ==
<syntaxhighlight lang="python">
pairs = count // 2
</syntaxhighlight>
== Objekte kopieren (Shallow/Deep Copy) ==
<syntaxhighlight lang="python">
import copy
a = [1, 2, 3]
b = copy.copy(a)
c = [a, [1, 2, 3]]
d = copy.deepcopy(c)
# Speziell bei Listen (shallow copy):
copied_list = original_list[:]
</syntaxhighlight>
== Sortieren ==
== Sortieren ==
<pre>a =["Joe", "Eve", "Bob", "alma", "Adam"]
<syntaxhighlight lang="python">
a =["Joe", "Eve", "Bob", "alma", "Adam"]
a.sort()
a.sort()
# sort by a global function:
# sort by a global function:
Zeile 166: Zeile 251:
# sort by a lambda function which calculates the sorting key:
# sort by a lambda function which calculates the sorting key:
a.sort(key=lambda x: x[2])
a.sort(key=lambda x: x[2])
</pre>
# 2-stufig: nach Länge absteigend, dann alphabetisch:
a.sort(key=lambda x: (-len(x), x))
# comparism function:
def mySort(a, b): return len(a) - len(b)
import functools
a.sort(key=functools.cmp_to_key(mySort))
</syntaxhighlight>


== Externes Programm aufrufen ==
== Externes Programm aufrufen ==
<pre>
<syntaxhighlight lang="python">
with supbprocess.popen([ '/usr/bin/wc', '-l', file ], stdout=subprocess.PIPE) as proc:
with supbprocess.popen([ '/usr/bin/wc', '-l', file ], stdout=subprocess.PIPE) as proc:
   count = int(proc.stdout.read().decode())
   count = int(proc.stdout.read().decode())
</pre>
</syntaxhighlight>


== Dateien ==
== Dateien ==
* Lesen:
* Lesen:
<pre>
<syntaxhighlight lang="python">
with open(self._filename, "r") as fp:
with open(self._filename, "r") as fp:
   for line in fp:
   for line in fp:
     print(line)
     print(line)
   # fp.close() ist implizit
   # fp.close() ist implizit
</pre>
</syntaxhighlight>
* Binärdatei:
<syntaxhighlight lang="python">
with open(self._filename, "rb") as fp:
  data = fp.read(8000)
  while data:
    doIt(data)
    data = fp.read(8000)
</syntaxhighlight>
 
* Schreiben:
* Schreiben:
<pre>
<syntaxhighlight lang="python">
with open(self._filename, "w") as fp, open(self._input, "r") as fpInp:
with open(self._filename, "w") as fp, open(self._input, "r") as fpInp:
   line = fpInp.read()
   line = fpInp.read()
   fp.write(line);
   fp.write(line);
</pre>
</syntaxhighlight>


= Sprachbesonderheiten =
= Sprachbesonderheiten =
== Variable Zahl Parameter in Methode: Liste ==
<syntaxhighlight lang="python">
# numbers ist eine Liste:
def find_sum(*numbers):
    result = 0
    for num in numbers:
        result = result + num
   
    print("Sum = ", result)
# function call with 3 arguments
find_sum(1, 2, 3)
</syntaxhighlight>
== Variable Zahl Parameter in Methode: Map ==
<syntaxhighlight lang="python">
# numbers ist eine Liste:
def show(**params):
    result = 0
    for name,value in params.items():
        print(f'{name}: {value}')
# function call with 3 arguments
show(jonny="admin", berta="user")
</syntaxhighlight>
== Reflection ==
<syntaxhighlight lang="python">
class A:
  def __init__(self):
    self._a = 0
  def asString(self):
    return 'A'
a = A()
assertTrue(hasattr(a, '_a'));
assertTrue(hasattr(a, 'asString'));
assertFalse(hasattr(a, 'b'));
</syntaxhighlight>
== Type Hints ==
<syntaxhighlight lang="python">
from typing import Sequence
Vector = list[float]
def sqr(x: float) -> float:
  return x*x
def first(items: Sequence[str]) -> str:
  return items[0]
def printName(name: str) -> None:
  print(name);
</syntaxhighlight>
== Aufruf Superclass-Konstruktor ==
== Aufruf Superclass-Konstruktor ==
<pre>class B (A):
<syntaxhighlight lang="python">class B (A):
   def __init__(self, a):
   def __init__(self, a):
     A.__init__(self, a)
     A.__init__(self, a)
</pre>
  def asString(self):
    return 'B: ' + super().asString
</syntaxhighlight>


== Abstrakte Klasse ==
== Abstrakte Klasse ==
<pre>class A:
<syntaxhighlight lang="python">class A:


@abstractmethod
@abstractmethod
def process(self):
def process(self):
   pass
   pass
</pre>
</syntaxhighlight>


== Verschachtelte Methoden ==
== Verschachtelte Methoden ==
<pre>
<syntaxhighlight lang="python">
class Example:
class Example:
   def scan(self, file):
   def scan(self, file):
Zeile 220: Zeile 373:
       def _error(msg):
       def _error(msg):
         print("line {}: {}\n{}".format(lineNo, msg, line)
         print("line {}: {}\n{}".format(lineNo, msg, line)
</pre>       
</syntaxhighlight>       
          
          


Zeile 226: Zeile 379:
Damit eine Klasse mit "x in classInstance" angesprochen werden kann, muss es einen Iterator geben.
Damit eine Klasse mit "x in classInstance" angesprochen werden kann, muss es einen Iterator geben.
Im Beispiel wird dies in einer Klasse zusammengefasst:__iter__() liefert als Iterator sich selbst und __next__() implementiert diesen Iterator:
Im Beispiel wird dies in einer Klasse zusammengefasst:__iter__() liefert als Iterator sich selbst und __next__() implementiert diesen Iterator:
<pre>
<syntaxhighlight lang="python">
class Example:
class Example:
   def __init__():
   def __init__():
Zeile 242: Zeile 395:
   def next():
   def next():
     return self.__next__()
     return self.__next__()
</pre>
</syntaxhighlight>


== Generator ==
== Generator ==
* einfach mindestens ein "yield <value>" in die Funktion einfügen
* einfach mindestens ein "yield <value>" in die Funktion einfügen
* Bei Rekursion: yield from <method_call>
* Bei Rekursion: yield from <method_call>
<pre>def nextFile(directory)
<syntaxhighlight lang="python">def nextFile(directory)
  for node in os.listdir(directory):
  for node in os.listdir(directory):
   full = directory + os.sep + node
   full = directory + os.sep + node
Zeile 253: Zeile 406:
   if os.path.isdir(full):
   if os.path.isdir(full):
     yield from nextFile(full)
     yield from nextFile(full)
</pre>
</syntaxhighlight>


== Unittests ==
== Unittests ==
<pre>
<syntaxhighlight lang="python">
import unittest
import unittest
import sim_parser as sim
import sim_parser as sim


class SimParserTest(sim.SimParser):
class SimParserTest(unittest.TestCase):
      
      
     def testNextToken(self):
     def testNextToken(self):
Zeile 270: Zeile 423:
if __name__ == "__main__":  
if __name__ == "__main__":  
     unittest.main()
     unittest.main()
</pre>
</syntaxhighlight>
 
== ArgParse ==
<syntaxhighlight lang="python">
def main(argv=None): # IGNORE:C0111
    '''Command line options.'''
    if argv is None:
        argv = sys.argv
    program_name = os.path.basename(sys.argv[0])
    program_version = "v%s" % __version__
    program_build_date = str(__updated__)
    program_version_message = '%%(prog)s %s (%s)' % (program_version, program_build_date)
    program_shortdesc = __import__('__main__').__doc__.split("\n")[1]
    program_license = '''%s
  Created by Hamatoma on %s.
  Copyright 2022 Hamatoma. All rights reserved.
 
  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0
 
  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.
USAGE
''' % (program_shortdesc, str(__date__))
    try:
        # Setup argument parser
        parser = ArgumentParser(description=program_license, formatter_class=RawDescriptionHelpFormatter)
        parser.add_argument('file', help="file to dump")
        parser.add_argument('-v', '--verbose', dest='verbose', action='count', help='set verbosity level [default: %(default)s]')
        parser.add_argument('-o', '--offset', dest='offset', help='offset of the output [default: %(default)s]', metavar='OFFSET', type=int, default=0)
        parser.add_argument('-l', '--length', dest='length', help='length of the output [default: %(default)s]', metavar='LENGTH', type=int, default=80 )
        parser.add_argument('-V', '--version', action='version', version=program_version_message)
        args = parser.parse_args(argv[1:])
        offset = args.offset
        length = args.length
        filename = args.file
        if not os.path.exists(filename):
            raise CLIError('not a file: ' + filename)
...
        return 0
    except KeyboardInterrupt:
        return 0
    except Exception as e:
        if DEBUG or TESTRUN:
            raise(e)
        indent = len(program_name) * " "
        sys.stderr.write(program_name + ": " + repr(e) + "\n")
        sys.stderr.write(indent + "  for help use --help")
        return 2
if __name__ == "__main__":
    sys.exit(main())
</syntaxhighlight>

Version vom 22. April 2024, 20:18 Uhr

Links

Exception

try:
   raise Exception("not allowed")
except ValueError as error:
   print('value error: ' + repr(error))
except SyntaxError as error:
   print('syntax error: ' + repr(error))
else:
    raise Exception("unknown")
try:
   doit()
finally:
   closeIt()

Regular Expression

import re
rexpr = re.compile(r"([\da-z]+)")
match = rexpr.match(line)
if match != None:
   number = (int) rexpr.group(1)
# Replacement:
regex = re.compile(r"A\d+", re.IGNORECASE)
for line in some_file:
    other = regex.sub('<Id>', line)
# Replacement mit Referenzen:
s = 'aaa@xxx.com bbb@yyy.net ccc@zzz.org'
re.sub('([a-z]+)@([a-z]+)', r'\2@\1', s)

Datentypen

String

  • "x" und 'x' sind gleichwertig

Formatierung

  • f-String
# Gleitpunktzahl mit 3 Stellen ausgeben:
f'{self.floatValue:.3f}'
# 2-stellig mit führender 0 ausgeben:
f'{sec//3600}:{sec%3600//60:02}:{sec%60:02}'
# String linksbündig:
f'{data:<10}'
# String rechtsbündig:
f'{data:>10}'
  • str.format()
"{:3.7f} {:s} {:07d}".format(3.14, "hello", 100)
"{0:d} / {0:x}".format(714)
"{}-{}: {}".format('abc.txt', 9, 7.99)
precision=2
'{:.Pf}'.replace('P', str(precision)).format(value)
  • Bytes -> String: b'data'.decode("utf-8")
  • String -> Bytes: "string".encode("utf-8")
  • capitalize() count() endswith() find() index()
  • isalnum() isalpha() isascii() isdecimal() isidentifier() islower() isnumeric() isprintable() isspace() isupper()
  • join() partition() rfind() rindex() rpartition() rsplit() split() splitlines() startswith()
  • strip() swapcase() title() translate() upper() zfill()

Bytes

text = b"abcde".decode("utf-8") 
binary = "abc123".encode("utf-8")

Container (List)

  • List: ['a', 1]; x[1] = 5; x.insert(0, 'firstItem'); x.remove('a'); ix=x.index('a'); del x[0];
    • x.append(99)
    • list1 = list1 + list2
  • Tupel: t = ('a', 1); l = list(t)
  • list2 = [x for x in range(3)]
  • contains99 = 99 in x

Dictionary

x = { 'key' : 'val', 'xyz': 3 }
x['key'] = value
del x['key'];
contains = 'key' in x and 'key2' not in x
size = len(x)
for key, value in x.items():
  print(key, value)
for key in x:
  print key
  • x.itervalues()
  • x.setdefault(key[, value]): setzt Wert nur, wenn noch nicht gesetzt
  • x.keys(), x.values()
  • x.copy(): flache Kopie
  • x.update(dict): addiert dict zu x

Mengen

s = {3, 'sjoerd'}
s = {c for c in 'abracadabra' if c not in 'abc'}
assertEquals(s, {'d', 'r'})
iterable = ['y', 3];
s = set(iterable) ; 
f = frozenset(iterable)
s.add(9)
s.remove(9) 
for elem in s:
  print elem
size = len(s)
contains = 3 in s and 4 not in s
intersection = s & f
union = s | f
isPartOf = s <= f
diff = s - f

Datum/Zeit

import datetime, time
# ab hour optional:
date1 = datetime.datetime(2019, 4, 1, 22, 44, 12, 123456)
timeX = date1.timestamp() # float, sec since epoc
formatted = date1.strftime('%Y.%m.%dT%H:%M:%S')
now = datetime.datetime.now()
daylySeconds = (now.time().hour*60+now.time().minute)*60+now.time().second
yesterday = datetime.datetime.fromtimestamp(time.time() - 24*3600)
firstOfMonth = date1.replace(day=1)
asStringMicroseconds = date1.strftime('%Y.%m.%dT%H:%M:%S.%f dayOfTheWeek (e.g. "Sun"): %a')
weekNo = date1.strftime('%W')
# returns e.g. '08'
date2 = time.time()
date3 = time.localtime(date2)
date4 = time.strftime('%Y.%m.%d-%H:%M:%S.%f dayOfTheWeek: %w', date3)
dateXStr = time.strftime('%Y.%m.%d-%H:%M:%S.%f dayOfTheWeek: %w', time.localtime(timeX))
# Scannen aus Text:
date5 = datetime.datetime.strptime("30 Nov 00", "%d %b %y")
timeTuple = time.strptime("30 Nov 00", "%d %b %y")
# mktime interpretiert lokale Zeit!
time2 = time.mktime(timeTuple)
#  calendar.timegm()¶ interpretiert GM-Time
time3 = calendar.timegm(timeTuple)
date5 = datetime.datetime.fromtimestamp(time.time() - 86400));

# Zeitdifferenz 

date = date + datetime.timedelta(days=50, seconds=27, microseconds=10, milliseconds=29000, minutes=5, hours=8, weeks=2)
diffSec = (date1 - date2).total_seconds()
diffDays = (date1 - date2).days

Leistungsmessung

import timeit
body = '''text = 'abcdefg'
s = list(text)
s[6] = 'W'
''.join(s)
'''
print(timeit.timeit(body, number=1000000))

Enum

from enum import Enum
class TokenType(Enum):
  digit = 1 ; string = 2 ; id = 3 ; operator = 4

x = TokenType.id
for item in TokenType:
  print(item.name)

Typcheck

isStringOrSubclass = isinstance(aVariable, str)
isString = type(aVariable) is str
isList = type([1, 2]) is list
isDict = type({ 0:"a", 1:"b" }) is dict

Spezielle Methoden/Attribute

  • Statische Methoden:
class X:
   # statische Variable
   _data = []
   @staticmethod
   def add(item):
      X._data.append(item)

X.add("new")
  • Feststellen, ob Attribut existiert: hasattr(instance, nameOfAttribute)
  • dynamischer Code:
exec 'import ' + module
  • Vollständige Kopie (deep copy):
import copy
x = [1, 2]
y = copy.deepcopy(x)
  • Superclass-Konstruktor:
class Parent:
   def __init__(self, name)
      self._name = name
class Child(Parent):
   def __init__(self, name):
      Parser.__init__(self, name)

Funktionale Programmierung

import functools, math
array = [ 1, 9, 7, 5 ]
max = functools.reduce(lambda rc, item: item if item > rc else rc, array, -1E+100)
squares = list(map(lambda x: x*x, array))
squares2 = list(filter(lambda x: int(math.sqrt(x)) == math.sqrt(x), array))

Typische Situationen

Division Integer

pairs = count // 2


Objekte kopieren (Shallow/Deep Copy)

import copy
a = [1, 2, 3]
b = copy.copy(a)
c = [a, [1, 2, 3]]
d = copy.deepcopy(c)
# Speziell bei Listen (shallow copy):
copied_list = original_list[:]


Sortieren

a =["Joe", "Eve", "Bob", "alma", "Adam"]
a.sort()
# sort by a global function:
a.sort(key=str.lower)
# sort by a lambda function which calculates the sorting key:
a.sort(key=lambda x: x[2])
# 2-stufig: nach Länge absteigend, dann alphabetisch:
a.sort(key=lambda x: (-len(x), x))
# comparism function:
def mySort(a, b): return len(a) - len(b)
import functools
a.sort(key=functools.cmp_to_key(mySort))

Externes Programm aufrufen

with supbprocess.popen([ '/usr/bin/wc', '-l', file ], stdout=subprocess.PIPE) as proc:
   count = int(proc.stdout.read().decode())

Dateien

  • Lesen:
with open(self._filename, "r") as fp:
  for line in fp:
     print(line)
  # fp.close() ist implizit
  • Binärdatei:
with open(self._filename, "rb") as fp:
  data = fp.read(8000)
  while data:
     doIt(data)
     data = fp.read(8000)
  • Schreiben:
with open(self._filename, "w") as fp, open(self._input, "r") as fpInp:
  line = fpInp.read()
  fp.write(line);

Sprachbesonderheiten

Variable Zahl Parameter in Methode: Liste

# numbers ist eine Liste:
def find_sum(*numbers):
    result = 0
    for num in numbers:
        result = result + num
    
    print("Sum = ", result)

# function call with 3 arguments
find_sum(1, 2, 3)

Variable Zahl Parameter in Methode: Map

# numbers ist eine Liste:
def show(**params):
    result = 0
    for name,value in params.items():
        print(f'{name}: {value}')

# function call with 3 arguments
show(jonny="admin", berta="user")

Reflection

class A:
  def __init__(self):
    self._a = 0
  def asString(self):
    return 'A'
a = A()
assertTrue(hasattr(a, '_a'));
assertTrue(hasattr(a, 'asString'));
assertFalse(hasattr(a, 'b'));

Type Hints

from typing import Sequence
Vector = list[float]
def sqr(x: float) -> float:
  return x*x
def first(items: Sequence[str]) -> str:
  return items[0]
def printName(name: str) -> None:
  print(name);

Aufruf Superclass-Konstruktor

class B (A):
  def __init__(self, a):
    A.__init__(self, a)
  def asString(self):
    return 'B: ' + super().asString

Abstrakte Klasse

class A:

@abstractmethod
def process(self):
  pass

Verschachtelte Methoden

class Example:
  def scan(self, file):
     lineNo = 0
     for line in file:
       lineNo += 1
       if line.startswith('[':
           chapter = Chapter(line[1:-1])
       elif re.match(r'\w+='):
           var, value = line.split('=')
           chapter._vars[var] = value
       else:
           _error('invalid input')
      def _error(msg):
         print("line {}: {}\n{}".format(lineNo, msg, line)


Klasse als Sequenz

Damit eine Klasse mit "x in classInstance" angesprochen werden kann, muss es einen Iterator geben. Im Beispiel wird dies in einer Klasse zusammengefasst:__iter__() liefert als Iterator sich selbst und __next__() implementiert diesen Iterator:

class Example:
  def __init__():
    self._nextItems = []
  def __iter__():
    self._nextItems = [1, 2, 3]
    return self
  def __next__():
    if len(self._nextItem) == 0:
      raise StopIteration
    else:
      rc = self._nextItems[0]
      del self._nextItems[0]
      return rc
  def next():
    return self.__next__()

Generator

  • einfach mindestens ein "yield <value>" in die Funktion einfügen
  • Bei Rekursion: yield from <method_call>
def nextFile(directory)
 for node in os.listdir(directory):
  full = directory + os.sep + node
  yield full
  if os.path.isdir(full):
    yield from nextFile(full)

Unittests

import unittest
import sim_parser as sim

class SimParserTest(unittest.TestCase):
    
    def testNextToken(self):
        parser = sim.SimParser()
        parser.setSource('''10 'abc' var12 +;
    ''')
        self.assertEqual(parser.token(0), sim.Number(10, True, 0, 0))

if __name__ == "__main__": 
    unittest.main()

ArgParse

def main(argv=None): # IGNORE:C0111
    '''Command line options.'''
    if argv is None:
        argv = sys.argv
    program_name = os.path.basename(sys.argv[0])
    program_version = "v%s" % __version__
    program_build_date = str(__updated__)
    program_version_message = '%%(prog)s %s (%s)' % (program_version, program_build_date)
    program_shortdesc = __import__('__main__').__doc__.split("\n")[1]
    program_license = '''%s
  Created by Hamatoma on %s.
  Copyright 2022 Hamatoma. All rights reserved.

  Licensed under the Apache License 2.0
  http://www.apache.org/licenses/LICENSE-2.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.
USAGE
''' % (program_shortdesc, str(__date__))
    try:
        # Setup argument parser
        parser = ArgumentParser(description=program_license, formatter_class=RawDescriptionHelpFormatter)
        parser.add_argument('file', help="file to dump")
        parser.add_argument('-v', '--verbose', dest='verbose', action='count', help='set verbosity level [default: %(default)s]')
        parser.add_argument('-o', '--offset', dest='offset', help='offset of the output [default: %(default)s]', metavar='OFFSET', type=int, default=0)
        parser.add_argument('-l', '--length', dest='length', help='length of the output [default: %(default)s]', metavar='LENGTH', type=int, default=80 )
        parser.add_argument('-V', '--version', action='version', version=program_version_message)
        args = parser.parse_args(argv[1:])
        offset = args.offset
        length = args.length
        filename = args.file
        if not os.path.exists(filename):
            raise CLIError('not a file: ' + filename)
...
        return 0
    except KeyboardInterrupt:
        return 0
    except Exception as e:
        if DEBUG or TESTRUN:
            raise(e)
        indent = len(program_name) * " "
        sys.stderr.write(program_name + ": " + repr(e) + "\n")
        sys.stderr.write(indent + "  for help use --help")
        return 2
if __name__ == "__main__":
    sys.exit(main())