Python core part2
1. Comprehensions
2.
List Comprehensions
与上面的语句达到相同的效果,但是复杂的多
another example
and another for set comprehensions
3. Dictionary Comprehensions
下面的例子里,去每个item的第一个字母作为key,只有最后一组被保留了,因为key必须唯一
4. 不要把comprehension写的太复杂,比如下面的例子,列出目录中的python文件及其大小
5. 给comprehension加上过滤filter以得到101内的质数
6.
7. Generator functions
8. Laziness, 只有执行到才会求解
9. Generator Expression
节省内存占用
带过滤条件
10. Iteration Tools
11. any and all
12. zip()
13. Class
14. self, Instance methods must accept a reference to the actual instance on which the method was called as the first argument.
f.number()只是Flight.number(f)的语法糖
__init__并不是constractor, 只是初始化变量
class的所有成员都是public的
15. Class invariants: truths about an object that endure for its lifetime.
16. another class example:
17. Class reference to another class
18. seating definition
allocate set method
testing allocate seat method
show the result of setting
19. 将函数作为参数传递
类成员
非类成员
调用过程,非类成员函数console_card_printer被当作参数传递
示例完整代码
1 """Model for aircraft flights.""" 2 3 4 class Flight: 5 """A flight with a particuar passenger aircraft.""" 6 7 def __init__(self, number, aircraft): 8 if not number[:2].isalpha(): 9 raise ValueError(f"No airline code in '{number}'") 10 11 if not number[:2].isupper(): 12 raise ValueError(f"Invalid airline code '{number}'") 13 14 if not (number[2:].isdigit() and int(number[2:]) <= 9999): 15 raise ValueError(f"Invalid route number '{number}'") 16 17 self._number = number 18 self._aircraft = aircraft 19 rows, seats = self._aircraft.seating_plan() 20 self._seating = [None] + \ 21 [{letter: None for letter in seats} for _ in rows] 22 23 def aircraft_model(self): 24 return self._aircraft.model() 25 26 def number(self): 27 return self._number 28 29 def airline(self): 30 return self._number[:2] 31 32 def allocate_seat(self, seat, passenger): 33 """Allocate a seat to a passenger. 34 35 Args: 36 seat: A seat designator such as '12C' or '21F'. 37 passenger: The passenger name. 38 39 Raises: 40 ValueError: If the seat is unavailable. 41 """ 42 row, letter = self._parse_seat(seat) 43 44 if self._seating[row][letter] is not None: 45 raise ValueError(f"Set {seat} already occupied") 46 47 self._seating[row][letter] = passenger 48 49 def _parse_seat(self, seat): 50 rows, seat_letters = self._aircraft.seating_plan() 51 52 letter = seat[-1] 53 if letter not in seat_letters: 54 raise ValueError(f"Invalid seat letter {letter}") 55 56 row_text = seat[:-1] 57 try: 58 row = int(row_text) 59 except ValueError: 60 raise ValueError(f"Invalid seat row {row_text}") 61 62 if row not in rows: 63 raise ValueError(f"Invalid row number {row}") 64 65 return row, letter 66 67 def relocate_passenger(self, from_seat, to_seat): 68 """Relocate a passenger to a different seat. 69 70 Args: 71 from_seat: The existing seat designator for the 72 passenger to be moved. 73 74 to_set: The new seat designator. 75 """ 76 from_row, from_letter = self._parse_seat(from_seat) 77 if self._seating[from_row][from_letter] is None: 78 raise ValueError(f"No passenger to relocate in seat {from_seat}") 79 80 to_row, to_letter = self._parse_seat(to_seat) 81 if self._seating[to_row][to_letter] is not None: 82 raise ValueError(f"Seat {to_seat} already occupied") 83 84 self._seating[to_row][to_letter] = self._seating[from_row][from_letter] 85 self._seating[from_row][from_letter] = None 86 87 def num_available_seats(self): 88 return sum(sum(1 for s in row.values() if s is None) for row in self._seating if row is not None) 89 90 def make_boarding_cards(self, card_printer): 91 for passenger, seat in sorted(self._passenger_seats()): 92 card_printer(passenger, seat, self.number(), self.aircraft_model()) 93 94 def _passenger_seats(self): 95 """An iterable series of passenger seating locations.""" 96 row_numbers, seat_letters = self._aircraft.seating_plan() 97 for row in row_numbers: 98 for letter in seat_letters: 99 passenger = self._seating[row][letter] 100 if passenger is not None: 101 yield (passenger, f"{row}{letter}") 102 103 104 def console_card_printer(passenger, seat, fligt_number, aircraft): 105 output = f"| Name: {passenger}" \ 106 f" Flight: {fligt_number}" \ 107 f" Seat: {seat}" \ 108 f" Aircraft: {aircraft}" \ 109 " |" 110 banner = "+" + "-" * (len(output) - 2) + "+" 111 border = "|" + " " * (len(output) - 2) + "|" 112 lines = [banner, border, output, border, banner] 113 card = "\n".join(lines) 114 print(card) 115 print() 116 117 118 class Aircraft: 119 120 def __init__(self, registration, model, num_rows, num_seats_per_row): 121 self._registration = registration 122 self._model = model 123 self._num_rows = num_rows 124 self._num_seats_per_row = num_seats_per_row 125 126 def registration(self): 127 return self._registration 128 129 def model(self): 130 return self._model 131 132 def seating_plan(self): 133 return (range(1, self._num_rows + 1), "ABCDEFGHJK"[:self._num_seats_per_row]) 134 135 136 def make_flight(): 137 f = Flight("BA758", Aircraft("G-EUPT", "Airbus A319", 138 num_rows=22, num_seats_per_row=6)) 139 f.allocate_seat("12A", "Guido van Rossum") 140 f.allocate_seat("15F", "Bjarne Stroustrup") 141 f.allocate_seat("15E", "Anders Hejlsberg") 142 f.allocate_seat("1C", "John McCarthy") 143 f.allocate_seat("1D", "Rich Hickey") 144 return f
20. polymorphism
增加的代码
1 def make_flights(): 2 f = Flight("BA758", AirbusA319("G-EUPT")) 3 f.allocate_seat("12A", "Guido van Rossum") 4 f.allocate_seat("15F", "Bjarne Stroustrup") 5 f.allocate_seat("15E", "Anders Hejlsberg") 6 f.allocate_seat("1C", "John McCarthy") 7 f.allocate_seat("1D", "Rich Hickey") 8 9 g = Flight("AF72", Boeing777("F-GSPS")) 10 g.allocate_seat("55K", "Larry Wall") 11 g.allocate_seat("33G", "Yukihiro Matsumoto") 12 g.allocate_seat("4B", "Brian Kernighan") 13 g.allocate_seat("4A", "Dennis Richie") 14 15 return f, g 16 17 18 class AirbusA319: 19 20 def __init__(self, registration): 21 self._registration = registration 22 23 def registration(self): 24 return self._registration 25 26 def model(self): 27 return "Airbus A319" 28 29 def seating_plan(self): 30 return range(1, 23), "ABCDEF" 31 32 class Boeing777: 33 34 def __init__(self, registration): 35 self._registration = registration 36 37 def registration(self): 38 return self._registration 39 40 def model(self): 41 return "Boeing 777" 42 43 def seating_plan(self): 44 # For simplicity's sake, we ignore complex 45 # seating arrangement for first-class 46 return range(1, 56), "ABCDEGHJK"
运行示例:
21.
1 class AircraftBase: 2 3 def __init__(self, registration): 4 self._registration = registration 5 6 def registration(self): 7 return self._registration 8 9 def num_seats(self): 10 rows, row_seats = self.seating_plan() 11 return len(rows) * len(row_seats) 12 13 class AirbusA319(AircraftBase): 14 15 def model(self): 16 return "Airbus A319" 17 18 def seating_plan(self): 19 return range(1, 23), "ABCDEF" 20 21 class Boeing777(AircraftBase): 22 23 def model(self): 24 return "Boeing 777" 25 26 def seating_plan(self): 27 # For simplicity's sake, we ignore complex 28 # seating arrangement for first-class 29 return range(1, 56), "ABCDEGHJK"
运行:
22. open file
23. mode
24. example of write
\n是python使用的换行符,在保存时会自动转换为系统的换行符,所以同样是本例,linux的文件会比windows的少一个字节
只有在执行了close()之后,文件才会保存
25. read from file
seek只能赋值为0,对于文本文件来说
26. append to file
27. Iterating over files
1 import sys 2 3 f = open(sys.argv[1], mode='rt', encoding='utf-8') 4 for line in f: 5 print(line) 6 f.close()
output:
避免多一个换行
1 import sys 2 3 f = open(sys.argv[1], mode='rt', encoding='utf-8') 4 for line in f: 5 sys.stdout.write(line) 6 f.close()
output:
28. write Recaman data
1 from re import A 2 import sys 3 from itertools import count, islice 4 5 6 def sequence(): 7 """Generate Recaman's sequence.""" 8 seen = set() 9 a = 0 10 for n in count(1): 11 yield a 12 seen.add(a) 13 c = a - n 14 if c < 0 or c in seen: 15 c = a + n 16 a = c 17 18 19 def write_sequence(filename, num): 20 """Write Recaman's sequence to a text file.""" 21 f = open(filename, mode='wt', encoding='utf-8') 22 f.writelines(f"{r}\n" for r in islice(sequence(), num + 1)) 23 f.close() 24 25 26 if __name__ == '__main__': 27 write_sequence(filename=sys.argv[1], num=int(sys.argv[2]))
运行:
29. read file
1 """Read and print an integer series.""" 2 import sys 3 4 def read_series(filename): 5 f = open(filename, mode='rt', encoding='utf-8') 6 series = [] 7 for line in f: 8 a = int(line.strip()) 9 series.append(a) 10 f.close() 11 return series 12 13 def main(filename): 14 series = read_series(filename) 15 print(series) 16 17 if __name__ == "__main__": 18 main(filename=sys.argv[1])
运行:
故意制造一个类型错误
运行出错
出错后,file没有close,优化程序:
1 """Read and print an integer series.""" 2 import sys 3 4 def read_series(filename): 5 try: 6 f = open(filename, mode='rt', encoding='utf-8') 7 return [int(line.strip()) for line in f] 8 # series = [] 9 # for line in f: 10 # a = int(line.strip()) 11 # series.append(a) 12 finally: 13 f.close() 14 return series 15 16 def main(filename): 17 series = read_series(filename) 18 print(series) 19 20 if __name__ == "__main__": 21 main(filename=sys.argv[1])
30. File usage pattern
31.
用with重写的函数
1 from re import A 2 import sys 3 from itertools import count, islice 4 5 6 def sequence(): 7 """Generate Recaman's sequence.""" 8 seen = set() 9 a = 0 10 for n in count(1): 11 yield a 12 seen.add(a) 13 c = a - n 14 if c < 0 or c in seen: 15 c = a + n 16 a = c 17 18 19 def write_sequence(filename, num): 20 """Write Recaman's sequence to a text file.""" 21 f = open(filename, mode='wt', encoding='utf-8') 22 f.writelines(f"{r}\n" for r in islice(sequence(), num + 1)) 23 f.close() 24 25 26 def write_sequence_with(filename, num): 27 """Write Recaman's sequence to a text file.""" 28 with open(filename, mode='wt', encoding='utf-8') as f: 29 f.writelines(f"{r}\n" for r in islice(sequence(), num + 1)) 30 31 32 if __name__ == '__main__': 33 write_sequence_with(filename=sys.argv[1], num=int(sys.argv[2]))
1 """Read and print an integer series.""" 2 import sys 3 4 def read_series(filename): 5 try: 6 f = open(filename, mode='rt', encoding='utf-8') 7 return [int(line.strip()) for line in f] 8 # series = [] 9 # for line in f: 10 # a = int(line.strip()) 11 # series.append(a) 12 finally: 13 f.close() 14 return series 15 16 def read_series_with(filename): 17 with open(filename, mode='rt', encoding='utf-8') as f: 18 return [int(line.strip()) for line in f] 19 20 21 def main(filename): 22 series = read_series_with(filename) 23 print(series) 24 25 if __name__ == "__main__": 26 main(filename=sys.argv[1])
32. bmp.py
1 """A module for dealing with BMP bitmap image files.""" 2 3 def write_grayscale(filename, pixels): 4 """Creates and writes a grayscale BMP file. 5 6 Args: 7 filename: The name of the BMP file to me created. 8 9 pixels: A rectangular image stored as a sequence of rows. 10 Each row must be an iterable series of integers in the 11 range 0-255. 12 13 Raises: 14 ValueError: If any of the integer values are out of range. 15 OSError: If the file couldn't be written. 16 """ 17 height = len(pixels) 18 width = len(pixels[0]) 19 20 with open(filename, 'wb') as bmp: 21 #BMP Header 22 bmp.write(b'BM') 23 24 size_bookmark = bmp.tell() # The next four bytes hold the filesize as a 32-bit 25 bmp.write(b'\x00\x00\x00\x00') # little-endian integer. Zero placeholder for now. 26 27 bmp.write(b'\x00\x00') # Unused 16-bit integer - should be zero 28 bmp.write(b'\x00\x00') # Unused 16-bit integer - should be zero 29 30 pixel_offset_bookmark = bmp.tell() # The next four bytes hold the integer offset to the 31 bmp.write(b'\x00\x00\x00\x00') # pixel data. Zero placeholder for now. 32 33 # Image Header 34 bmp.write(b'\x28\x00\x00\x00') # Image header size in bytes - 40 decimal 35 bmp.write(_int32_to_bytes(width)) # Image width in pixels 36 bmp.write(_int32_to_bytes(height)) # Image height in pixels 37 bmp.write(b'\x01\x00') # Number of image planes 38 bmp.write(b'\x08\x00') # Bits per pixel 8 for grayscale 39 bmp.write(b'\x00\x00\x00\x00') # No compression 40 bmp.write(b'\x00\x00\x00\x00') # Zero for uncompressed images 41 bmp.write(b'\x00\x00\x00\x00') # Unused pixels per meter 42 bmp.write(b'\x00\x00\x00\x00') # Unused pixels per meter 43 bmp.write(b'\x00\x00\x00\x00') # Use whole color table 44 bmp.write(b'\x00\x00\x00\x00') # All colors are important 45 46 # Color palette - a linear grayscale 47 for c in range(256): 48 bmp.write(bytes((c,c,c,0))) # Blue, Green, Red, Zero 49 50 # Pixel data 51 pixel_data_bookmark = bmp.tell() 52 for row in reversed(pixels): # BMP files are bottom to top 53 row_data = bytes(row) 54 bmp.write(row_data) 55 padding = b'\x00' * ((4 - (len(row) % 4)) % 4) # Pad row to multiple of four bytes 56 bmp.write(padding) 57 58 # End of file 59 eof_bookmark = bmp.tell() 60 61 # Fill in file size placeholder 62 bmp.seek(size_bookmark) 63 bmp.write(_int32_to_bytes(eof_bookmark)) 64 65 # Fill in pixel offset placeholder 66 bmp.seek(pixel_offset_bookmark) 67 bmp.write(_int32_to_bytes(pixel_data_bookmark)) 68 69 def _int32_to_bytes(i): 70 """Convert an integer to four bytes in little-endian format.""" 71 72 # &: Bitwise-and 73 # >>: Right-shift 74 75 return bytes((i & 0xff, i >> 8 & 0xff, i >> 16 & 0xff, i >> 24 & 0xff))
fractal.py
1 """Gomputing Mandelbrot sets.""" 2 3 import math 4 5 def mandel(real, imag): 6 """The logarithm of number of iterations needed to 7 determine whether a complex point is in the 8 Mandelbrot set. 9 10 Args: 11 real: The real coordinate 12 imag: The imaginary coordinate 13 14 Returns: 15 An integer in the range 1-255. 16 """ 17 x = 0 18 y = 0 19 for i in range(1, 257): 20 if x*x + y*y > 4.0: 21 break 22 xt = real + x*x - y*y 23 y = imag + 2.0 * x * y 24 x = xt 25 return int(math.log(i) * 256 / math.log(256)) - 1 26 27 def mandelbrot(size_x, size_y): 28 """Make an Mandelbrot set image. 29 30 Args: 31 size_x: Image width 32 sixe_y: Image height 33 34 Returns: 35 A list of lists of integers in the range 0-255. 36 """ 37 return [[mandel((3.5 * x / size_x) - 2.5, (2.0 * y / size_y) -1.0) for x in range(size_x)] for y in range(size_y)]
执行:
生成的bmp
add function in bmp.py to read from bmp file
1 def dimensions(filename): 2 """Determine the dimensions in pixels of a BMP image. 3 4 Args: 5 filename: The filename of a BMP file. 6 7 Returns: 8 A tuple containing two integers with the width 9 and height in pixels. 10 11 Raises: 12 ValueError: If the file was not a BMP file. 13 OSError: If there was a problem reading the file. 14 """ 15 with open(filename, 'rb') as f: 16 magic = f.read(2) 17 if magic != b'BM': 18 raise ValueError(f"{filename} is not a BMP file") 19 20 f.seek(18) 21 width_bytes = f.read(4) 22 height_bytes = f.read(4) 23 24 return (_bytes_to_int32(width_bytes), _bytes_to_int32(height_bytes)) 25 26 def _bytes_to_int32(b): 27 """Convert a bytes object containing four bytes into an integer.""" 28 return b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)
33.
1 >>> def words_per_line(flo): 2 ... return [len(line.split()) for line in flo.readlines()] 3 ... 4 >>> with open("wastedland.txt", mode='rt', encoding='utf-8') as real_file: 5 ... wpl = words_per_line(real_file) 6 ... 7 >>> wpl 8 [9, 8, 9, 9] 9 >>> 10 >>> type(real_file) 11 <class '_io.TextIOWrapper'> 12 >>> 13 >>> from urllib.request import urlopen 14 >>> with urlopen("http://sixty-north.com/c/t.txt") as web_file: 15 ... wpl = words_per_line(web_file) 16 ... 17 >>> wpl 18 [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 7, 8, 14, 12, 8] 19 >>> 20 >>> type(web_file) 21 <class 'http.client.HTTPResponse'> 22 >>>
34. Context Manager
1 """Demonstrate raiding a refrigerator.""" 2 3 from contextlib import closing 4 5 class RefrigeratorRaider: 6 """Raid a refrigerator""" 7 8 def open(self): 9 print("Open fridge door.") 10 11 def take(self, food): 12 print(f"Finding {food}...") 13 if food == 'deep fried pizza': 14 raise RuntimeError("Health warning!") 15 print(f"Taking {food}") 16 17 def close(self): 18 print("Close fridge door.") 19 20 def raid(food): 21 #r = RefrigeratorRaider() 22 with closing(RefrigeratorRaider()) as r: 23 r.open() 24 r.take(food) 25 #r.close()
保证冰箱总能被关闭
1 >>> from fridge import raid 2 >>> 3 >>> raid('bacon') 4 Open fridge door. 5 Finding bacon... 6 Taking bacon 7 Close fridge door. 8 >>> 9 >>> raid('deep fried pizza') 10 Open fridge door. 11 Finding deep fried pizza... 12 Close fridge door. 13 Traceback (most recent call last): 14 File "<stdin>", line 1, in <module> 15 File "C:\luke\Learn\Python\fridge.py", line 24, in raid 16 r.take(food) 17 File "C:\luke\Learn\Python\fridge.py", line 14, in take 18 raise RuntimeError("Health warning!") 19 RuntimeError: Health warning! 20 >>>