CA3 Python Programming Test Overview
CA3 Python Programming Test Overview
Decimal numbers in Python can be created using the decimal module, which provides the Decimal class for handling decimal arithmetic, offering higher precision than floating-point arithmetic and reducing floating-point issues like representation and arithmetic errors. An example is decimal.Decimal('0.1') which avoids the imprecision observed with float(0.1). Despite these advantages, Decimal is generally slower than floats due to higher computational costs, and care must be taken to manage precision manually. Floats, meanwhile, are adequate for many practical applications given their speed but may suffer from precision issues in critical applications.
Python's reverse slicing, such as [::-1], is key for efficiently reversing sequences, reflecting its power in concise data structure manipulation. For example, using 'hello world'[::-1] efficiently reverses the string, crucial for real-world data processing tasks like palindrome detection, undo operations, and formatted output generation. Understanding slicing paves the way for exploiting Python lists and strings capabilities, leading to optimized and readable code areas where performance on sequences is critical.
Using printf-style formatting with "%f", a floating-point number can be formatted to a specified degree of precision. For example, given x = 56.236, the code `print("%.2f" % x)` outputs '56.24', rounding to two decimal places. In contrast, the format() method provides additional flexibility and readability, allowing for detailed formatting within a single call, e.g., `'{:.2f}'.format(x)`, producing the same result. The format() method is preferred due to its composability and readability in modern Python development over legacy printf-style formatting.
A shallow copy in Python creates a new object, but inserts references into it to the objects found in the original. Therefore, altering a mutable object within either the original or copied composite object often reflects immediately in the other. For instance, using copy.copy(list_original) on a list of lists results in a shallow copy. Any modification to a sublist affects both lists. To avoid issues tied to shallow copying, a deep copy, which duplicates everything recursively, can be employed. The copy.deepcopy() function from Python's copy module can be utilized for this purpose.
The range() function in Python generates a sequence of numbers, supporting iteration in for-loops without manually indexing sequences. It creates an iterable sequence of integers, starting from 0 if not otherwise specified. For instance, `for i in range(4): print(i)` outputs 0, 1, 2, 3, iterating from 0 up to, but not including, 4. This simplifies iteration over sequences without needing explicit indexing or list initialization, highlighting Python's internal iteration abstraction.
In Python, an integer can be created from a binary number using int() with a base argument, such as int('101', 2), which converts the binary string '101' into the integer 5. To get an integer's binary equivalent, one can use the bin() function, which returns a binary string prefixed with '0b'. For instance, bin(5) yields '0b101'. The string.format() method can be used to format output, including converting numbers into binary strings without prefixes, e.g., '{:b}'.format(5) yields '101'. This method provides additional flexibility in formatting output.
Lists and strings in Python are both sequence types, but they have distinct differences. Lists are mutable, meaning their contents can be changed, whereas strings are immutable, making them unchangeable once created. This implies operations that modify contents must create new strings. For example, a list can be modified using methods like append(), pop(), and remove(), whereas to modify a string, one might need to create a new one or use methods like replace() to achieve a similar outcome. Example: list = [1, 2, 3]; list[0] = 4 gives list as [4, 2, 3], whereas str = 'abc'; str[0] = 'z' is not valid and requires creating a new string str = 'z' + str[1:]
Slicing in Python allows one to manually iterate through a string to find a substring's occurrences by examining each sliced part. This method is labor-intensive and involves looping and comparing segments of the string to the target substring. In contrast, string methods like str.count() efficiently count the occurrences directly. For example, while one might slice 'hello hello' into parts and manually count occurrences of 'lo', the optimized `s = 'hello hello'; print(s.count('lo'))` achieves the desired result succinctly and efficiently. This showcases Python's powerful abstraction for string searching via methods over slicing.
Python's handling of data types, shown in list methods like append(), reflects its flexible, dynamic type system. Lists being mutable supports in-place operations like list.append(), adding elements directly without creating new objects, thus aligning with mutable sequence design. In contrast, strings' immutability reflects a different intent; methods like str.replace() always return new strings to maintain original data unaltered, crucial for data integrity in multi-threaded scenarios. This dichotomy emphasizes Python's thoughtful data structure implementation, balancing performance and mutability against stability and data security.
To reverse a string in Python, one can employ a loop structure alongside string concatenation. Although less idiomatic than using slicing (e.g., string[::-1]), a for loop together with incremental string concatenation illustrates fundamental iteration and string handling concepts. For example, reversing 'abcd' could be implemented with: `result = ''; for char in 'abcd': result = char + result; print(result)` outputs 'dcba', building the string backward. While this approach demonstrates iteration's low-level operations, it's less efficient and less readable compared to direct slicing or reversed()