Python: Unterschied zwischen den Versionen

Aus Info-Theke
Zur Navigation springen Zur Suche springen
 
Zeile 290: Zeile 290:


= Sprachbesonderheiten =
= Sprachbesonderheiten =
== Komplexe Variable dumpen ==
<syntaxhighlight lang="python">
print(vars(foo),vars(bar))
</syntaxhighlight>
== Variable Zahl Parameter in Methode: Liste ==
== Variable Zahl Parameter in Methode: Liste ==
<syntaxhighlight lang="python">
<syntaxhighlight lang="python">

Aktuelle Version vom 16. Dezember 2024, 14:49 Uhr

Links[Bearbeiten]

Exception[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

String[Bearbeiten]

  • "x" und 'x' sind gleichwertig

Formatierung[Bearbeiten]

  • 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[Bearbeiten]

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

Container (List)[Bearbeiten]

  • 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[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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

Enum[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

  • 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[Bearbeiten]

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[Bearbeiten]

Division Integer[Bearbeiten]

pairs = count // 2


Objekte kopieren (Shallow/Deep Copy)[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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

Dateien[Bearbeiten]

  • 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[Bearbeiten]

Komplexe Variable dumpen[Bearbeiten]

print(vars(foo),vars(bar))

Variable Zahl Parameter in Methode: Liste[Bearbeiten]

# 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[Bearbeiten]

# 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[Bearbeiten]

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'));
print(getattr(a, '_a))
names = ['bob', 'alice']
it = iter(names)
assertTrue(next(it) == 'bob')
assertTrue(next(it) == 'alice')

Type Hints[Bearbeiten]

from typing import List, Sequence, Mapping
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);
def evalMap(map: Mapping[int, str]):
  return map[3] == 'Hello'

Aufruf Superclass-Konstruktor[Bearbeiten]

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

Abstrakte Klasse[Bearbeiten]

class A:

@abstractmethod
def process(self):
  pass

Verschachtelte Methoden[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

  • 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[Bearbeiten]

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[Bearbeiten]

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())