Compare commits
43
Commits
74545a6ad1
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a335bc362 | ||
|
|
5440bf3773 | ||
|
|
57e46c4fce | ||
|
|
fe40d7f00e | ||
|
|
f4981fb8fd | ||
|
|
5587fcab38 | ||
|
|
0f133528b3 | ||
|
|
943741fbc4 | ||
|
|
7025098824 | ||
|
|
527ff3654d | ||
|
|
fd6f0e574c | ||
|
|
d2bb4dc72a | ||
|
|
14dbd3ed39 | ||
|
|
df963da832 | ||
|
|
49b7d7134b | ||
|
|
df793f5ae9 | ||
|
|
582e2bcfe1 | ||
|
|
2ca60ee9f9 | ||
|
|
e75cba4117 | ||
|
|
2556ad33ca | ||
|
|
70581e083e | ||
|
|
de08f52211 | ||
|
|
7ab36cc4c5 | ||
|
|
dd85aebb88 | ||
|
|
21661d71ee | ||
|
|
34e39ba1d9 | ||
|
|
71750bd96c | ||
|
|
12474cca3f | ||
|
|
3df5a742d8 | ||
|
|
facd334915 | ||
|
|
5732b28b4e | ||
|
|
c3e0c45786 | ||
|
|
d807bd6b3b | ||
|
|
60aaa1ebb8 | ||
|
|
79f8a7f5cc | ||
|
|
cfe8be26e0 | ||
|
|
805c5c275e | ||
|
|
83859026be | ||
|
|
5efb942978 | ||
|
|
74f9527832 | ||
|
|
081471fa5d | ||
|
|
291ba82046 | ||
|
|
14ed1783f9 |
@@ -0,0 +1,5 @@
|
||||
.DS_Store
|
||||
geckodriver.log
|
||||
.gitignore
|
||||
*.pyc
|
||||
*/__pycache__
|
||||
Vendored
+7
@@ -7,6 +7,13 @@
|
||||
"program": "simulation/SimulationRunner.py",
|
||||
"justMyCode": true,
|
||||
"args": "./HotdogSimulation.py"
|
||||
},
|
||||
{
|
||||
"name": "Python: File",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"justMyCode": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# Question 7:
|
||||
# 1. Strings in Python are sequences of Unicode characters, while bytes
|
||||
# are sequences of raw binary data.
|
||||
# 2. Strings in Python are immutable, bytes objects are mutable
|
||||
# 3. Strings in Python are encoded using a specific character encoding,
|
||||
# bytes objects do not have an inherent encoding and represent raw binary
|
||||
# data.
|
||||
import sys
|
||||
|
||||
string_example = "Hello"
|
||||
bytes_example = b"Hello"
|
||||
|
||||
string_size = sys.getsizeof(string_example)
|
||||
bytes_size = sys.getsizeof(bytes_example)
|
||||
|
||||
print("Size of string:", string_size)
|
||||
print("Size of bytes:", bytes_size)
|
||||
|
||||
# Emojis are represented using Unicode characters, which require more
|
||||
# bytes to store compared to ASCII characters. Therefore, if you have
|
||||
# a string that contains emojis, its size will be larger than a string
|
||||
# without emojis.
|
||||
|
||||
def print_string_as_numbers(input_string):
|
||||
for char in input_string:
|
||||
print(ord(char), end=' ')
|
||||
|
||||
# Example usage
|
||||
input_string = "Hello, World!"
|
||||
print_string_as_numbers(input_string)
|
||||
@@ -0,0 +1,36 @@
|
||||
# Question 8: It assumes that the CSV file being read
|
||||
# (tomato_sales_error.csv) has a column named "Tomato_Sales."
|
||||
# If the column doesn't exist in the CSV file or if there is an issue
|
||||
# with the file itself, an error will be raised.
|
||||
|
||||
# Question 9:
|
||||
import pandas as pd
|
||||
|
||||
def read_tomato_sales(file_name):
|
||||
data = pd.read_csv(file_name)
|
||||
|
||||
# Ensure required columns exist
|
||||
required_columns = ["Store", "Region", "Tomato_Sales"]
|
||||
missing_columns = set(required_columns) - set(data.columns)
|
||||
if missing_columns:
|
||||
raise ValueError(f"Invalid CSV format: Missing columns: {', '.join(missing_columns)}")
|
||||
|
||||
# Validate Tomato_Sales column
|
||||
tomato_sales = data["Tomato_Sales"]
|
||||
if not tomato_sales.dtype == int and not tomato_sales.dtype == float:
|
||||
raise ValueError("Invalid CSV format: 'Tomato_Sales' column must contain numerical values.")
|
||||
|
||||
# Calculate total tomato sales
|
||||
total_sales = tomato_sales.sum()
|
||||
print(f"Total tomato sales: {total_sales}")
|
||||
|
||||
# Question 10: Bytes represent raw binary data, while strings represent
|
||||
# textual data. Using bytes allows us to handle various character
|
||||
# encodings. By working with bytes, we can ensure that the data remains in
|
||||
# its raw encoded form, allowing for accurate handling of different
|
||||
# encodings.
|
||||
|
||||
# In the interactive Python REPL (Read-Eval-Print Loop), the "_" variable
|
||||
# is a special variable that is automatically assigned the result of the
|
||||
# last expression evaluated. The type of the "_" variable reflects the
|
||||
# type of the last expression evaluated in the REPL.
|
||||
@@ -0,0 +1,141 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2580
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
|
||||
{\colortbl;\red255\green255\blue255;\red26\green26\blue26;\red255\green255\blue255;}
|
||||
{\*\expandedcolortbl;;\cssrgb\c13333\c13333\c13333;\cssrgb\c100000\c100000\c100000;}
|
||||
\margl1440\margr1440\vieww11520\viewh8400\viewkind0
|
||||
\deftab720
|
||||
\pard\pardeftab720\parhyphenfactor20\partightenfactor0
|
||||
|
||||
\f0\fs32 \cf2 \cb3 \expnd0\expndtw0\kerning0
|
||||
1. What is a type hierarchy?\
|
||||
The type hierarchy in Python refers to the organization and relationships among different types or classes in the Python programming language. \
|
||||
It defines how types are related to each other and how they inherit attributes and behaviors from their parent types.\
|
||||
the type hierarchy in Python provides a structured organization of types, allowing for code reuse, inheritance, and polymorphism, which are fundamental principles of object-oriented programming.\
|
||||
\
|
||||
\
|
||||
\
|
||||
2. What is the difference between __repr__() and __str__()?\
|
||||
The __repr__() method is intended to provide a detailed and unambiguous representation of the object. It is primarily used for debugging and development purposes.\
|
||||
the __str__() method is used to provide a more user-friendly and readable representation of the object. It is intended for displaying the object to end-users.\
|
||||
\
|
||||
\
|
||||
\
|
||||
3. What is the range of an integer?\
|
||||
In Python 2, the int type is a fixed-size integer, typically represented using 32 bits or 64 bits depending on the platform. The maximum value for an int in Python 2 is sys.maxint, which is usually 2^31 - 1 or 2^63 - 1. Or you need to use \'91Long\'92 instead.\
|
||||
In Python 3, there is only one integer type, int, which behaves like the long type in Python 2. The int type in Python 3 can represent integers of arbitrary size limited only by the available memory.\
|
||||
\
|
||||
Ex:\
|
||||
import sys\
|
||||
\
|
||||
# Python 2\
|
||||
print(sys.maxint) # Output: 2147483647 (on most platforms)\
|
||||
\
|
||||
# Python 3\
|
||||
print(sys.maxsize) # Output: 9223372036854775807 (on most platforms)\
|
||||
\
|
||||
\
|
||||
\
|
||||
4. Why string is a immutable sequence but you can still assign or change the index from a string?\
|
||||
Strings are immutable sequences, which means that once a string is created, its elements cannot be modified. But you can still create new strings by using concatenation or string manipulation methods to achieve the desired modifications.\
|
||||
\
|
||||
\
|
||||
\
|
||||
5. Describe the __closure__ attribute.\
|
||||
The __closure__ attribute returns a tuple of cell objects, where each cell object represents a captured variable. \
|
||||
A cell object holds a reference to the variable's value, allowing the function to access and use the value even after the original scope has finished executing.\
|
||||
The cell objects stored in the __closure__ attribute have the cell_contents attribute, which provides direct access to the value of the captured variable.\
|
||||
\
|
||||
\
|
||||
\
|
||||
6. What is a code object and a function object? Any difference between them?\
|
||||
Code object:\
|
||||
A code object represents byte-compiled executable Python code, or bytecode. \
|
||||
It contains the instructions that make up the logic of a function, method, module, or other executable code. \
|
||||
The code object includes information such as the bytecode instructions, the constants used by the bytecode, the names used by the bytecode, the filename from which the code was compiled, and more. \
|
||||
Code objects are immutable and do not contain any references to mutable objects.\
|
||||
Function object:\
|
||||
A function object, on the other hand, is a callable object that represents a Python function. \
|
||||
It contains a reference to a code object, which defines the implementation of the function. \
|
||||
In addition to the code object, a function object also includes references to the function's globals (the module in which it was defined), the default argument values, and other attributes such as the function name, qualified function name, and more. \
|
||||
Function objects are mutable and can have additional attributes assigned to them.\
|
||||
\
|
||||
In summary, a code object represents the bytecode and metadata of Python code, while a function object is a callable object that encapsulates a code object and provides additional functionality, such as the ability to be called and have attributes assigned to it. A function object is essentially a runtime representation of a function defined in Python code, with the code object containing the actual implementation details.\
|
||||
\
|
||||
\
|
||||
\
|
||||
7. What is a traceback object and how we use it?\
|
||||
Traceback objects represent a stack trace of an exception. \
|
||||
They are created when an exception occurs and provide information about the sequence of function calls leading up to the exception.\
|
||||
\
|
||||
One way to use it we can figure it out by using \'91try\'85 except\'85\'92 function:\
|
||||
\
|
||||
try:\
|
||||
# Some code that may raise an exception\
|
||||
except Exception as e:\
|
||||
# Handle the exception\
|
||||
print("An exception occurred:", type(e).__name__)\
|
||||
print("Error message:", str(e))\
|
||||
\
|
||||
Exception is the base class for all built-in exceptions in Python. \
|
||||
It is a superclass that encompasses a wide range of exceptions, such as TypeError, ValueError, NameError, and many others. \
|
||||
By using Exception in the except statement, you catch any exception that is raised during the execution of the try block.\
|
||||
\
|
||||
\
|
||||
\
|
||||
8. What is the \'91auditing event\'92 meaning?\
|
||||
It refers to a mechanism in Python that allows custom auditing or monitoring of attribute access on objects. When accessing the tb_frame attribute of a traceback object, an auditing event of type __getattr__ is raised. This event provides an opportunity to intercept and customize the attribute access behavior, if desired.\
|
||||
\
|
||||
In simple terms, an auditing event is a way to track or log attribute access on objects for monitoring or auditing purposes. It allows you to observe and potentially modify the behavior when accessing specific attributes.\
|
||||
\
|
||||
The auditing events are specific to the implementation of Python and are typically used in specialized scenarios where attribute access needs to be monitored or customized.\
|
||||
\
|
||||
\
|
||||
\
|
||||
9. How to find the common values and different values from two lists?\
|
||||
list1 = [1, 2, 3, 4, 6]\
|
||||
list2 = [2, 4, 6, 7, 8]\
|
||||
\
|
||||
# Find common values\
|
||||
common_values = []\
|
||||
for item in list1:\
|
||||
if item in list2:\
|
||||
common_values.append(item)\
|
||||
\
|
||||
# Find different values\
|
||||
different_values = []\
|
||||
for item in list1:\
|
||||
if item not in list2:\
|
||||
different_values.append(item)\
|
||||
for item in list2:\
|
||||
if item not in list1:\
|
||||
different_values.append(item)\
|
||||
\
|
||||
print("Common values:", common_values) # Common values: [2, 4, 6]\
|
||||
print("Different values:", different_values) # Different values: [1, 3, 7, 8]\
|
||||
\
|
||||
\
|
||||
\
|
||||
# Or there is another way to do this by using set() method\
|
||||
# Find common values\
|
||||
common_values = set(list1) & set(list2) # The '&' operator performs an intersection\
|
||||
\
|
||||
# Find different values\
|
||||
different_values = set(list1) ^ set(list2) # The '^' operator performs a symmetric difference\
|
||||
\
|
||||
print("Common values:", common_values) # Common values: \{2, 4, 6\}\
|
||||
print("Different values:", different_values) # Different values: \{1, 3, 7, 8\}\
|
||||
\
|
||||
\
|
||||
\
|
||||
10. The difference between list and set?\
|
||||
In summary, lists are ordered, allow duplicate elements, and are mutable. \
|
||||
Sets are unordered, do not allow duplicates, and are also mutable. \
|
||||
\
|
||||
The following detailed explanations are provided by AI:\
|
||||
1. Order: Lists are ordered collections, meaning they preserve the order of elements. Each element in a list has an index associated with it. Sets, on the other hand, are unordered collections. They do not preserve the original order of elements and do not have indices.\
|
||||
2. Duplicate elements: Lists allow duplicate elements, which means you can have multiple occurrences of the same value in a list. Sets, on the other hand, do not allow duplicate elements. Each element in a set is unique.\
|
||||
3. Mutable vs. Immutable: Lists are mutable, which means you can modify individual elements, add new elements, or remove elements from a list. Sets are also mutable, allowing the addition and removal of elements. However, you cannot modify individual elements in a set since they are unordered.\
|
||||
4. Membership testing: Checking for membership (whether an element exists in a collection) is faster in sets compared to lists. Sets use a hashing mechanism that provides efficient membership testing, while lists require iterating over the elements to check for membership.\
|
||||
5. Mathematical set operations: Sets support various set operations like union, intersection, difference, and symmetric difference. These operations can be performed using operators (|, &, -, ^) or methods. Lists do not provide built-in operations for set operations.\
|
||||
6. Data uniqueness: Sets are often used to ensure the uniqueness of elements in a collection. You can easily eliminate duplicates from a list by converting it to a set and then back to a list if the order of elements is not important.\
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2580
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
|
||||
{\colortbl;\red255\green255\blue255;\red26\green26\blue26;\red255\green255\blue255;\red39\green40\blue50;
|
||||
}
|
||||
{\*\expandedcolortbl;;\cssrgb\c13333\c13333\c13333;\cssrgb\c100000\c100000\c100000;\cssrgb\c20392\c20784\c25490;
|
||||
}
|
||||
\margl1440\margr1440\vieww28300\viewh14980\viewkind0
|
||||
\deftab720
|
||||
\pard\pardeftab720\parhyphenfactor20\partightenfactor0
|
||||
|
||||
\f0\fs32 \cf2 \cb3 \expnd0\expndtw0\kerning0
|
||||
CPython implementation detail: CPython currently uses a reference-counting scheme with (optional) delayed detection of cyclically linked garbage, which collects most objects as soon as they become unreachable, but is not guaranteed to collect garbage containing circular references.\
|
||||
\
|
||||
What is a reference-counting scheme?\
|
||||
It refers to a memory management technique where each object in a programming language implementation, such as CPython, keeps track of the number of references pointing to it. \
|
||||
Whenever a reference is created to an object, its reference count is increased, and when a reference is deleted or goes out of scope, the reference count is decreased. \
|
||||
\
|
||||
What is a reference?\
|
||||
In the context of memory management, a "reference" refers to an identifier or value that allows access to an object in a programming language. \
|
||||
It is a way to refer to or point to the memory location where an object is stored.\
|
||||
\
|
||||
What is the advantage of reference-counting scheme?\
|
||||
The advantage of the reference-counting scheme is that it allows objects to be deallocated immediately when they are no longer needed. \
|
||||
It ensures efficient memory management because objects can be freed as soon as their reference count reaches zero, without the need for more complex garbage collection algorithms.\
|
||||
\
|
||||
What is a garbage?\
|
||||
In the context of memory management, "garbage" refers to objects that are no longer reachable or used by the program but still occupy memory. \
|
||||
This typically occurs when objects are created dynamically during program execution but are not properly deallocated or no longer accessible. \
|
||||
Garbage collection is the process of identifying and reclaiming memory occupied by such unused objects, making it available for reuse. \
|
||||
The reference-counting scheme used by CPython helps in automatically deallocating most objects as soon as they become unreachable. \
|
||||
However, in the case of circular references, where objects refer to each other in a loop, additional mechanisms are required to detect and collect such cyclically linked garbage. It\'92s called "delayed detection of cyclically linked garbage" to collect and deallocate objects that are involved in cyclic references.\
|
||||
\
|
||||
\
|
||||
\
|
||||
What is a __blabla__(): method?\
|
||||
In Python, the following are special attributes (also known as dunder attributes) that can be accessed on objects or functions.\
|
||||
These special attributes provide additional information or access to specific properties of objects in Python. \
|
||||
\
|
||||
What is the advantages of the dunder method?\
|
||||
Overall, dunder attributes provide flexibility, customization, and enhanced functionality to Python objects and classes. \
|
||||
They contribute to the expressive nature of the language and enable powerful features like operator overloading and introspection.\
|
||||
\
|
||||
Convention: Dunder attributes follow a specific naming convention, starting and ending with double underscores (__). This convention makes them easily recognizable and distinguishes them from regular attributes.\
|
||||
Customization: Dunder attributes allow you to customize and define the behavior of objects and classes. By implementing specific dunder methods, you can change how objects behave in certain situations, such as arithmetic operations, string representation, comparisons, and more.\
|
||||
Operator Overloading: Dunder attributes enable operator overloading, allowing objects to participate in built-in operations like addition (+), subtraction (-), equality (==), and more. This makes it possible to define meaningful operations for custom classes.\
|
||||
Introspection: Dunder attributes provide a way to introspect and access information about objects and classes. For example, name and doc allow you to retrieve the name and documentation of an object. This introspection capability is useful for debugging, documentation generation, and code analysis.\
|
||||
Integration with Language Features: Dunder attributes seamlessly integrate with various language features, such as iteration (with iter), context managers (with enter and exit), attribute access (with getattr, setattr), and more. This allows you to leverage the full power of the Python language in your classes.\
|
||||
Code Readability: By following the conventions for dunder attributes, your code becomes more readable and understandable by other Python developers. They can easily recognize and understand the purpose of these special attributes.\
|
||||
\
|
||||
\
|
||||
\
|
||||
What is a Von Neumann\'92s model of a \'93stored program computer\'94?\
|
||||
Von Neumann's model of a "stored program computer" is a fundamental concept in computer architecture that describes the organization and operation of modern digital computers.\
|
||||
It describes a computer architecture where instructions and data are stored together in memory, enabling the execution of instructions as data, and forming the basis of programmable digital computers.\
|
||||
The distinguishing feature of Von Neumann's model is that both data and instructions are stored in the same memory. This means that the instructions that govern the computer's operations can be treated as data and manipulated like any other type of information. This concept, known as the "stored program concept," allows for the flexibility and programmability of modern computers.\
|
||||
\
|
||||
\
|
||||
\
|
||||
\
|
||||
\pard\pardeftab720\partightenfactor0
|
||||
\cf4 \cb1 What is the difference between identity and type?\
|
||||
Identity: \
|
||||
The identity of an object is a unique identifier that remains constant throughout the object's lifetime. \
|
||||
It can be thought of as the object's address in memory. \
|
||||
Python provides a built-in function called id() that returns an integer representing the identity of an object. \
|
||||
The identity never changes once the object is created, and no two objects can have the same identity at the same time.\
|
||||
Type: \
|
||||
The type of an object defines the category or class to which the object belongs. \
|
||||
It determines the behavior of the object and the operations that can be performed on it. \
|
||||
In Python, the type of an object is determined by its class, which defines the object's characteristics and behavior. \
|
||||
The type of an object can be obtained using the type() function.\
|
||||
\
|
||||
To summarize, the identity of an object is a unique identifier associated with its memory location, while the type of an object defines its category or class, determining its behavior and the operations that can be performed on it.\
|
||||
\
|
||||
\
|
||||
\
|
||||
The important distinction between immutability and having an unchangeable value in the context of container objects that reference mutable objects in Python.\
|
||||
In Python, immutability refers to the property of an object that prevents its internal state or structure from being modified after it is created. Immutable objects, such as integers, strings, and tuples, cannot be changed once they are created. However, when an immutable container object (like a tuple or a frozenset) contains a reference to a mutable object (such as a list or a set), the value of the mutable object can be modified even though the container object itself cannot be changed.\
|
||||
So, while the value of the mutable object can be altered, the container object is still considered immutable because its internal structure (the collection of objects it contains) cannot be changed. The container object cannot be modified to add, remove, or replace elements, but the mutable object it references can be modified independently.\
|
||||
Therefore, the concept of immutability is more subtle than simply having an unchangeable value. It refers to the inability to modify the structure or internal state of an object, but it doesn't necessarily guarantee that all the objects referenced by an immutable container are themselves immutable.\
|
||||
\
|
||||
\
|
||||
\
|
||||
What is a close() method in Python?\
|
||||
The close() method is typically invoked on an object representing the file or resource. \
|
||||
Calling the close() method can release the associated system resources and ensure that any buffered data is written to the disk.\
|
||||
\
|
||||
It's important to note that closing a file or resource is good practice to free up system resources and prevent any potential issues. Failing to close resources properly can result in resource leaks and may lead to unexpected behavior in your program.\
|
||||
\
|
||||
\
|
||||
\
|
||||
\'93try...finally\'94 statement:\
|
||||
The try...finally statement is used to ensure that certain code is always executed, regardless of whether an exception occurs or not. \
|
||||
The code within the try block is executed, and if an exception occurs, it can be caught and handled using an appropriate except block. After the try block (and any associated except blocks), the code within the finally block is executed, ensuring that it always runs, regardless of exceptions. This is useful for cleaning up resources or releasing locks, even if an exception occurs.\cf2 \cb3 \
|
||||
\pard\pardeftab720\parhyphenfactor20\partightenfactor0
|
||||
\cf2 \
|
||||
\
|
||||
\
|
||||
\'93with\'94 statement:\
|
||||
The with statement provides automatic resource management, improves code readability, handles exceptions effectively, and allows for the creation of custom context managers. It is a recommended approach for managing resources that need proper initialization and cleanup, such as files, database connections, network sockets, and more. By using the with statement, you can ensure that your code is more robust, maintainable, and less prone to resource leaks and error handling issues.\
|
||||
\
|
||||
\
|
||||
\
|
||||
What is a container?\
|
||||
A container refers to an object that can hold multiple other objects or values. \
|
||||
Examples of containers in Python include tuples, lists, dictionaries, sets, and other collection types.\
|
||||
Containers are used to store and organize multiple objects or values together. They provide a way to group related data and operate on them as a whole. \
|
||||
\
|
||||
\
|
||||
\
|
||||
What is a type hierarchy?\
|
||||
The type hierarchy in Python refers to the organization and relationships among different types or classes in the Python programming language. \
|
||||
It defines how types are related to each other and how they inherit attributes and behaviors from their parent types.\
|
||||
the type hierarchy in Python provides a structured organization of types, allowing for code reuse, inheritance, and polymorphism, which are fundamental principles of object-oriented programming.\
|
||||
\
|
||||
\
|
||||
\
|
||||
## The attached file HW7_test.py provides an example on how dunder method works. Don\'92t forget to check it out.}
|
||||
@@ -0,0 +1,156 @@
|
||||
# 3.3 Reading Note
|
||||
|
||||
They have same output:
|
||||
|
||||
```Python
|
||||
class MyClass:
|
||||
def __getitem__(self, index):
|
||||
return f"Item at index {index}"
|
||||
|
||||
x = MyClass()
|
||||
item = x[3]
|
||||
print(item) # Output: Item at index 3
|
||||
```
|
||||
```Python
|
||||
# Equivalent to type(x).\_\_getitem\_\_(x, 3)
|
||||
item = type(x).__getitem__(x, 3)
|
||||
print(item) # Output: Item at index 3
|
||||
```
|
||||
|
||||
---
|
||||
## 3.3.1
|
||||
|
||||
|
||||
1. The object.\_\_new\_\_() method is a special method in Python that is called to create a new instance of a class. It is responsible for the low-level creation of an object before its initialization.
|
||||
|
||||
2. The object.\_\_init\_\_() method is a special method in Python that is called after an instance of a class has been created by the \_\_new\_\_() method. It is responsible for initializing the object's attributes and performing any necessary setup.
|
||||
|
||||
3. The object.\_\_del\_\_() method is a special method in Python that is called when an instance of a class is about to be destroyed or garbage-collected.
|
||||
|
||||
4. The cyclic garbage collector in CPython is responsible for detecting and breaking reference cycles, ensuring that memory is properly deallocated even in the presence of reference cycles.
|
||||
|
||||
5. the \_\_format\_\_() method allows objects to define their own customized string representations when used with format-related operations.
|
||||
|
||||
6. x < y calls x.\_\_lt\_\_(y)
|
||||
x <= y calls x.\_\_le\_\_(y)
|
||||
x == y calls x.\_\_eq\_\_(y)
|
||||
x != y calls x.\_\_ne\_\_(y)
|
||||
x > y calls x.\_\_gt\_\_(y)
|
||||
x >= y calls x.\_\_ge\_\_(y)
|
||||
|
||||
---
|
||||
## 3.3.2
|
||||
|
||||
### 3.3.2.1
|
||||
|
||||
1. The methods \_\_get\_\_, \_\_set\_\_, and \_\_delete\_\_ are used to implement descriptors in Python. Descriptors are a way to customize attribute access in classes. These methods are defined in a descriptor class, and when an instance of the descriptor class is present in an owner class, they are invoked to control attribute access.
|
||||
|
||||
### 3.3.2.2
|
||||
1. In Python, a descriptor is an object attribute that has "binding behavior" due to the overriding of attribute access through methods in the descriptor protocol: \_\_get\_\_(), \_\_set\_\_(), and \_\_delete\_\_(). If an object defines any of these methods, it is considered a descriptor.
|
||||
|
||||
### 3.3.2.4
|
||||
1. Using \_\_slots\_\_ can save significant memory compared to using \_\_dict\_\_, and it can also improve attribute lookup speed.
|
||||
|
||||
---
|
||||
## 3.3.3
|
||||
1.
|
||||
``` Python
|
||||
class Philosopher:
|
||||
def __init_subclass__(cls, /, default_name, **kwargs):
|
||||
super().__init_subclass__(**kwargs)
|
||||
cls.default_name = default_name
|
||||
|
||||
class AustralianPhilosopher(Philosopher, default_name="Bruce"):
|
||||
pass
|
||||
```
|
||||
|
||||
This code sets up a base class called Philosopher that defines a custom behavior for its subclasses when they are created.
|
||||
|
||||
The default_name parameter allows each subclass to have a default name attribute, and the AustralianPhilosopher subclass demonstrates the usage by setting its default_name to "Bruce".
|
||||
|
||||
1. The purpose of \_\_set_name\_\_() is to provide a hook for objects to perform any necessary initialization or setup when they are assigned to a class attribute. It allows the objects to be aware of their assigned name within the class they belong to, which can be useful for various purposes such as introspection or customization.
|
||||
|
||||
### 3.3.3.1
|
||||
1. The C3 linearization algorithm is a method used to determine the order in which base classes are searched for a particular attribute or method during multiple inheritance in Python. It ensures that the resolution order respects the consistency and priority of the inheritance hierarchy.
|
||||
|
||||
### 3.3.3.2
|
||||
1. MRO (Method Resolution Order) entries are resolved: This refers to the determination of the order in which base classes are searched for a particular attribute or method. The MRO defines the inheritance hierarchy and is calculated using the C3 linearization algorithm.
|
||||
|
||||
---
|
||||
## 3.3.5
|
||||
1. Type annotations in Python refer to the practice of adding hints or metadata about the types of variables, function parameters, and return values in code. They are used to provide static type checking and improve code clarity, maintainability, and tooling support. They are optional and do not affect the runtime behavior of the code. Python remains a dynamically typed language, but type annotations allow developers to specify the expected types and enable type checking tools to catch potential errors.
|
||||
|
||||
``` Python
|
||||
x: int = 5
|
||||
def add(a: int, b: int) -> int:
|
||||
return a + b
|
||||
```
|
||||
|
||||
### 3.3.5.1
|
||||
1. The purpose of \_\_class_getitem\_\_() is to allow runtime parameterization of standard-library generic classes in order to more easily apply type hints to these classes.
|
||||
|
||||
The \_\_class_getitem\_\_() method is called when you use square brackets notation ([]) with a generic class to specify the type arguments. For example:
|
||||
|
||||
```Python
|
||||
from typing import List
|
||||
|
||||
# Define a generic class
|
||||
class MyGenericClass:
|
||||
...
|
||||
|
||||
# Use the generic class with type arguments
|
||||
my_instance = MyGenericClass[int]()
|
||||
```
|
||||
|
||||
In Python, generic classes are classes that can operate on different types of objects or collections in a flexible way. They are typically defined with type variables that represent the types of the objects or collections they work with. However, when using these generic classes, you need a way to specify the actual types you want to use.
|
||||
|
||||
In the example above, 'MyGenericClass[int]()' invokes the \_\_class_getitem\_\_() method of MyGenericClass to specify that the type argument for the generic class is int. This allows you to parameterize the generic class at runtime and apply type hints to it.
|
||||
|
||||
By implementing \_\_class_getitem\_\_() in your custom classes, you can enable similar behavior and allow runtime parameterization of your own generic classes.
|
||||
|
||||
2. What is the runtime parameterization?
|
||||
|
||||
**Runtime parameterization** refers to the ability to provide or specify parameters or arguments at runtime, rather than at compile time. It allows for dynamic customization or configuration of a program or component during its execution.
|
||||
|
||||
In the context of generic classes in Python, **runtime parameterization** refers to the ability to specify type arguments or type parameters for a generic class at runtime. Generic classes are designed to work with different types of objects or collections in a flexible way, and the specific types they operate on can be determined dynamically.
|
||||
|
||||
By allowing **runtime parameterization** of generic classes, you can provide the actual types or type arguments to be used when creating instances of the generic class. This enables you to customize the behavior or functionality of the generic class based on the specific types you need to work with in a particular situation.
|
||||
|
||||
**Runtime parameterization** of generic classes is commonly used in scenarios where the types involved may vary or depend on external factors. It provides flexibility and adaptability to handle different data types or collections dynamically, without requiring explicit type annotations or definitions at compile time.
|
||||
|
||||
---
|
||||
## 3.3.9
|
||||
|
||||
In this example, we define a 'FileManager' class that acts as a context manager for working with files.
|
||||
|
||||
```Python
|
||||
class FileManager:
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
|
||||
def __enter__(self):
|
||||
self.file = open(self.filename, 'w')
|
||||
return self.file
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.file.close()
|
||||
|
||||
# Usage of the context manager
|
||||
with FileManager('example.txt') as file:
|
||||
file.write('Hello, world!')
|
||||
```
|
||||
1. The *'\_\_enter\_\_'* method is responsible for setting up the runtime context, which in this case involves opening the specified file in write mode. The method returns the file object, which is then bound to the variable *'file'* in the *'with'* statement.
|
||||
|
||||
2. The *'\_\_exit\_\_'* method is called when exiting the runtime context. It is responsible for cleaning up any resources, in this case, closing the file. If an exception occurred within the *'with'* block, the exception information is passed to the *'\_\_exit\_\_'* method, allowing you to handle any necessary cleanup or error handling.
|
||||
|
||||
3. By using the *'with'* statement, the context manager automatically takes care of opening and closing the file for us. This ensures that the file is always closed, even if an exception occurs within the *'with'* block.
|
||||
|
||||
4. An explanation of the parameters in the *'\_\_exit\_\_'* method:
|
||||
|
||||
**self**: The self parameter refers to the instance of the class itself. It allows you to access the attributes and methods of the class within the '\_\_exit\_\_' method.
|
||||
|
||||
**exc_type**: This parameter represents the type of exception that occurred, if any. It will be None if no exception occurred within the with block.
|
||||
|
||||
**exc_value**: This parameter holds the instance of the exception that occurred, if any. Like exc_type, it will be None if no exception occurred.
|
||||
|
||||
**traceback**: The traceback parameter is a traceback object that encapsulates the call stack at the point where the exception occurred. It provides information about the line numbers and file names leading up to the exception.
|
||||
@@ -0,0 +1,68 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2580
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
{\*\expandedcolortbl;;}
|
||||
\margl1440\margr1440\vieww28300\viewh17700\viewkind0
|
||||
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
|
||||
|
||||
\f0\fs24 \cf0 1. They have same output:\
|
||||
class MyClass:\
|
||||
def __getitem__(self, index):\
|
||||
return f"Item at index \{index\}"\
|
||||
\
|
||||
x = MyClass()\
|
||||
item = x[3]\
|
||||
print(item) # Output: Item at index 3\
|
||||
\
|
||||
# Equivalent to type(x).__getitem__(x, 3)\
|
||||
item = type(x).__getitem__(x, 3)\
|
||||
print(item) # Output: Item at index 3\
|
||||
\
|
||||
2. The object.__new__() method is a special method in Python that is called to create a new instance of a class. It is responsible for the low-level creation of an object before its initialization. \
|
||||
\
|
||||
3. The object.__init__() method is a special method in Python that is called after an instance of a class has been created by the __new__() method. It is responsible for initializing the object's attributes and performing any necessary setup.\
|
||||
\
|
||||
4. The object.__del__() method is a special method in Python that is called when an instance of a class is about to be destroyed or garbage-collected.\
|
||||
\
|
||||
5. The cyclic garbage collector in CPython is responsible for detecting and breaking reference cycles, ensuring that memory is properly deallocated even in the presence of reference cycles.\
|
||||
\
|
||||
6. the __format__() method allows objects to define their own customized string representations when used with format-related operations.\
|
||||
\
|
||||
7. x < y calls x.__lt__(y)\
|
||||
x <= y calls x.__le__(y)\
|
||||
x == y calls x.__eq__(y)\
|
||||
x != y calls x.__ne__(y)\
|
||||
x > y calls x.__gt__(y)\
|
||||
x >= y calls x.__ge__(y)\
|
||||
\
|
||||
8. The methods __get__, __set__, and __delete__ are used to implement descriptors in Python. Descriptors are a way to customize attribute access in classes. These methods are defined in a descriptor class, and when an instance of the descriptor class is present in an owner class, they are invoked to control attribute access.\
|
||||
\
|
||||
9. In Python, a descriptor is an object attribute that has "binding behavior" due to the overriding of attribute access through methods in the descriptor protocol: __get__(), __set__(), and __delete__(). If an object defines any of these methods, it is considered a descriptor.\
|
||||
\
|
||||
10. Using __slots__ can save significant memory compared to using __dict__, and it can also improve attribute lookup speed.\
|
||||
\
|
||||
11. class Philosopher:\
|
||||
def __init_subclass__(cls, /, default_name, **kwargs):\
|
||||
super().__init_subclass__(**kwargs)\
|
||||
cls.default_name = default_name\
|
||||
\
|
||||
class AustralianPhilosopher(Philosopher, default_name="Bruce"):\
|
||||
pass\
|
||||
\
|
||||
\
|
||||
This code sets up a base class called Philosopher that defines a custom behavior for its subclasses when they are created. \
|
||||
The default_name parameter allows each subclass to have a default name attribute, and the AustralianPhilosopher subclass demonstrates the usage by setting its default_name to "Bruce".\
|
||||
\
|
||||
12. The purpose of __set_name__() is to provide a hook for objects to perform any necessary initialization or setup when they are assigned to a class attribute. It allows the objects to be aware of their assigned name within the class they belong to, which can be useful for various purposes such as introspection or customization.\
|
||||
\
|
||||
13. The C3 linearization algorithm is a method used to determine the order in which base classes are searched for a particular attribute or method during multiple inheritance in Python. It ensures that the resolution order respects the consistency and priority of the inheritance hierarchy.\
|
||||
\
|
||||
14. MRO (Method Resolution Order) entries are resolved: This refers to the determination of the order in which base classes are searched for a particular attribute or method. The MRO defines the inheritance hierarchy and is calculated using the C3 linearization algorithm.\
|
||||
\
|
||||
15. Type annotations in Python refer to the practice of adding hints or metadata about the types of variables, function parameters, and return values in code. They are used to provide static type checking and improve code clarity, maintainability, and tooling support. They are optional and do not affect the runtime behavior of the code. Python remains a dynamically typed language, but type annotations allow developers to specify the expected types and enable type checking tools to catch potential errors.\
|
||||
\
|
||||
x: int = 5\
|
||||
def add(a: int, b: int) -> int:\
|
||||
return a + b\
|
||||
\
|
||||
16. The purpose of __class_getitem__() is to allow runtime parameterization of standard-library generic classes in order to more easily apply type hints to these classes.}
|
||||
@@ -0,0 +1,46 @@
|
||||
class BoundedInt():
|
||||
def __init__(self, i, min, max):
|
||||
"""
|
||||
Create a bounded integer.
|
||||
|
||||
Args:
|
||||
i (int): The initial value of the integer.
|
||||
min (int): The minimum value of the integer.
|
||||
max (int): The maximum value of the integer.
|
||||
"""
|
||||
self.i = i
|
||||
self.min = min
|
||||
self.max = max
|
||||
|
||||
def __int__(self):
|
||||
"""
|
||||
Convert the bounded integer to int.
|
||||
|
||||
Returns:
|
||||
int: The value of the bounded integer.
|
||||
"""
|
||||
return self.i
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, BoundedInt):
|
||||
if self.i + other.i > self.max:
|
||||
raise ValueError("Addition exceeds maximum value")
|
||||
return BoundedInt(self.i + other.i, self.min, self.max)
|
||||
elif isinstance(other, int):
|
||||
if self.i + other > self.max:
|
||||
raise ValueError("Addition exceeds maximum value")
|
||||
return BoundedInt(self.i + other, self.min, self.max)
|
||||
else:
|
||||
raise TypeError("Unsupported operand type")
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, BoundedInt):
|
||||
if self.i - other.i < self.min:
|
||||
raise ValueError("Subtraction exceeds minimum value")
|
||||
return BoundedInt(self.i - other.i, self.min, self.max)
|
||||
elif isinstance(other, int):
|
||||
if self.i - other < self.min:
|
||||
raise ValueError("Subtraction exceeds minimum value")
|
||||
return BoundedInt(self.i - other, self.min, self.max)
|
||||
else:
|
||||
raise TypeError("Unsupported operand type")
|
||||
@@ -0,0 +1,67 @@
|
||||
from BoundedInt import BoundedInt
|
||||
|
||||
class BoundedIntTester:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def test1(self):
|
||||
bi1 = BoundedInt(0xdeadbeef, min = (0xdeadbeef-1), max = (0xdeadbeef+1))
|
||||
if int(bi1) == 0xdeadbeef:
|
||||
print(f"✅ Test 1 passed!")
|
||||
else:
|
||||
print(f"❌ Test 1 failed, int(bi1) = {int(bi1)}, expected 0xdeadbeef")
|
||||
|
||||
def test2(self):
|
||||
"""
|
||||
Test that addition works for two BoundedInts, and throws an error if the bounds are exceeded.
|
||||
"""
|
||||
bi2 = BoundedInt(1, min = 0, max = 1)
|
||||
bi3 = BoundedInt(1, min = 0, max = 1)
|
||||
try:
|
||||
bi4 = bi2 + bi3 # 1 + 1 = 2, which is more than max = 1
|
||||
print(f"❌ Test 2 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 2 passed!")
|
||||
|
||||
def test3(self):
|
||||
"""
|
||||
Test that addition works for two BoundedInts, and throws an error if the bounds are exceeded.
|
||||
"""
|
||||
bi4 = BoundedInt(1, min = 0, max = 1)
|
||||
bi5 = BoundedInt(2, min = 0, max = -1)
|
||||
try:
|
||||
bi6 = bi4 - bi5 # 1 - 2 = (-1), which is less than min = 0
|
||||
print(f"❌ Test 3 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 3 passed!")
|
||||
|
||||
def test4(self):
|
||||
"""
|
||||
Test that addition works for a BoundedInt and a regular int, and throws an error if the bounds are exceeded.
|
||||
"""
|
||||
bi7 = BoundedInt(1, min = 0, max = 1)
|
||||
bi8 = 2
|
||||
try:
|
||||
bi9 = bi7 + bi8
|
||||
print(f"❌ Test 4 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 4 passed!")
|
||||
|
||||
def test5(self):
|
||||
"""
|
||||
Test that subtraction works for a BoundedInt and a regular int, and throws an error if the bounds are exceeded.
|
||||
"""
|
||||
bi10 = BoundedInt(1, min = 0, max = 1)
|
||||
bi11 = 2
|
||||
try:
|
||||
bi12 = bi10 - 11
|
||||
print(f"❌ Test 5 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 5 passed!")
|
||||
|
||||
tester = BoundedIntTester()
|
||||
tester.test1()
|
||||
tester.test2()
|
||||
tester.test3()
|
||||
tester.test4()
|
||||
tester.test5()
|
||||
@@ -0,0 +1,63 @@
|
||||
# 1. Why does ord("😀") give a different number than 0xf09f9880, which is what the hexdump of the same character yields?
|
||||
#
|
||||
# The ord() function returns the Unicode code point of a character as an integer, which is 128512 for the smiley face.
|
||||
# However, the hexdump command, returns the UTF-8 encoding of character.
|
||||
# The hexadecimal representation of 128512 is 0x1F600.
|
||||
# The UTF-8 encoding of the "😀" character is represented by the sequence of bytes F0 9F 98 80 in hexadecimal.
|
||||
# UTF-8 is one of the encoding schemes used to represent Unicode characters as binary data.
|
||||
#
|
||||
#
|
||||
# 8. Hypothetical Situation: If the dataframe is not formatted or cleaned, while the column storing the tomoto sales data isn't named exactly same as 'Tomato_Sales'
|
||||
# It will raise a KeyError instead.
|
||||
#
|
||||
#
|
||||
# 9. The solution of the hypothetical situation from my question 8:
|
||||
|
||||
def read_tomato_sales(file_name):
|
||||
data = pd.read_csv(file_name)
|
||||
if not pd.api.types.is_numeric_dtype(data["Tomato_Sales"]):
|
||||
raise TypeError("Tomato_Sales column should contain only numeric values")
|
||||
total_sales = data.iloc[:, -1].sum() # This is the key
|
||||
print(f"Total tomato sales: {total_sales}")
|
||||
# read_tomato_sales("tomato_sales_error.csv")
|
||||
|
||||
|
||||
# 10. Different human languages can use various character encodings such as UTF-8, UTF-16, or ASCII.
|
||||
# While using bytes, you can work with raw data without worrying about specific encodings.
|
||||
# This allows us to avoid encoding-related errors and ensures compatibility across different language texts.
|
||||
|
||||
def encode_decode_data():
|
||||
print('-' * 20)
|
||||
data = input("Enter a sentence using any language: ")
|
||||
print('-' * 20)
|
||||
print("The sentence you entered is: {}".format(data))
|
||||
print('-' * 20)
|
||||
encoded_data = data.encode('utf-8')
|
||||
print("This sentence after encoded is: {}".format(encoded_data))
|
||||
print('-' * 20)
|
||||
byte_length = len(encoded_data)
|
||||
print("The byte length of this sentence is: {}".format(byte_length))
|
||||
print('-' * 20)
|
||||
decoded_data = encoded_data.decode()
|
||||
print("This sentence after decoded is: {}".format(decoded_data))
|
||||
print('-' * 20)
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_function = 'function1'
|
||||
|
||||
if run_function == 'function1':
|
||||
encode_decode_data()
|
||||
elif run_function == 'function2':
|
||||
read_tomato_sales(file_name)
|
||||
|
||||
|
||||
# 2.5. REPL stands for Read-Eval-Print Loop.
|
||||
# A REPL is an interactive programming environment that allows you to read input, evaluate expressions or statements, print output, and repeat the process.
|
||||
# It provides a quick way to experiment with code, test small snippets, and get immediate feedback.
|
||||
# The Python REPL allows you to interactively enter Python code and see the results immediately without needing to write a full script and execute it separately.
|
||||
|
||||
|
||||
# 3. The '_' is a convention that holds the value of the last printed expression or the result of the last evaluated expression.
|
||||
# The actual type of the "_" variable depends on the value assigned to it.
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
# 1. Annotate the following python expressions with the specific types of each literal, as well as the overall return value:
|
||||
# i = 3
|
||||
# f = 3.0
|
||||
# c = 3+3j
|
||||
# b = b'abcdefg'
|
||||
# s = 'abcdefg'
|
||||
# s = "abcdefg"
|
||||
|
||||
i = 3
|
||||
f = 3.0
|
||||
c = 3+3j
|
||||
b = b'abcdefg'
|
||||
s1 = 'abcdefg'
|
||||
s2 = "abcdefg"
|
||||
|
||||
def check_the_datatype():
|
||||
print()
|
||||
print('This is the answer for Q1:')
|
||||
print()
|
||||
variable_names = ['i', 'f', 'c', 'b', 's1', 's2']
|
||||
data_list = [i, f, c, b, s1, s2]
|
||||
for variable, data in zip(variable_names, data_list):
|
||||
print("The type of this assigned value {} = {} is: {}".format(variable, data, type(data).__name__))
|
||||
|
||||
|
||||
|
||||
# 2. For each of the types string, bytestring, integer, floating point, and imaginary literals,
|
||||
# construct a 5x5 table showing what happens when the character "0" or number 0 is compared to each other type
|
||||
|
||||
from tabulate import tabulate
|
||||
from termcolor import colored
|
||||
|
||||
from tabulate import tabulate
|
||||
from termcolor import colored
|
||||
|
||||
def tablesQ2():
|
||||
print()
|
||||
print('-' * 20)
|
||||
print()
|
||||
print('This is the answer for Q2:')
|
||||
print()
|
||||
types = ["String", "Byte String", "Integer", "Floating Point", "Imaginary"]
|
||||
literals = ['"0"', 'b"0"', '0', '0.0', '0j']
|
||||
|
||||
table_data = []
|
||||
|
||||
for type_ in types:
|
||||
|
||||
row = [type_]
|
||||
|
||||
for literal in literals:
|
||||
|
||||
if type_ == "String":
|
||||
result = literal == '"0"'
|
||||
elif type_ == "Byte String":
|
||||
result = literal.encode() == b"0"
|
||||
elif type_ == "Integer":
|
||||
try:
|
||||
result = int(literal) == 0
|
||||
except ValueError:
|
||||
result = False
|
||||
elif type_ == "Floating Point":
|
||||
try:
|
||||
result = float(literal) == 0.0
|
||||
except ValueError:
|
||||
result = False
|
||||
elif type_ == "Imaginary":
|
||||
result = literal.replace('j', 'j0') == "0j"
|
||||
color = 'green' if result else 'red'
|
||||
colored_result = colored(result, color)
|
||||
row.append(colored_result)
|
||||
|
||||
table_data.append(row)
|
||||
|
||||
table = tabulate(table_data, headers=["Type"] + literals, tablefmt="pipe")
|
||||
print(table)
|
||||
|
||||
|
||||
|
||||
# 3. Now do the same thing for the + and == operators for each pair of types in two other 5x5 tables.
|
||||
|
||||
def tablesQ3():
|
||||
print()
|
||||
print('-' * 20)
|
||||
print()
|
||||
print('This is the answer for Q3:')
|
||||
print()
|
||||
|
||||
operators = ["+", "=="]
|
||||
types = ["str", "bytes", "int", "float", "complex"]
|
||||
literals = ['"0"', 'b"0"', '0', '0.0', '0+0j']
|
||||
|
||||
for operator in operators:
|
||||
print(f"Table for {operator} Operator:")
|
||||
table_data = []
|
||||
|
||||
for type_ in types:
|
||||
row = [type_]
|
||||
|
||||
for literal in literals:
|
||||
try:
|
||||
result = eval(f"{literal} {operator} {type_}({literal})")
|
||||
color = 'green'
|
||||
except TypeError:
|
||||
result = False
|
||||
color = 'red'
|
||||
|
||||
colored_result = colored(result, color)
|
||||
row.append(colored_result)
|
||||
|
||||
table_data.append(row)
|
||||
|
||||
table = tabulate(table_data, headers=["Type"] + literals, tablefmt="pipe")
|
||||
print(table)
|
||||
print()
|
||||
|
||||
|
||||
|
||||
# Write a small program that uses the AST module to open the lexer/parser example, and dumps the resulting AST.
|
||||
# See if there are any arguments to the parse method which make the output easier to read.
|
||||
|
||||
# By default, ast.dump() prints the AST in a compact format.
|
||||
# However, there are two optional arguments that can enhance the readability:
|
||||
# indent: Specifies the number of spaces to use for indentation. Setting it to a positive integer (e.g., 4) indents each level of the AST by that amount.
|
||||
# annotate_fields: When set to True, adds field names as comments to the output, making it easier to identify each part of the AST.
|
||||
|
||||
import ast
|
||||
|
||||
def dump_ast(filename):
|
||||
with open(filename, 'r') as file:
|
||||
source_code = file.read()
|
||||
|
||||
try:
|
||||
tree = ast.parse(source_code)
|
||||
ast_dump = ast.dump(tree, indent=4, annotate_fields=True)
|
||||
print(ast_dump)
|
||||
except SyntaxError as e:
|
||||
print(f"Syntax error in {filename}: {e}")
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_the_datatype()
|
||||
tablesQ2()
|
||||
tablesQ3()
|
||||
print()
|
||||
@@ -0,0 +1,91 @@
|
||||
# 5. What does this do? print("\007") Can you figure out why?
|
||||
|
||||
# It is a ASCII Bell character.
|
||||
# It generates a beep sound or a system alert depending on the platform and environment where the code is executed.
|
||||
# It is often used to trigger attention or alert the user in certain situations or as a way to generate a simple sound signal in text-based interfaces.
|
||||
|
||||
# BUT NOTHING HAPPENED ON MAC.
|
||||
|
||||
|
||||
|
||||
# 6. What does this do? print("abcdefg\rhijklmnop") Can you figure out why?
|
||||
|
||||
# '\r' is a carriage return character
|
||||
# When the string is printed, the carriage return character '\r' causes the cursor to return to the beginning of the line.
|
||||
# So when "hijklmnop" is printed, the cursor moves back to the start of the line, and the subsequent text "abcdefg" overwrites the initial characters.
|
||||
|
||||
# The output is gonna be 'hijklmnop'.
|
||||
|
||||
|
||||
|
||||
# 7. To shut down the HTTP server afterward, using Ctrl + C to interrupt the execution of the Python program.
|
||||
|
||||
import http.server
|
||||
import socketserver
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
class MyRequestHandler(http.server.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'text/plain')
|
||||
self.end_headers()
|
||||
output_string = "abcdefg\rhijklmnop"
|
||||
self.wfile.write(output_string.encode())
|
||||
|
||||
PORT = 8000
|
||||
Handler = MyRequestHandler
|
||||
httpd = socketserver.TCPServer(("", PORT), Handler)
|
||||
print(f"Serving on port {PORT}")
|
||||
|
||||
httpd.serve_forever()
|
||||
|
||||
# The HTTP server sends the response over the network to the client, which is typically a web browser.
|
||||
# In this function, the server sends an HTTP response with a status code of 200 and a content type of "text/plain".
|
||||
# The response body is set to the string "abcdefg\rhijklmnop" encoded as bytes.
|
||||
# When the client receives this response, it interprets the \r character as a normal character and displays the entire string "abcdefg\rhijklmnop" as it is.
|
||||
|
||||
# The '\r' character is a carriage return character, which is a control character used to return the cursor to the beginning of the current line.
|
||||
# The behavior of the carriage return character '\r' can depend on the platform and how the output is handled.
|
||||
|
||||
# For example:
|
||||
# In Safari and Chrome, the "http://localhost:8000" shows:
|
||||
# abcdefg
|
||||
# hijklmnop
|
||||
# In Macbook Terminal, the "curl http://localhost:8000" shows:
|
||||
# hijklmnop%
|
||||
|
||||
|
||||
|
||||
# 8. Think of a way someone might try to commit a crime or hide an embezzlement scheme using the answers to the above two questions.
|
||||
|
||||
# The key is by manipulating or altering the output displayed on a web page versus what is actually happening in the system.
|
||||
|
||||
# Case 1:
|
||||
# Show the false financial transactions to earn the cut.
|
||||
# Case 2:
|
||||
# Delivey the heist planning details and hide any suspicious activity.
|
||||
# Case 3:
|
||||
# Overwrite the previously displayed information for the false testimony purpose.
|
||||
|
||||
|
||||
|
||||
# 9. Think of how you would do input validation to prevent such a crime. Replace the code REPLACE ME here so the tests pass:
|
||||
|
||||
def validate(input_str):
|
||||
if '\r' in input_str or '\n' in input_str:
|
||||
raise ValueError("Crime detected!")
|
||||
|
||||
try:
|
||||
validate("abcdefg")
|
||||
print("✅ test1 pass!")
|
||||
except ValueError:
|
||||
print("❌ test1 fail!")
|
||||
|
||||
try:
|
||||
validate("abcdefg\rhijklmnop")
|
||||
print("❌ test2 fail!")
|
||||
except ValueError:
|
||||
print("✅ test2 pass!")
|
||||
|
||||
# Test 1 pass means there is no ValueError
|
||||
# Test 2 pass means the ValueError has been detected
|
||||
@@ -0,0 +1,76 @@
|
||||
########## This file only contains the question 2, 4, and 10. The rest is in the BoundedInt.py. ##########
|
||||
|
||||
|
||||
|
||||
# 2. Modify the template to pass test 1, which checks that int() called on your class will return the value of i.
|
||||
|
||||
# class BoundedInt():
|
||||
# def __init__(self, i, min, max):
|
||||
# """
|
||||
# Create a bounded integer.
|
||||
|
||||
# Args:
|
||||
# i (int): The initial value of the integer.
|
||||
# min (int): The minimum value of the integer.
|
||||
# max (int): The maximum value of the integer.
|
||||
# """
|
||||
# self.i = i
|
||||
# self.min = min
|
||||
# self.max = max
|
||||
|
||||
# def __int__(self):
|
||||
# """
|
||||
# Convert the bounded integer to int.
|
||||
|
||||
# Returns:
|
||||
# int: The value of the bounded integer.
|
||||
# """
|
||||
# return self.i
|
||||
|
||||
|
||||
|
||||
# 4. In that reading material, there's a sentence that starts with "For instance, to evaluate the expression x + y, "...
|
||||
# What do you think the types of x and y are? Guess, without checking first.
|
||||
# What are they, actually? You can use the debugger's local window to find out.
|
||||
|
||||
# x might be an instance of a class that has defined the __add__() method
|
||||
# And y is the object that is compatible with the x instance for the addition operation.
|
||||
|
||||
class MyClass:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, MyClass):
|
||||
return MyClass(self.value + other.value)
|
||||
elif isinstance(other, int):
|
||||
return MyClass(self.value + other)
|
||||
else:
|
||||
raise TypeError("Unsupported operand type.")
|
||||
|
||||
# Example usage
|
||||
obj1 = MyClass(5)
|
||||
obj2 = MyClass(10)
|
||||
result1 = obj1 + obj2 # Calls obj1.__add__(obj2)
|
||||
print(result1.value) # Output: 15
|
||||
|
||||
result2 = obj1 + 3 # Calls obj1.__add__(3)
|
||||
print(result2.value) # Output: 8
|
||||
|
||||
|
||||
|
||||
# 10. Think about how you would change the template so it could allow adding a BoundedInt to an emoji,
|
||||
# if there was a hypothetical function sentiment(emoji) which returned a floating point number from -10.0 to 10.0
|
||||
# which indicated whether the emoji was happy or sad. e.g. BoundedInt(1, min = 1, max = 10) + 😁 would raise ValueError.
|
||||
|
||||
# By adding the conceptional function 'sentiment(emoji)' in the '__add__()' method
|
||||
# The sentiment will analyze the happy level of the input emoji and return a floating number from a number range
|
||||
# For example:
|
||||
# 10 for a 😊 smiley face
|
||||
# -10 for a frowny face
|
||||
# 0 for a 🍕
|
||||
# The protential code can be like this:
|
||||
'''
|
||||
elif isinstance(other, str) and sentiment(other) < 0:
|
||||
aise ValueError("Cannot add a BoundedInt to a sad emoji")
|
||||
'''
|
||||
@@ -0,0 +1,77 @@
|
||||
########## Some commands in pdb ##########
|
||||
# help: Display a list of available pdb commands or get help on a specific command.
|
||||
# break or b: Set a breakpoint at a specific line or function.
|
||||
# continue or c: Continue execution until the next breakpoint or the program finishes.
|
||||
# step or s: Step into the next line of code, diving into function calls.
|
||||
# next or n: Step over the next line of code, without diving into function calls.
|
||||
# return or r: Continue execution until the current function returns.
|
||||
# list or l: Show the current line of code and surrounding lines.
|
||||
# print or p: Evaluate and print the value of an expression or variable.
|
||||
# watch: Set a watchpoint on an expression or variable. The debugger will break when the value changes.
|
||||
# quit or q: Quit the debugger and stop execution.
|
||||
|
||||
|
||||
########## There is a main() function at the end ##########
|
||||
|
||||
|
||||
# 2. Provide an example script where setting a breakpoint on a particular line
|
||||
# Then using either step over or step into will yield the same result.
|
||||
|
||||
class Same_StepOverStepInto_Result:
|
||||
def calculation2(self, a, b):
|
||||
result = a + b
|
||||
product = self.multiply(a, b) # Step into this method call
|
||||
|
||||
breakpoint() # Set a breakpoint here
|
||||
|
||||
print(f"The sum is: {result}")
|
||||
print(f"The product is: {product}")
|
||||
|
||||
def multiply(self, x, y):
|
||||
return x * y
|
||||
|
||||
|
||||
# calculator2 = Same_StepOverStepInto_Result()
|
||||
# calculator2.calculation2(6, 7)
|
||||
|
||||
|
||||
|
||||
# 3. Here is another example which will provide different results from 'step' and 'next' commands
|
||||
|
||||
class Diff_StepOverStepInto_Result:
|
||||
def multiply(self, a, b):
|
||||
return a * b
|
||||
|
||||
def calculation3(self, a, b):
|
||||
result = a + b
|
||||
|
||||
breakpoint() # Set a breakpoint here
|
||||
|
||||
product = self.multiply(a, b)
|
||||
|
||||
print(f"The sum is: {result}")
|
||||
print(f"The product is: {product}")
|
||||
|
||||
|
||||
# calculator3 = Diff_StepOverStepInto_Result()
|
||||
# calculator3.calculation3(6, 7)
|
||||
|
||||
|
||||
|
||||
# Choose wich Class to run
|
||||
def main():
|
||||
choice = input("Enter 2 to run Q2 class for same result, 3 to run Q3 class for different result: ")
|
||||
|
||||
if choice == '2':
|
||||
print('Here is the sample task for Question 2:')
|
||||
calculator2 = Same_StepOverStepInto_Result()
|
||||
calculator2.calculation2(6, 7)
|
||||
elif choice == '3':
|
||||
print('Here is the sample task for Question 3:')
|
||||
calculator3 = Diff_StepOverStepInto_Result()
|
||||
calculator3.calculation3(6, 7)
|
||||
else:
|
||||
print("Please only choose between 2 and 3")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,79 @@
|
||||
class Vector_1:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, Vector_1):
|
||||
# Add the corresponding coordinates of both vectors
|
||||
new_x = self.x + other.x
|
||||
new_y = self.y + other.y
|
||||
return Vector_1(new_x, new_y)
|
||||
else:
|
||||
raise TypeError("Unsupported operand type: +")
|
||||
|
||||
def __str__(self):
|
||||
return f"Vector({self.x}, {self.y})"
|
||||
|
||||
# # Create two Vector instances
|
||||
# vector1 = Vector_1(2, 3)
|
||||
# vector2 = Vector_1(4, 5)
|
||||
|
||||
# # Add two Vector instances using the + operator
|
||||
# result1 = vector1 + vector2
|
||||
|
||||
# # Print the result
|
||||
# print(result1)
|
||||
|
||||
|
||||
|
||||
class Vector_2:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, Vector_2):
|
||||
# Add the corresponding coordinates of both vectors
|
||||
new_x = self.x + other.x
|
||||
new_y = self.y + other.y
|
||||
return Vector_2(new_x, new_y)
|
||||
else:
|
||||
raise TypeError("Unsupported operand type: +")
|
||||
|
||||
# def __str__(self):
|
||||
# return f"Vector({self.x}, {self.y})"
|
||||
|
||||
# # Create two Vector instances
|
||||
# vector3 = Vector_2(2, 3)
|
||||
# vector4 = Vector_2(4, 5)
|
||||
|
||||
# # Add two Vector instances using the + operator
|
||||
# result2 = vector3 + vector4
|
||||
|
||||
# # Print the result
|
||||
# print(result2)
|
||||
|
||||
|
||||
def main():
|
||||
# Create two Vector instances
|
||||
vector1 = Vector_1(2, 3)
|
||||
vector2 = Vector_1(4, 5)
|
||||
# Add two Vector instances using the + operator
|
||||
result1 = vector1 + vector2
|
||||
# Print the result
|
||||
print("This is printout of the Class using __str__() method:")
|
||||
print(result1)
|
||||
|
||||
# Create two Vector instances
|
||||
vector3 = Vector_2(2, 3)
|
||||
vector4 = Vector_2(4, 5)
|
||||
# Add two Vector instances using the + operator
|
||||
result2 = vector3 + vector4
|
||||
# Print the result
|
||||
print("This is printout of the Class without using __str__() method:")
|
||||
print(result2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,85 @@
|
||||
# Create a class that implements a context manager as described in 3.3.9.
|
||||
# The context manager should keep track of an array of banana emojis.
|
||||
# The class should be able to be used with with: so it adds a banana to the list, and upon exit, removes a banana from the list.
|
||||
|
||||
# class BananaManager:
|
||||
# def __init__(self, bananas):
|
||||
# self.bananas = bananas
|
||||
|
||||
# def __enter__(self):
|
||||
# self.bananas.append("🍌")
|
||||
# return self.bananas
|
||||
|
||||
# def __exit__(self, exc_type, exc_value, traceback):
|
||||
# self.bananas.pop()
|
||||
|
||||
# # Usage of the banana manager
|
||||
# banana_list = ["🍌", "🍌"]
|
||||
# print("Before with statement:", banana_list)
|
||||
|
||||
# with BananaManager(banana_list) as adding_bananas:
|
||||
# print("Inside with statement:", adding_bananas)
|
||||
|
||||
# print("After with statement:", banana_list)
|
||||
|
||||
|
||||
|
||||
# Questions: can you use a with block inside of another with block? (You might have to get creative for this to work.).
|
||||
# If you can make that work, how many bananas are in the list?
|
||||
|
||||
# class BananaManager:
|
||||
# def __init__(self, bananas):
|
||||
# self.bananas = bananas
|
||||
|
||||
# def __enter__(self):
|
||||
# self.bananas.append("🍌")
|
||||
# return self.bananas
|
||||
|
||||
# def __exit__(self, exc_type, exc_value, traceback):
|
||||
# self.bananas.pop()
|
||||
|
||||
# # Usage of the banana manager
|
||||
# banana_list = ["🍌", "🍌"]
|
||||
# print("Before with statement:", banana_list)
|
||||
|
||||
# with BananaManager(banana_list) as adding_bananas:
|
||||
# print("Inside first with statement:", adding_bananas)
|
||||
|
||||
# with BananaManager(adding_bananas) as inside_bananas:
|
||||
# print("Inside second with statement:", inside_bananas)
|
||||
|
||||
# print("After with statement:", banana_list)
|
||||
|
||||
|
||||
|
||||
# Another question: can you structure the program so that you can get the class to have more than 0 bananas *outside* of a with block?
|
||||
|
||||
class BananaManager:
|
||||
def __init__(self, bananas):
|
||||
self.bananas = bananas
|
||||
|
||||
def __enter__(self):
|
||||
self.bananas.append("🍌")
|
||||
return self.bananas
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.bananas.pop()
|
||||
|
||||
def outside_banana(self):
|
||||
self.bananas.append("🍌")
|
||||
|
||||
# Usage of the banana manager
|
||||
banana_list = ["🍌", "🍌"]
|
||||
print("Before with statement:", banana_list)
|
||||
|
||||
bananamanager = BananaManager(banana_list)
|
||||
bananamanager.outside_banana() # Add a banana outside of a with block
|
||||
print("Outside adding a banana:", banana_list)
|
||||
|
||||
with BananaManager(banana_list) as adding_bananas:
|
||||
print("Inside first with statement:", adding_bananas)
|
||||
|
||||
with BananaManager(adding_bananas) as inside_bananas:
|
||||
print("Inside second with statement:", inside_bananas)
|
||||
|
||||
print("After with statement:", banana_list)
|
||||
@@ -0,0 +1,56 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2580
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
{\*\expandedcolortbl;;}
|
||||
\margl1440\margr1440\vieww11520\viewh8400\viewkind0
|
||||
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
|
||||
|
||||
\f0\fs24 \cf0 scott@MacBook-Pro-6 Scott_Submissions % python3 HW7.py\
|
||||
Enter 2 to run Q2 class for same result, 3 to run Q3 class for different result: 1\
|
||||
Please only choose between 2 and 3\
|
||||
scott@MacBook-Pro-6 Scott_Submissions % python3 HW7.py\
|
||||
Enter 2 to run Q2 class for same result, 3 to run Q3 class for different result: 2\
|
||||
Here is the sample task for Question 2:\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(27)calculation2()\
|
||||
-> print(f"The sum is: \{result\}")\
|
||||
(Pdb) step\
|
||||
The sum is: 13\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(28)calculation2()\
|
||||
-> print(f"The product is: \{product\}")\
|
||||
(Pdb) c\
|
||||
The product is: 42\
|
||||
scott@MacBook-Pro-6 Scott_Submissions % python3 HW7.py\
|
||||
Enter 2 to run Q2 class for same result, 3 to run Q3 class for different result: 2\
|
||||
Here is the sample task for Question 2:\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(27)calculation2()\
|
||||
-> print(f"The sum is: \{result\}")\
|
||||
(Pdb) next\
|
||||
The sum is: 13\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(28)calculation2()\
|
||||
-> print(f"The product is: \{product\}")\
|
||||
(Pdb) c\
|
||||
The product is: 42\
|
||||
scott@MacBook-Pro-6 Scott_Submissions % python3 HW7.py\
|
||||
Enter 2 to run Q2 class for same result, 3 to run Q3 class for different result: 3\
|
||||
Here is the sample task for Question 3:\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(50)calculation3()\
|
||||
-> product = self.multiply(a, b)\
|
||||
(Pdb) step\
|
||||
--Call--\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(42)multiply()\
|
||||
-> def multiply(self, a, b):\
|
||||
(Pdb) c\
|
||||
The sum is: 13\
|
||||
The product is: 42\
|
||||
scott@MacBook-Pro-6 Scott_Submissions % python3 HW7.py\
|
||||
Enter 2 to run Q2 class for same result, 3 to run Q3 class for different result: 3\
|
||||
Here is the sample task for Question 3:\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(50)calculation3()\
|
||||
-> product = self.multiply(a, b)\
|
||||
(Pdb) next\
|
||||
> /Users/scott/Desktop/GTSP/python-bootcamp/Scott_Submissions/HW7.py(52)calculation3()\
|
||||
-> print(f"The sum is: \{result\}")\
|
||||
(Pdb) c\
|
||||
The sum is: 13\
|
||||
The product is: 42\
|
||||
scott@MacBook-Pro-6 Scott_Submissions % }
|
||||
@@ -0,0 +1,89 @@
|
||||
# import sys
|
||||
# # Python 3
|
||||
# print(sys.maxsize) # Output: 9223372036854775807 (on most platforms)
|
||||
|
||||
|
||||
|
||||
|
||||
# list1 = [1, 2, 3, 4, 6]
|
||||
# list2 = [2, 4, 6, 7, 8]
|
||||
# # Find common values
|
||||
# common_values = []
|
||||
# for item in list1:
|
||||
# if item in list2:
|
||||
# common_values.append(item)
|
||||
|
||||
# # Find different values
|
||||
# different_values = []
|
||||
# for item in list1:
|
||||
# if item not in list2:
|
||||
# different_values.append(item)
|
||||
# for item in list2:
|
||||
# if item not in list1:
|
||||
# different_values.append(item)
|
||||
|
||||
# print("Common values:", common_values) # Common values: [2, 4, 6]
|
||||
# print("Different values:", different_values) # Different values: [1, 3, 7, 8]
|
||||
|
||||
|
||||
# # Find common values
|
||||
# common_values = set(list1) & set(list2)
|
||||
|
||||
# # Find different values
|
||||
# different_values = set(list1) ^ set(list2)
|
||||
|
||||
# print("Common values:", common_values)
|
||||
# print("Different values:", different_values)
|
||||
|
||||
|
||||
|
||||
|
||||
# def outer_function():
|
||||
# outer_variable = 10
|
||||
|
||||
# def inner_function():
|
||||
# inner_variable = 20
|
||||
# print("Inner function: ", inner_variable)
|
||||
# print("Outer function (captured variable): ", outer_variable)
|
||||
|
||||
# return inner_function
|
||||
|
||||
# # Create a closure by calling the outer function
|
||||
# closure = outer_function()
|
||||
|
||||
# # Access the cell object from the closure
|
||||
# cell_object = closure.__closure__[0]
|
||||
|
||||
# # Access and print the value stored in the cell
|
||||
# print("Cell contents: ", cell_object.cell_contents)
|
||||
|
||||
# # Set a new value to the cell
|
||||
# cell_object.cell_contents = 30
|
||||
|
||||
# # Access and print the updated value from the closure
|
||||
# print("Updated cell contents: ", closure.__closure__[0].cell_contents)
|
||||
|
||||
|
||||
|
||||
def greet(name):
|
||||
message = f"Hello, {name}!"
|
||||
print(message)
|
||||
|
||||
# Accessing code object
|
||||
code_obj = greet.__code__
|
||||
print(code_obj.co_name) # Output: greet
|
||||
print(code_obj.co_argcount) # Output: 1 (number of arguments)
|
||||
print(code_obj.co_varnames) # Output: ('name', 'message')
|
||||
|
||||
# Accessing function object
|
||||
print(greet.__name__) # Output: greet
|
||||
print(greet.__defaults__) # Output: None (no default arguments)
|
||||
print(greet.__globals__) # Output: {'__name__': '__main__', ...} (global namespace)
|
||||
|
||||
# Modifying function object attributes
|
||||
greet.__name__ = 'say_hello'
|
||||
greet.__defaults__ = ('John',)
|
||||
greet.__globals__['message'] = 'Welcome!'
|
||||
|
||||
# Call the modified function
|
||||
greet() # Output: Hello, John!
|
||||
@@ -0,0 +1,257 @@
|
||||
scott@MacBook-Pro-6 Desktop % npm install -g @cloudflare/wrangler
|
||||
npm ERR! code EACCES
|
||||
npm ERR! syscall mkdir
|
||||
npm ERR! path /usr/local/lib/node_modules/@cloudflare
|
||||
npm ERR! errno -13
|
||||
npm ERR! Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/@cloudflare'
|
||||
npm ERR! [Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/@cloudflare'] {
|
||||
npm ERR! errno: -13,
|
||||
npm ERR! code: 'EACCES',
|
||||
npm ERR! syscall: 'mkdir',
|
||||
npm ERR! path: '/usr/local/lib/node_modules/@cloudflare'
|
||||
npm ERR! }
|
||||
npm ERR!
|
||||
npm ERR! The operation was rejected by your operating system.
|
||||
npm ERR! It is likely you do not have the permissions to access this file as the current user
|
||||
npm ERR!
|
||||
npm ERR! If you believe this might be a permissions issue, please double-check the
|
||||
npm ERR! permissions of the file and its containing directories, or try running
|
||||
npm ERR! the command again as root/Administrator.
|
||||
|
||||
npm ERR! A complete log of this run can be found in:
|
||||
npm ERR! /Users/scott/.npm/_logs/2023-06-19T09_56_53_005Z-debug-0.log
|
||||
scott@MacBook-Pro-6 Desktop % sudo npm install -g @cloudflare/wrangler
|
||||
Password:
|
||||
npm WARN deprecated @cloudflare/wrangler@1.21.0: This package is for Wrangler v1.x and is no longer supported. Please visit https://www.npmjs.com/package/wrangler for Wrangler v2+.
|
||||
|
||||
added 22 packages in 3s
|
||||
|
||||
3 packages are looking for funding
|
||||
run `npm fund` for details
|
||||
scott@MacBook-Pro-6 Desktop % wrangler config
|
||||
⛔ DEPRECATED ⛔
|
||||
The version of Wrangler you are using is now deprecated.
|
||||
Please update to the latest version of wrangler to prevent critical errors.
|
||||
If originally installed via npm, run `npm uninstall -g @cloudflare/wrangler && npm install -g wrangler` to update to the latest version.
|
||||
If originally installed via cargo, run `cargo uninstall wrangler && npm install -g wrangler`
|
||||
Docs migration guide: https://developers.cloudflare.com/workers/wrangler/migration/migrating-from-wrangler-1/#update-wrangler-version
|
||||
To find your API Token, go to https://dash.cloudflare.com/profile/api-tokens
|
||||
and create it using the "Edit Cloudflare Workers" template.
|
||||
|
||||
Consider using `wrangler login` which only requires your Cloudflare username and password.
|
||||
|
||||
If you are trying to use your Global API Key instead of an API Token
|
||||
(Not Recommended), run `wrangler config --api-key`.
|
||||
Enter API Token:
|
||||
bc70cf5fbbd43ab841faa22bb9b8ae67389a9
|
||||
💁 Validating credentials...
|
||||
Error: Authentication check failed. Please make sure your API token is correct.
|
||||
⚠️ Code 6003: Invalid request headers
|
||||
scott@MacBook-Pro-6 Desktop % curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
|
||||
-H "Authorization: Bearer n27K9bdHXZJCUPq6jGU5F5N8okSFNQDsLvHP4u79" \
|
||||
-H "Content-Type:application/json"
|
||||
{"result":{"id":"1f5dd3d359342f37d9bfd5136697efd4","status":"active"},"success":true,"errors":[],"messages":[{"code":10000,"message":"This API Token is valid and active","type":null}]}% scott@MacBook-Pro-6 Desktop % wrangler config
|
||||
|
||||
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ ⛔ DEPRECATED ⛔ │
|
||||
│ The version of Wrangler you are using is now deprecated. │
|
||||
│ Please update to the latest version of wrangler to prevent critical errors. │
|
||||
│ If originally installed via npm, run `npm uninstall -g @cloudflare/wrangler && npm install -g wrangler` to update to the latest version. │
|
||||
│ If originally installed via cargo, run `cargo uninstall wrangler && npm install -g wrangler` │
|
||||
│ Docs migration guide: https://developers.cloudflare.com/workers/wrangler/migration/migrating-from-wrangler-1/#update-wrangler-version │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ To find your API Token, go to https://dash.cloudflare.com/profile/api-tokens │
|
||||
│ and create it using the "Edit Cloudflare Workers" template. │
|
||||
│ │
|
||||
│ Consider using `wrangler login` which only requires your Cloudflare username and password. │
|
||||
│ │
|
||||
│ If you are trying to use your Global API Key instead of an API Token │
|
||||
│ (Not Recommended), run `wrangler config --api-key`. │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
Enter API Token:
|
||||
n27K9bdHXZJCUPq6jGU5F5N8okSFNQDsLvHP4u79
|
||||
💁 Validating credentials...
|
||||
Error: Permission denied (os error 13)
|
||||
scott@MacBook-Pro-6 Desktop % wrangler config
|
||||
|
||||
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ ⛔ DEPRECATED ⛔ │
|
||||
│ The version of Wrangler you are using is now deprecated. │
|
||||
│ Please update to the latest version of wrangler to prevent critical errors. │
|
||||
│ If originally installed via npm, run `npm uninstall -g @cloudflare/wrangler && npm install -g wrangler` to update to the latest version. │
|
||||
│ If originally installed via cargo, run `cargo uninstall wrangler && npm install -g wrangler` │
|
||||
│ Docs migration guide: https://developers.cloudflare.com/workers/wrangler/migration/migrating-from-wrangler-1/#update-wrangler-version │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ To find your API Token, go to https://dash.cloudflare.com/profile/api-tokens │
|
||||
│ and create it using the "Edit Cloudflare Workers" template. │
|
||||
│ │
|
||||
│ Consider using `wrangler login` which only requires your Cloudflare username and password. │
|
||||
│ │
|
||||
│ If you are trying to use your Global API Key instead of an API Token │
|
||||
│ (Not Recommended), run `wrangler config --api-key`. │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
Enter API Token:
|
||||
Enter API Token:
|
||||
n27K9bdHXZJCUPq6jGU5F5N8okSFNQDsLvHP4u79
|
||||
💁 Validating credentials...
|
||||
Error: Permission denied (os error 13)💁 Validating credentials...
|
||||
Error: Authentication check failed. Please make sure your API token is correct.
|
||||
⚠️ Code 6003: Invalid request headers
|
||||
scott@MacBook-Pro-6 Desktop % n27K9bdHXZJCUPq6jGU5F5N8okSFNQDsLvHP4u79
|
||||
zsh: command not found: n27K9bdHXZJCUPq6jGU5F5N8okSFNQDsLvHP4u79
|
||||
scott@MacBook-Pro-6 Desktop % 💁 Validating credentials...
|
||||
zsh: command not found: 💁
|
||||
scott@MacBook-Pro-6 Desktop % sudo wrangler config
|
||||
Password:
|
||||
|
||||
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ ⛔ DEPRECATED ⛔ │
|
||||
│ The version of Wrangler you are using is now deprecated. │
|
||||
│ Please update to the latest version of wrangler to prevent critical errors. │
|
||||
│ If originally installed via npm, run `npm uninstall -g @cloudflare/wrangler && npm install -g wrangler` to update to the latest version. │
|
||||
│ If originally installed via cargo, run `cargo uninstall wrangler && npm install -g wrangler` │
|
||||
│ Docs migration guide: https://developers.cloudflare.com/workers/wrangler/migration/migrating-from-wrangler-1/#update-wrangler-version │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ To find your API Token, go to https://dash.cloudflare.com/profile/api-tokens │
|
||||
│ and create it using the "Edit Cloudflare Workers" template. │
|
||||
│ │
|
||||
│ Consider using `wrangler login` which only requires your Cloudflare username and password. │
|
||||
│ │
|
||||
│ If you are trying to use your Global API Key instead of an API Token │
|
||||
│ (Not Recommended), run `wrangler config --api-key`. │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
Enter API Token:
|
||||
n27K9bdHXZJCUPq6jGU5F5N8okSFNQDsLvHP4u79
|
||||
💁 Validating credentials...
|
||||
✨ Successfully configured. You can find your configuration file at: /Users/scott/.wrangler/config/default.toml
|
||||
|
||||
╭────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ A new major version of wrangler is available! │
|
||||
│ You can learn more about updating here: │
|
||||
│ https://developers.cloudflare.com/workers/cli-wrangler/install-update#update │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
scott@MacBook-Pro-6 Desktop % Users/scott/.wrangler/config/default.toml
|
||||
zsh: no such file or directory: Users/scott/.wrangler/config/default.toml
|
||||
scott@MacBook-Pro-6 Desktop % wrangler generate my-worker
|
||||
|
||||
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ ⛔ DEPRECATED ⛔ │
|
||||
│ The version of Wrangler you are using is now deprecated. │
|
||||
│ Please update to the latest version of wrangler to prevent critical errors. │
|
||||
│ If originally installed via npm, run `npm uninstall -g @cloudflare/wrangler && npm install -g wrangler` to update to the latest version. │
|
||||
│ If originally installed via cargo, run `cargo uninstall wrangler && npm install -g wrangler` │
|
||||
│ Docs migration guide: https://developers.cloudflare.com/workers/wrangler/migration/migrating-from-wrangler-1/#update-wrangler-version │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
⬇️ Installing cargo-generate v0.5.0...
|
||||
🔧 Creating project called `my-worker`...
|
||||
✨ Done! New project created /Users/scott/Desktop/my-worker
|
||||
|
||||
╭────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ A new major version of wrangler is available! │
|
||||
│ You can learn more about updating here: │
|
||||
│ https://developers.cloudflare.com/workers/cli-wrangler/install-update#update │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
|
||||
scott@MacBook-Pro-6 Desktop % npm uninstall -g @cloudflare/wrangler && npm install -g wrangler
|
||||
npm ERR! code EACCES
|
||||
npm ERR! syscall rename
|
||||
npm ERR! path /usr/local/lib/node_modules/@cloudflare/wrangler
|
||||
npm ERR! dest /usr/local/lib/node_modules/@cloudflare/.wrangler-YTQXDq6U
|
||||
npm ERR! errno -13
|
||||
npm ERR! Error: EACCES: permission denied, rename '/usr/local/lib/node_modules/@cloudflare/wrangler' -> '/usr/local/lib/node_modules/@cloudflare/.wrangler-YTQXDq6U'
|
||||
npm ERR! [Error: EACCES: permission denied, rename '/usr/local/lib/node_modules/@cloudflare/wrangler' -> '/usr/local/lib/node_modules/@cloudflare/.wrangler-YTQXDq6U'] {
|
||||
npm ERR! errno: -13,
|
||||
npm ERR! code: 'EACCES',
|
||||
npm ERR! syscall: 'rename',
|
||||
npm ERR! path: '/usr/local/lib/node_modules/@cloudflare/wrangler',
|
||||
npm ERR! dest: '/usr/local/lib/node_modules/@cloudflare/.wrangler-YTQXDq6U'
|
||||
npm ERR! }
|
||||
npm ERR!
|
||||
npm ERR! The operation was rejected by your operating system.
|
||||
npm ERR! It is likely you do not have the permissions to access this file as the current user
|
||||
npm ERR!
|
||||
npm ERR! If you believe this might be a permissions issue, please double-check the
|
||||
npm ERR! permissions of the file and its containing directories, or try running
|
||||
npm ERR! the command again as root/Administrator.
|
||||
|
||||
npm ERR! A complete log of this run can be found in:
|
||||
npm ERR! /Users/scott/.npm/_logs/2023-06-19T10_14_51_613Z-debug-0.log
|
||||
scott@MacBook-Pro-6 Desktop % sudo npm uninstall -g @cloudflare/wrangler && npm install -g wrangler
|
||||
Password:
|
||||
|
||||
removed 22 packages in 55ms
|
||||
npm ERR! code EACCES
|
||||
npm ERR! syscall mkdir
|
||||
npm ERR! path /Users/scott/.npm/_cacache/content-v2/sha512/ba/97
|
||||
npm ERR! errno EACCES
|
||||
npm ERR!
|
||||
npm ERR! Your cache folder contains root-owned files, due to a bug in
|
||||
npm ERR! previous versions of npm which has since been addressed.
|
||||
npm ERR!
|
||||
npm ERR! To permanently fix this problem, please run:
|
||||
npm ERR! sudo chown -R 501:20 "/Users/scott/.npm"
|
||||
|
||||
npm ERR! A complete log of this run can be found in:
|
||||
npm ERR! /Users/scott/.npm/_logs/2023-06-19T10_14_59_956Z-debug-0.log
|
||||
scott@MacBook-Pro-6 Desktop % sudo chown -R 501:20 "/Users/scott/.npm"
|
||||
scott@MacBook-Pro-6 Desktop % npm install -g wrangler
|
||||
npm ERR! code EACCES
|
||||
npm ERR! syscall mkdir
|
||||
npm ERR! path /usr/local/lib/node_modules/wrangler
|
||||
npm ERR! errno -13
|
||||
npm ERR! Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/wrangler'
|
||||
npm ERR! [Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/wrangler'] {
|
||||
npm ERR! errno: -13,
|
||||
npm ERR! code: 'EACCES',
|
||||
npm ERR! syscall: 'mkdir',
|
||||
npm ERR! path: '/usr/local/lib/node_modules/wrangler'
|
||||
npm ERR! }
|
||||
npm ERR!
|
||||
npm ERR! The operation was rejected by your operating system.
|
||||
npm ERR! It is likely you do not have the permissions to access this file as the current user
|
||||
npm ERR!
|
||||
npm ERR! If you believe this might be a permissions issue, please double-check the
|
||||
npm ERR! permissions of the file and its containing directories, or try running
|
||||
npm ERR! the command again as root/Administrator.
|
||||
|
||||
npm ERR! A complete log of this run can be found in:
|
||||
npm ERR! /Users/scott/.npm/_logs/2023-06-19T10_16_04_916Z-debug-0.log
|
||||
scott@MacBook-Pro-6 Desktop % sudo npm install -g wrangler --unsafe-perm
|
||||
npm WARN deprecated rollup-plugin-inject@3.0.2: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject.
|
||||
npm WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
|
||||
|
||||
added 107 packages in 25s
|
||||
|
||||
15 packages are looking for funding
|
||||
run `npm fund` for details
|
||||
scott@MacBook-Pro-6 Desktop % wrangler --version
|
||||
⛅️ wrangler 3.1.0
|
||||
------------------
|
||||
@@ -0,0 +1,28 @@
|
||||
import pdb
|
||||
|
||||
def calculate_average(numbers):
|
||||
total = sum(numbers)
|
||||
average = total / len(numbers)
|
||||
return average
|
||||
|
||||
def main():
|
||||
data = [1, 2, 3, 4, 5]
|
||||
|
||||
pdb.set_trace()
|
||||
result = calculate_average(data)
|
||||
print("The average is:", result)
|
||||
|
||||
pdb.set_trace() # Set a breakpoint at this line
|
||||
|
||||
print("Program execution resumed.")
|
||||
# ... continue with the rest of your code
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
# n or next: Execute the next line of code.
|
||||
# s or step: Step into a function call.
|
||||
# c or continue: Continue execution until the next breakpoint or the program's end.
|
||||
# p or print: Print the value of a variable.
|
||||
# q or quit: Quit the debugger and exit the program.
|
||||
@@ -0,0 +1,76 @@
|
||||
from enum import Enum
|
||||
|
||||
class Tokens(Enum):
|
||||
QUOTE = 1,
|
||||
CHAR = 2,
|
||||
NEWLINE = 3,
|
||||
SPACE = 4
|
||||
|
||||
class Lexer:
|
||||
tokens = list()
|
||||
def __init__(self):
|
||||
pass
|
||||
def lex(self, str):
|
||||
for c in str:
|
||||
if c == "'" or c == '"':
|
||||
self.tokens.append(Tokens.QUOTE)
|
||||
print("Token: QUOTE")
|
||||
elif c == "\n":
|
||||
self.tokens.append(Tokens.NEWLINE)
|
||||
print("Token: NEWLINE")
|
||||
elif c == " ":
|
||||
self.tokens.append(Tokens.SPACE)
|
||||
print("Token: SPACE")
|
||||
else:
|
||||
self.tokens.append(Tokens.CHAR)
|
||||
print("Token: CHAR")
|
||||
def __str__(self):
|
||||
return ",".join(Tokens(token).name for token in self.tokens)
|
||||
|
||||
class States(Enum):
|
||||
INITIAL = 0,
|
||||
BEGINQUOTE = 1
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.state = States.INITIAL
|
||||
self.line = 1
|
||||
|
||||
def transition(self, state):
|
||||
print(f"{States(self.state).name} -> {States(state).name}")
|
||||
self.state = state
|
||||
|
||||
def parse(self, tokens):
|
||||
for token in tokens:
|
||||
if self.state == States.INITIAL:
|
||||
if token == Tokens.QUOTE:
|
||||
self.transition(States.BEGINQUOTE)
|
||||
elif token == Tokens.NEWLINE:
|
||||
self.line += 1
|
||||
continue
|
||||
if self.state == States.BEGINQUOTE:
|
||||
if token == Tokens.QUOTE:
|
||||
self.transition(States.INITIAL)
|
||||
elif token == Tokens.CHAR or token == Tokens.SPACE:
|
||||
pass
|
||||
elif token == Tokens.NEWLINE:
|
||||
raise ValueError(f"Unterminated string on line {self.line}")
|
||||
continue
|
||||
|
||||
if __name__ == "__main__":
|
||||
test1 = """abcdefg
|
||||
"abcde
|
||||
'a'
|
||||
bareword
|
||||
"""
|
||||
|
||||
lexer = Lexer()
|
||||
lexer.lex(test1)
|
||||
# print(lexer)
|
||||
parser = Parser()
|
||||
try:
|
||||
parser.parse(lexer.tokens)
|
||||
except ValueError as error:
|
||||
print(error)
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# question 8: If the column or data type is invalid, and we take them into calculations without noticing this, wrong number will be produced.
|
||||
# question 9:
|
||||
def read_tomato_sales(file_name):
|
||||
data = pd.read_csv(file_name)
|
||||
if "Tomato_Sales" in data.columns and data["Tomato_Sales"].dtype == "int64":
|
||||
total_sales = data["Tomato_Sales"].sum()
|
||||
print(f"Total tomato sales: {total_sales}")
|
||||
else:
|
||||
raise ValueError("Invalid column or data type.")
|
||||
# question 10: Reasons:
|
||||
# 1. Different languages may have different character encodings, which define how characters are represented
|
||||
# as binary data. By using bytes, you can handle various character encodings, such as UTF-8, UTF-16, or others.
|
||||
# 2. Bytes are language-agnostic and treat text as raw binary data.
|
||||
# 3. Bytes can handle any kind of binary data, including text data in different languages, as well as
|
||||
# non-textual data such as images, audio, or video.
|
||||
def process_multilingual_data(data):
|
||||
# Convert string to bytes using UTF-8 encoding
|
||||
byte_data = data.encode('utf-8')
|
||||
|
||||
# Convert bytes back to string for display or further processing
|
||||
processed_data = byte_data.decode('utf-8')
|
||||
|
||||
return processed_data
|
||||
|
||||
# Example usage
|
||||
text = "This is shunan zhao"
|
||||
processed_text = process_multilingual_data(text)
|
||||
print(processed_text)
|
||||
# 1: ord("😀") gives you the Unicode code point of the character, while 0xf09f9880 represents the byte
|
||||
# sequence in UTF-8 encoding used to represent that character.
|
||||
# 2.5: A REPL is an interactive programming environment that allows you to enter commands or expressions,
|
||||
# which are then evaluated and the results are printed or displayed.
|
||||
# 3: the "_" variable is a special variable that holds the result of the last executed expression or
|
||||
# statement. It is often referred to as the "underscore variable."
|
||||
#The type can vary based on the context and the value assigned to in the current REPL session. For example:
|
||||
# If the last executed expression was an integer, the type of "_" would be int.
|
||||
# If the last executed expression was a string, the type of "_" would be str.
|
||||
# If the last executed expression was a list, the type of "_" would be list.
|
||||
@@ -0,0 +1,170 @@
|
||||
overloading in python:
|
||||
Function overloading refers to the ability to define multiple functions with the same name but different parameter lists.
|
||||
However, in Python, you can achieve similar functionality by using default arguments and optional parameters. Here's an example:
|
||||
def my_function(param1, param2=None):
|
||||
if param2 is None:
|
||||
# Perform action when only one parameter is provided
|
||||
print("Parameter 1:", param1)
|
||||
else:
|
||||
# Perform action when both parameters are provided
|
||||
print("Parameter 1:", param1)
|
||||
print("Parameter 2:", param2)
|
||||
In this example, the my_function function takes two parameters. The second parameter param2 is set to None by default, making it optional. Inside the function, you can check if param2 is None to determine whether it was provided or not.
|
||||
|
||||
superclass’s __new__() method:
|
||||
The __new__() method in Python is a special method defined in a class that is responsible for creating and returning a new instance of that class. It is a static method that gets called before the __init__() method and is primarily used in the creation of immutable objects or when you need more control over the object creation process.
|
||||
When dealing with inheritance, the __new__() method of the superclass is automatically called when creating an instance of a subclass. This happens before the subclass's __init__() method is invoked. The __new__() method of the superclass can be overridden in the subclass to customize the object creation process.
|
||||
|
||||
metaclasses:
|
||||
Metaclasses in Python provide a way to define the behavior and structure of classes themselves. A metaclass is the class of a class, i.e., a class that defines how a class should be created, just as a class defines how an instance should be created. Metaclasses allow you to customize class creation and modify class attributes, methods, and behavior.
|
||||
|
||||
class constructor expression:
|
||||
In Python, the class constructor is defined using the __init__() method. It is called automatically when an object is created from a class and is responsible for initializing the object's attributes.
|
||||
class MyClass:
|
||||
def __init__(self, param1, param2):
|
||||
self.param1 = param1
|
||||
self.param2 = param2
|
||||
|
||||
# Creating an instance of MyClass
|
||||
obj = MyClass("Hello", 42)
|
||||
|
||||
gc module:
|
||||
The gc module in Python provides an interface to the garbage collector and related functions for managing memory and collecting unused objects. It is part of Python's memory management system and allows you to control and monitor the garbage collection process.
|
||||
|
||||
“rich comparison” methods:
|
||||
"Rich comparison" methods, also known as "comparison operators" or "comparison magic methods," are special methods in Python that allow objects to define their own behavior for comparison operations such as equality, inequality, less than, greater than, etc. These methods enable you to customize how objects are compared and ordered.
|
||||
By implementing rich comparison methods in your classes, you can define custom rules for comparison operations and make objects behave in a way that suits your needs.
|
||||
class Rectangle:
|
||||
def __init__(self, width, height):
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Rectangle):
|
||||
return self.width == other.width and self.height == other.height
|
||||
return False
|
||||
|
||||
def __lt__(self, other):
|
||||
if isinstance(other, Rectangle):
|
||||
return self.width * self.height < other.width * other.height
|
||||
return NotImplemented
|
||||
|
||||
rect1 = Rectangle(3, 4)
|
||||
rect2 = Rectangle(4, 5)
|
||||
rect3 = Rectangle(3, 4)
|
||||
|
||||
print(rect1 == rect2) # Output: False
|
||||
print(rect1 == rect3) # Output: True
|
||||
print(rect1 < rect2) # Output: True
|
||||
|
||||
swapped-argument versions:
|
||||
The "swapped-argument versions" of the rich comparison methods refer to the reversed version of the original comparison methods. These methods allow you to define the behavior when the operands of the comparison are swapped.
|
||||
|
||||
hashed collections:
|
||||
Hashed collections in Python are data structures that use hashing algorithms to provide efficient lookup and retrieval of elements. They are designed to offer fast access to elements based on their unique hash values.
|
||||
|
||||
There are several hashed collection types available in Python's standard library:
|
||||
|
||||
dict (dictionary): A dictionary is an unordered collection of key-value pairs. It uses a hash table implementation, where the keys are hashed to provide fast lookup and retrieval of values. Dictionaries are commonly used when you need to map unique keys to corresponding values.
|
||||
|
||||
set: A set is an unordered collection of unique elements. It uses hash-based lookup to quickly determine membership of an element. Sets are useful when you want to store a collection of items without any duplicates and perform set operations such as union, intersection, and difference efficiently.
|
||||
|
||||
frozenset: Similar to a set, a frozenset is an immutable version of a set. Once created, its elements cannot be modified. Frozensets are often used as keys in dictionaries or elements in other sets because they are hashable.
|
||||
|
||||
salted in python:
|
||||
In Python, salting is commonly used in password hashing and encryption algorithms. Here's an example of how salting can be implemented using the bcrypt library, which is a popular choice for secure password hashing:
|
||||
import bcrypt
|
||||
|
||||
password = "my_password"
|
||||
salt = bcrypt.gensalt()
|
||||
|
||||
# Hash the password with the generated salt
|
||||
hashed_password = bcrypt.hashpw(password.encode(), salt)
|
||||
|
||||
# Verify the password
|
||||
if bcrypt.checkpw(password.encode(), hashed_password):
|
||||
print("Password is correct.")
|
||||
else:
|
||||
print("Password is incorrect.")
|
||||
|
||||
password hashing and encryption algorithms:
|
||||
Password hashing and encryption algorithms are used to protect sensitive information like passwords by transforming them into a non-readable format. Here are some commonly used algorithms in Python:
|
||||
|
||||
bcrypt: bcrypt is a popular password hashing algorithm that incorporates a salt value and multiple iterations of hashing to increase the security of passwords. It is designed to be slow and computationally expensive, making it resistant to brute-force attacks. The bcrypt library in Python provides an easy-to-use interface for working with bcrypt.
|
||||
|
||||
Argon2: Argon2 is a state-of-the-art password hashing algorithm that won the Password Hashing Competition in 2015. It is designed to be memory-hard and resistant to various types of attacks, including GPU and ASIC attacks. The argon2 library in Python provides support for Argon2.
|
||||
|
||||
PBKDF2: PBKDF2 (Password-Based Key Derivation Function 2) is a key derivation function that applies a cryptographic hash function (such as SHA-1 or SHA-256) iteratively with a salt value to produce a derived key. It is widely used for password hashing. The hashlib library in Python provides support for various hash functions that can be used with PBKDF2.
|
||||
|
||||
scrypt: scrypt is a password-based key derivation function that is designed to be memory-hard and resistant to various types of attacks, including hardware-based attacks. It is commonly used for password storage. The scrypt library in Python provides support for scrypt.
|
||||
|
||||
AES: AES (Advanced Encryption Standard) is a symmetric encryption algorithm that is widely used for encrypting data. It is a block cipher with various key sizes (128-bit, 192-bit, or 256-bit) and encryption modes (such as ECB, CBC, or GCM). The cryptography library in Python provides support for AES encryption.
|
||||
|
||||
O(n2) complexity:
|
||||
O(n^2) complexity, also known as quadratic complexity, refers to an algorithm whose execution time grows quadratically with the input size. It means that the time required to solve a problem double as the input size increases by a constant factor.
|
||||
|
||||
dict insertion:
|
||||
Dictionary insertion in Python has an average time complexity of O(1) and a worst-case time complexity of O(n) in scenarios where collisions occur frequently.
|
||||
|
||||
intentional asymmetry:
|
||||
Intentional asymmetry, in the context of cryptography, refers to the deliberate introduction of imbalance or non-uniformity in cryptographic algorithms or protocols. It is done to enhance security by making it difficult for attackers to exploit patterns or symmetries that could potentially weaken the system.
|
||||
|
||||
cryptography:
|
||||
Cryptography is the practice of securing communication and data by transforming it into a form that is unintelligible to unauthorized individuals. It involves the use of cryptographic algorithms and protocols to ensure confidentiality, integrity, authentication, and non-repudiation of information.
|
||||
|
||||
runtime introspection of dynamic class attributes:
|
||||
In Python, you can perform runtime introspection of dynamic class attributes using various built-in functions and attributes. Here are a few techniques:
|
||||
|
||||
dir() function: The dir() function returns a list of names in the current local or global scope. When called on a class or an instance, it returns a list of all attributes, including both static and dynamic attributes.
|
||||
|
||||
vars() function: The vars() function returns the __dict__ attribute of an object, which contains the object's attributes and their values as a dictionary. When called on a class, it returns the class's namespace dictionary.
|
||||
|
||||
getattr() function: The getattr() function allows you to dynamically access an attribute of an object by name. It takes two arguments: the object and the attribute name as a string. If the attribute exists, it is returned; otherwise, an optional default value can be provided.
|
||||
|
||||
Multiple inheritance:
|
||||
Multiple inheritance is a feature in object-oriented programming languages that allows a class to inherit attributes and behaviors from multiple parent classes. In Python, you can create a class that inherits from multiple parent classes by listing them in the class definition separated by commas.
|
||||
|
||||
MRO:
|
||||
MRO stands for Method Resolution Order and refers to the order in which methods are resolved or looked up in a class hierarchy that involves multiple inheritance. When a class inherits from multiple parent classes, the MRO determines the sequence in which the methods are searched for and executed.
|
||||
|
||||
lexical scoping:
|
||||
Lexical scoping, also known as static scoping, is a scoping mechanism used in programming languages to determine the scope of variables and identifiers based on their location in the source code. In lexical scoping, the scope of a variable is determined by its position or context in the program's text or source code, rather than by runtime conditions.
|
||||
|
||||
divmod():
|
||||
result = divmod(17, 5)
|
||||
print(result) # Output: (3, 2)
|
||||
pow():
|
||||
result = pow(2, 3)
|
||||
print(result) # Output: 8
|
||||
^:
|
||||
result = 5 ^ 3
|
||||
print(result) # Output: 6
|
||||
In this example, 5 ^ 3 performs a bitwise XOR operation on the numbers 5 and 3. The binary representation of 5 is 101, and the binary representation of 3 is 011. Performing the XOR operation on corresponding bits gives 110, which is equal to 6 in decimal.
|
||||
&:
|
||||
result = 12 & 7
|
||||
print(result) # Output: 4
|
||||
In this example, 12 & 7 performs a bitwise AND operation on the numbers 12 and 7. The binary representation of 12 is 1100, and the binary representation of 7 is 0111. Performing the AND operation on corresponding bits gives 0100, which is equal to 4 in decimal.
|
||||
@:
|
||||
In Python, the @ symbol is used as the matrix multiplication operator. It is also known as the "at" operator or "matmul" operator. The @ operator performs matrix multiplication between two arrays or matrices.
|
||||
%:
|
||||
result = 10 % 3
|
||||
print(result) # Output: 1
|
||||
<<:
|
||||
result = 10 << 2
|
||||
print(result) # Output: 40
|
||||
In this example, 10 << 2 shifts the bits of the number 10 two positions to the left. The binary representation of 10 is 1010, and shifting it two positions to the left gives 101000, which is equal to 40 in decimal.
|
||||
|:
|
||||
result = 5 | 3
|
||||
print(result) # Output: 7
|
||||
In this example, 5 | 3 performs a bitwise OR operation on the numbers 5 and 3. The binary representation of 5 is 101, and the binary representation of 3 is 011. Performing the OR operation on corresponding bits gives 111, which is equal to 7 in decimal.
|
||||
questions:
|
||||
1.What is the purpose of using a constructor in a class?
|
||||
2.How do you define a class method in Python?
|
||||
3.What is the difference between an instance variable and a class variable?
|
||||
4.How can you access an instance variable within a class method?
|
||||
5.Can a class method modify the value of a class variable? Why or why not?
|
||||
6.Explain the concept of method overloading with an example.
|
||||
7.What is the difference between a shallow copy and a deep copy of an object?
|
||||
8.How do you define a static method in Python? What is its significance?
|
||||
9."What is the difference between mutable sequences and immutable sequences in programming, and when would you choose to use one over the other?"
|
||||
10.Consider a scenario where you have a parent class called Animal and two child classes called Cat and Dog. If you have a variable named animal which is of type Animal, how would you determine if it is an instance of the Cat class using logical deduction instead of direct comparison?
|
||||
@@ -0,0 +1,165 @@
|
||||
class BananaContextManager:
|
||||
def __init__(self, banana_list):
|
||||
self.banana_list = banana_list
|
||||
|
||||
def __enter__(self):
|
||||
self.banana_list.append("🍌") # Add a banana to the list
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.banana_list: # Check if the list is not empty
|
||||
self.banana_list.pop() # Remove a banana from the list
|
||||
my_banana_list = []
|
||||
with BananaContextManager(my_banana_list):
|
||||
print(my_banana_list)
|
||||
print(my_banana_list) # Output: []
|
||||
|
||||
#Questions: can you use a with block inside of another with block?
|
||||
class BananaContextManager:
|
||||
def __init__(self, banana_list):
|
||||
self.banana_list = banana_list
|
||||
|
||||
def __enter__(self):
|
||||
self.banana_list.append("🍌") # Add a banana to the list
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.banana_list: # Check if the list is not empty
|
||||
self.banana_list.pop() # Remove a banana from the list
|
||||
my_banana_list = []
|
||||
with BananaContextManager(my_banana_list) as outer_cm:
|
||||
print(my_banana_list)
|
||||
|
||||
with BananaContextManager(outer_cm.banana_list) as inner_cm:
|
||||
inner_cm.banana_list.append("🍌") # Add another banana to the list
|
||||
print(my_banana_list)
|
||||
|
||||
inner_cm.banana_list.pop() # Remove a banana from the list
|
||||
print(my_banana_list)
|
||||
|
||||
print(my_banana_list)
|
||||
|
||||
print(my_banana_list)
|
||||
#The number of bananas in the list are 1,3,2,1,0.
|
||||
|
||||
#question:can you structure the program so that you can get the class to have more than 0 bananas *outside* of a with block?
|
||||
class BananaContextManager:
|
||||
def __init__(self, banana_list, initial_bananas=0):
|
||||
self.banana_list = banana_list
|
||||
self.initial_bananas = initial_bananas
|
||||
|
||||
def __enter__(self):
|
||||
for _ in range(self.initial_bananas):
|
||||
self.banana_list.append("🍌")
|
||||
self.banana_list.append("🍌") # Add a banana to the list
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.banana_list: # Check if the list is not empty
|
||||
self.banana_list.pop() # Remove a banana from the list
|
||||
|
||||
# Usage example
|
||||
my_banana_list = []
|
||||
banana_count = 1 # Number of bananas outside the with block
|
||||
|
||||
with BananaContextManager(my_banana_list, banana_count) as outer_cm:
|
||||
print(my_banana_list)
|
||||
|
||||
with BananaContextManager(outer_cm.banana_list) as inner_cm:
|
||||
inner_cm.banana_list.append("🍌") # Add another banana to the list
|
||||
print(my_banana_list)
|
||||
|
||||
inner_cm.banana_list.pop() # Remove a banana from the list
|
||||
print(my_banana_list)
|
||||
|
||||
print(my_banana_list)
|
||||
|
||||
print(my_banana_list)
|
||||
|
||||
#Update notes:
|
||||
#salting:
|
||||
#Let's say we have two users, Alice and Bob, who both have the same password, "password123". Without salting,
|
||||
#if we were to hash their passwords directly, they would produce the same hash value:
|
||||
'''''
|
||||
Alice's Password: password123
|
||||
Bob's Password: password123
|
||||
|
||||
Hashed Password (Alice and Bob): 7c6a180b36896a0a8c02787eeafb0e4c7b07a52e
|
||||
'''''
|
||||
#As you can see, the hashed passwords for both Alice and Bob are the same. This could be a problem because if an attacker obtains the hash value,
|
||||
#they can easily determine that Alice and Bob have the same password.
|
||||
#Now, let's introduce salting to the process. Each user will have a unique salt that is added to their password before hashing.
|
||||
# Here's an updated example:
|
||||
'''''
|
||||
Alice's Password: password123
|
||||
Bob's Password: password123
|
||||
|
||||
Alice's Salt: QGdG9jzV
|
||||
Bob's Salt: d8K27fsE
|
||||
|
||||
Salted and Hashed Password (Alice): QGdG9jzVpassword123 -> 48cf6b7b4b04819f6d717c9bc67a4feae0f1081a
|
||||
Salted and Hashed Password (Bob): d8K27fsEpassword123 -> d5fd5b3a42f8e6bc8c9844feeff24f4cb4fd8fa4
|
||||
|
||||
'''''
|
||||
#Now, even though Alice and Bob have the same password, their hashed passwords are different
|
||||
#because they used different salts. The salt makes each hash unique, even when the passwords are the same.
|
||||
|
||||
#Rich comparison methods:
|
||||
#Rich comparison methods allow objects to be compared using operators like <, >, ==, etc. By implementing these
|
||||
#methods in a class, you can define how objects of that class should be compared. Here's an example
|
||||
#using the __eq__ method to compare two Point objects:
|
||||
class Point:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y
|
||||
|
||||
point1 = Point(1, 2)
|
||||
point2 = Point(1, 2)
|
||||
point3 = Point(3, 4)
|
||||
|
||||
print(point1 == point2) # Output: True
|
||||
print(point1 == point3) # Output: False
|
||||
|
||||
#Swapped-argument versions:
|
||||
#Swapped-argument versions of methods provide flexibility when working with commutative operations.
|
||||
#For example, if you have a class representing a mathematical operation and want to support swapping the operands,
|
||||
#you can define a swapped-argument version of the method.
|
||||
|
||||
#Hashed collections:
|
||||
#Hashed collections like dictionaries (dict) and sets (set) use hash functions internally to efficiently store
|
||||
#and retrieve data. Here's an example using a dictionary:
|
||||
my_dict = {'apple': 5, 'banana': 3, 'orange': 2}
|
||||
|
||||
print(my_dict['apple']) # Output: 5
|
||||
print(my_dict.get('banana')) # Output: 3
|
||||
|
||||
#Dictionary insertion:
|
||||
#Dictionary insertion refers to adding key-value pairs to a dictionary. Here's an example:
|
||||
my_dict = {'apple': 5, 'banana': 3}
|
||||
|
||||
# Inserting a new key-value pair
|
||||
my_dict['orange'] = 2
|
||||
|
||||
print(my_dict) # Output: {'apple': 5, 'banana': 3, 'orange': 2}
|
||||
|
||||
#Multiple inheritance:
|
||||
#Multiple inheritance allows a class to inherit from multiple base classes. Here's a simplified example:
|
||||
class Base1:
|
||||
def method1(self):
|
||||
print("Base1 method")
|
||||
|
||||
class Base2:
|
||||
def method2(self):
|
||||
print("Base2 method")
|
||||
|
||||
class MyClass(Base1, Base2):
|
||||
pass
|
||||
|
||||
my_object = MyClass()
|
||||
my_object.method1() # Output: Base1 method
|
||||
my_object.method2() # Output: Base2 method
|
||||
|
||||
#AI cannot give me practcial examples about Intentional asymmetry and Cryptography.
|
||||
@@ -0,0 +1,53 @@
|
||||
#question 1:
|
||||
# i = 3 Literal Type: Integer, and its value is 3.
|
||||
|
||||
# f = 3.0 Literal Type: Float, and its value is 3.0.
|
||||
|
||||
# c = 3+3j Literal Type: Complex, and its value is 3+3j.
|
||||
|
||||
# b = b'abcdefg' Literal Type: Bytes, and its value is b'abcdefg'.
|
||||
|
||||
# s = 'abcdefg' Literal Type: String, and its value is 'abcdefg'.
|
||||
|
||||
# s = "abcdefg" Literal Type: String, and its value is "abcdefg".
|
||||
|
||||
#question 2:
|
||||
'''
|
||||
'0' b'0' 0 0.0 0j
|
||||
'0' Equal |Not equal |Not equal |Not equal |Not equal
|
||||
b'0'Not equal |Equal |Not equal |Not equal |Not equal
|
||||
0 Not equal |Not equal |Equal |Equal |Equal
|
||||
0.0 Not equal |Not equal |Equal |Equal |Not Equal
|
||||
0j Not equal |Not equal |Equal |Not equal |Equal
|
||||
'''
|
||||
#question 3:
|
||||
##The "+" operator case:
|
||||
'''
|
||||
'0' b'0' 0 0.0 0j
|
||||
'0' '00' |TypeError |TypeError |TypeError |TypeError
|
||||
b'0' TypeError |b'00' |TypeError |TypeError |TypeError
|
||||
0 TypeError |TypeError |0 |0.0 |0j
|
||||
0.0 TypeError |TypeError |0.0 |0.0 |TypeError
|
||||
0j TypeError |TypeError |0j |TypeError |0j
|
||||
'''
|
||||
##The "==" operator case:
|
||||
'''
|
||||
'0' b'0' 0 0.0 0j
|
||||
'0' True |False |False |False |False
|
||||
b'0 False |False |False |False |False
|
||||
0 False |False |False |True |True
|
||||
0.0 False |False |True |True |False
|
||||
0j False |False |True |False |True
|
||||
'''
|
||||
#question4:
|
||||
import ast
|
||||
|
||||
# Open the lexer/parser example file
|
||||
with open('lexer_parser_example.py', 'r') as file:
|
||||
source_code = file.read()
|
||||
|
||||
# Parse the source code into an AST
|
||||
tree = ast.parse(source_code)
|
||||
|
||||
# Dump the AST
|
||||
print(ast.dump(tree, indent=4))
|
||||
@@ -0,0 +1,34 @@
|
||||
# question 5:
|
||||
# The statement print("\007") outputs an ASCII escape sequence \007, which represents the Bell control character. The reason why print("\007")
|
||||
# produces a sound or visual alert is that when the string "\007" is printed, it is interpreted by the terminal or system as a signal to generate
|
||||
# an audible or visual alert, as defined by the specific implementation.
|
||||
|
||||
# question 6:
|
||||
# The code print("abcdefg\rhijklmnop") will output "hijklmnopg"
|
||||
# In Python, the '\r' character is a carriage return character, which instructs the console or terminal to move the cursor back to the beginning
|
||||
# of the current line, without advancing to the next line. This means that anything printed after the '\r' will overwrite whatever was printed earlier
|
||||
# on the same line.
|
||||
|
||||
# question 7:
|
||||
# In this case, the carriage return character \r is treated as a regular character within the response content. It does not have the same effect as
|
||||
# in the previous example where it was used in a print statement.
|
||||
|
||||
# qustion 8:
|
||||
# If a hacker attacks a credit card system. When the customer came to buy a can of Coke, he paid 2 knives to the store, but the display in the
|
||||
# background was "2/r500".
|
||||
|
||||
# question 9:
|
||||
def validate(input_string):
|
||||
if "\r" in input_string:
|
||||
raise ValueError("Crime detected!")
|
||||
try:
|
||||
validate("abcdefg")
|
||||
print("✅ test1 pass!")
|
||||
except:
|
||||
print("❌ test1 fail!")
|
||||
|
||||
try:
|
||||
validate("abcdefg\rhijklmnop")
|
||||
print("❌ test2 fail!")
|
||||
except ValueError as err:
|
||||
print("✅ test2 pass!")
|
||||
@@ -0,0 +1,77 @@
|
||||
class BoundedInt():
|
||||
def __init__(self, i, min_val, max_val):
|
||||
self.i = i
|
||||
self.min = min_val
|
||||
self.max = max_val
|
||||
|
||||
def __int__(self):
|
||||
return self.i
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, BoundedInt):
|
||||
result = self.i - other.i
|
||||
else:
|
||||
result = self.i - other
|
||||
if result < self.min:
|
||||
raise ValueError("Result exceeds min value")
|
||||
return BoundedInt(result, self.min, self.max)
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, BoundedInt):
|
||||
result = self.i + other.i
|
||||
else:
|
||||
result = self.i + other
|
||||
if result > self.max:
|
||||
raise ValueError("Result exceeds max value")
|
||||
return BoundedInt(result, self.min, self.max)
|
||||
|
||||
def test1(self):
|
||||
bi1 = BoundedInt(0xdeadbeef, min_val=(0xdeadbeef - 1), max_val=(0xdeadbeef + 1))
|
||||
if int(bi1) == 0xdeadbeef:
|
||||
print(f"✅ Test 1 passed!")
|
||||
else:
|
||||
print(f"❌ Test 1 failed, int(bi1) = {int(bi1)}, expected 0xdeadbeef")
|
||||
|
||||
def test2(self):
|
||||
bi2 = BoundedInt(1, min_val=0, max_val=1)
|
||||
bi3 = BoundedInt(1, min_val=0, max_val=1)
|
||||
try:
|
||||
bi4 = bi2 + bi3 # 1 + 1 = 2, which exceeds max_val = 1
|
||||
print(f"❌ Test 2 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 2 passed!")
|
||||
|
||||
def test3(self):
|
||||
bi4 = BoundedInt(1, min_val=0, max_val=1)
|
||||
bi5 = BoundedInt(2, min_val=0, max_val=-1)
|
||||
try:
|
||||
bi6 = bi4 - bi5 # 1 - 2 = -1, which is less than min_val = 0
|
||||
print(f"❌ Test 3 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 3 passed!")
|
||||
|
||||
def test4(self):
|
||||
bi7 = BoundedInt(1, min_val=0, max_val=1)
|
||||
bi8 = 2
|
||||
try:
|
||||
bi9 = bi7 + bi8
|
||||
print(f"❌ Test 4 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 4 passed!")
|
||||
|
||||
def test5(self):
|
||||
bi10 = BoundedInt(1, min_val=0, max_val=1)
|
||||
bi11 = 2
|
||||
try:
|
||||
bi12 = bi10 - 11
|
||||
print(f"❌ Test 5 failed!")
|
||||
except ValueError as err:
|
||||
print(f"✅ Test 5 passed!")
|
||||
|
||||
|
||||
tester = BoundedInt(0, 0, 0)
|
||||
tester.test1()
|
||||
tester.test2()
|
||||
tester.test3()
|
||||
tester.test4()
|
||||
tester.test5()
|
||||
@@ -0,0 +1,118 @@
|
||||
# question 1:
|
||||
#boolean context:
|
||||
#In programming, a boolean context refers to a situation where a condition or expression is evaluated as either true or false.
|
||||
#A boolean context typically occurs in control flow statements, such as if statements or while loops, where the condition determines whether
|
||||
#a certain block of code should be executed or repeated.
|
||||
|
||||
#Ellipsis:
|
||||
#an ellipsis (...) is a special token that represents an ellipsis object. It is often used as a placeholder in code or data structures where
|
||||
#you intend to fill in additional functionality or content later.
|
||||
|
||||
#machine-level double precision floating point numbers
|
||||
#Machine-level double precision floating-point numbers, often referred to as double, are a common representation of real numbers in computer systems.
|
||||
#They are a binary format used to store and manipulate floating-point values with higher precision compared to single precision.
|
||||
|
||||
#Callable types:
|
||||
#callable types refer to objects that can be called as functions. These objects are capable of executing code when invoked with parentheses, just
|
||||
#like a regular function.
|
||||
|
||||
#cell_contents:
|
||||
#the term "cell contents" refers to the value stored in a cell of a closure. A closure is a function object that retains references to variables
|
||||
#in its enclosing lexical scope, even when the outer function has finished executing.
|
||||
#When a closure is created, each variable it references is stored in a cell, which is an internal data structure associated with the closure.
|
||||
#The cell contents refer to the value stored within the cell associated with a particular variable in a closure. It represents the value of the
|
||||
#variable as seen by the closure, regardless of any changes made to the variable in the outer scope.
|
||||
|
||||
#example for "When an instance method object is created by retrieving a user-defined function object from a class via one of its instances,
|
||||
#its __self__ attribute is the instance, and the method object is said to be bound. The new method’s __func__ attribute is the original function
|
||||
#object."
|
||||
"""""
|
||||
class MyClass:
|
||||
def my_method(self):
|
||||
print("Hello, world!")
|
||||
|
||||
# Creating an instance of MyClass
|
||||
my_instance = MyClass()
|
||||
|
||||
# Retrieving the method object from the instance
|
||||
method_object = my_instance.my_method
|
||||
|
||||
# Accessing the attributes of the method object
|
||||
print(method_object.__self__) # Output: <__main__.MyClass object at 0x...>
|
||||
print(method_object.__func__) # Output: <function MyClass.my_method at 0x...>
|
||||
|
||||
# Calling the method through the method object
|
||||
method_object() # Output: Hello, world!
|
||||
"""""
|
||||
|
||||
#async def:
|
||||
# the async def syntax is used to define an asynchronous function, also known as a coroutine. An asynchronous function allows concurrent
|
||||
# execution of multiple tasks by allowing the program to proceed to other tasks while waiting for certain operations to complete.
|
||||
"""""
|
||||
import asyncio
|
||||
|
||||
async def my_coroutine():
|
||||
print("Coroutine started")
|
||||
await asyncio.sleep(1) # Simulating an asynchronous operation
|
||||
print("Coroutine completed")
|
||||
|
||||
# Calling the coroutine
|
||||
asyncio.run(my_coroutine())
|
||||
"""""
|
||||
#Static method and class method:
|
||||
#In Python, static methods and class methods are two types of methods that can be defined within a class.
|
||||
#Static methods:
|
||||
#Static methods are defined using the @staticmethod decorator or by declaring them inside the class without any special decorator.
|
||||
#Static methods are not bound to a specific instance or the class itself. They behave like regular functions but are defined within the class for organizational purposes.
|
||||
#Static methods do not have access to the instance or class attributes and cannot modify them directly.
|
||||
#Static methods can be called on the class itself or on an instance of the class.
|
||||
#Class methods:
|
||||
#Class methods are defined using the @classmethod decorator.
|
||||
#Class methods are bound to the class itself rather than the instances. They receive the class as the first argument (usually named cls) instead of the instance (self).
|
||||
#Class methods have access to the class attributes and can modify them if needed.
|
||||
#Class methods can be called on the class itself or on an instance of the class.
|
||||
|
||||
# question 2:
|
||||
def add_numbers(a, b):
|
||||
result = a + b
|
||||
return result
|
||||
|
||||
def multiply_numbers(x, y):
|
||||
result = x * y
|
||||
return result
|
||||
|
||||
def main():
|
||||
number1 = 5
|
||||
number2 = 10
|
||||
sum_result = add_numbers(number1, number2)
|
||||
breakpoint() # Set breakpoint here
|
||||
product_result = multiply_numbers(sum_result, number2)
|
||||
print("Product:", product_result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
# question 3:
|
||||
|
||||
def calculate_square(x):
|
||||
square = x ** 2
|
||||
return square
|
||||
|
||||
def calculate_cube(x):
|
||||
cube = x ** 3
|
||||
return cube
|
||||
|
||||
def main():
|
||||
number = 5
|
||||
breakpoint() # Set breakpoint here
|
||||
square_result = calculate_square(number)
|
||||
cube_result = calculate_cube(number)
|
||||
print("Square:", square_result)
|
||||
print("Cube:", cube_result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
PS C:\Users\Maxzh\python-bootcamp\max submission> python .\6_9_HW.py
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(89)main()
|
||||
-> product_result = multiply_numbers(sum_result, number2)
|
||||
(Pdb) next
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(90)main()
|
||||
-> print("Product:", product_result)
|
||||
(Pdb) c
|
||||
Product: 150
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(108)main()
|
||||
-> square_result = calculate_square(number)
|
||||
(Pdb) next
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(109)main()
|
||||
-> cube_result = calculate_cube(number)
|
||||
(Pdb) c
|
||||
Square: 25
|
||||
Cube: 125
|
||||
PS C:\Users\Maxzh\python-bootcamp\max submission> python .\6_9_HW.py
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(89)main()
|
||||
-> product_result = multiply_numbers(sum_result, number2)
|
||||
(Pdb) step
|
||||
--Call--
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(80)multiply_numbers()
|
||||
-> def multiply_numbers(x, y):
|
||||
(Pdb) c
|
||||
Product: 150
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(108)main()
|
||||
-> square_result = calculate_square(number)
|
||||
(Pdb) step
|
||||
--Call--
|
||||
> c:\users\maxzh\python-bootcamp\max submission\6_9_hw.py(97)calculate_square()
|
||||
-> def calculate_square(x):
|
||||
(Pdb) c
|
||||
Square: 25
|
||||
Cube: 125
|
||||
@@ -0,0 +1,155 @@
|
||||
Von Neumann's model:
|
||||
Von Neumann's model, also known as the Von Neumann architecture or the Von Neumann machine, refers to the conceptual design of a computer architecture. It was proposed by the Hungarian American mathematician and computer scientist John von Neumann in the late 1940s.
|
||||
|
||||
The Von Neumann architecture describes a computer system that consists of the following key components:
|
||||
|
||||
Central Processing Unit (CPU): The CPU is responsible for executing instructions and performing arithmetic and logical operations. It consists of an arithmetic logic unit (ALU) and a control unit.
|
||||
|
||||
Memory: The computer's memory is used to store both data and instructions. In the Von Neumann model, memory is organized as a linear sequence of addressable storage locations, where each location can hold a fixed amount of data. Instructions and data are stored together in the same memory.
|
||||
|
||||
Input/Output (I/O): The I/O devices enable communication between the computer and the external world. This includes devices such as keyboards, mice, displays, printers, and storage devices.
|
||||
|
||||
Bus: The bus is a communication pathway that allows data and instructions to be transferred between the CPU, memory, and I/O devices. It consists of address lines, data lines, and control lines.
|
||||
|
||||
Instruction Set: The Von Neumann architecture employs a stored program concept, where instructions are represented in binary form and stored in memory. The CPU fetches instructions from memory, decodes them, and executes them sequentially.
|
||||
|
||||
Sequential Execution: The Von Neumann architecture follows a sequential execution model, where instructions are executed one after another in a predetermined order, unless explicitly modified by branching or looping instructions.
|
||||
Mutable:
|
||||
In Python, the term "mutable" refers to an object's ability to be modified or changed after it has been created. In other words, if an object is mutable, its state can be altered by adding, removing, or modifying its elements or attributes.
|
||||
# Mutable list
|
||||
my_list = [1, 2, 3]
|
||||
my_list.append(4)
|
||||
print(my_list) # Output: [1, 2, 3, 4]
|
||||
On the other hand, some objects in Python are immutable, which means their state cannot be changed after they are created. Examples of immutable objects include strings, numbers (integers, floats), and tuples. When you modify an immutable object, a new object is created instead.
|
||||
# Immutable tuple
|
||||
my_tuple = (1, 2, 3)
|
||||
new_tuple = my_tuple + (4,)
|
||||
print(my_tuple) # Output: (1, 2, 3)
|
||||
print(new_tuple) # Output: (1, 2, 3, 4)
|
||||
|
||||
garbage-collected:
|
||||
In computer programming, garbage collection is a mechanism that automatically manages the memory used by a program. It frees up memory that is no longer needed, allowing it to be reused by other parts of the program. Garbage collection is especially useful in languages that provide automatic memory management, such as Python.
|
||||
|
||||
circular references:
|
||||
Circular references, also known as reference cycles, occur in programming languages when a group of objects reference each other in a way that creates a loop or cycle of references. This means that each object in the cycle refers to at least one other object in the cycle, forming a closed chain of references.
|
||||
In languages like Python that employ automatic memory management, circular references can lead to memory leaks, where memory occupied by unused objects is not reclaimed. This can result in the program consuming more and more memory over time, potentially leading to performance issues or crashes.
|
||||
|
||||
arithmetic operators:
|
||||
Arithmetic operators are used in programming languages, including Python, to perform mathematical operations on numerical values. Python provides several arithmetic operators that allow you to perform addition, subtraction, multiplication, division, and more.
|
||||
|
||||
A fruitful optimization:
|
||||
One example of a fruitful optimization is loop unrolling. Loop unrolling is a technique used to optimize the execution speed of loops by reducing loop control overhead and increasing instruction-level parallelism.
|
||||
|
||||
In a loop, the program executes a set of instructions repeatedly until a certain condition is met. Loop unrolling aims to reduce the number of iterations by increasing the number of instructions executed per iteration. This can lead to improved performance by reducing the overhead associated with loop control, such as loop variable updates and condition checks.
|
||||
|
||||
C function:
|
||||
A C function is a block of code in the C programming language that performs a specific task and can be called or invoked from other parts of a C program. Functions in C allow for modular programming, code reuse, and better organization of code.
|
||||
|
||||
C3 method:
|
||||
The C3 method, also known as the C3 linearization algorithm, is a method used in multiple inheritance to determine the order in which methods should be resolved or inherited from different parent classes. It is commonly used in programming languages that support multiple inheritance, such as Python.
|
||||
|
||||
The C3 method was developed by the developers of the programming language Dylan and later adopted by other languages, including Python.
|
||||
|
||||
The C3 method follows a specific algorithm to generate a linearization or method resolution order (MRO) for a class hierarchy. The linearization ensures that the order of method resolution is consistent and avoids conflicts and ambiguities that may arise due to multiple inheritance.
|
||||
|
||||
‘diamond’ inheritance structures:
|
||||
Diamond inheritance, also known as the diamond problem or diamond inheritance ambiguity, is a specific situation that arises in some programming languages with multiple inheritance. It occurs when a class inherits from two or more classes, which in turn inherit from a common base class. The inheritance hierarchy forms a diamond shape, hence the name.
|
||||
A
|
||||
/ \
|
||||
B C
|
||||
\ /
|
||||
D
|
||||
In this diagram, classes B and C inherit from class A, and class D inherits from both B and C. As a result, D indirectly inherits from A through multiple paths. This creates an ambiguity when resolving method or attribute lookup.
|
||||
|
||||
The diamond problem arises when a method or attribute is invoked on an instance of D, and there are conflicting implementations or definitions of the same method or attribute in classes B, C, or A. In such cases, it is unclear which implementation should be used.
|
||||
|
||||
socket objects:
|
||||
Socket objects are programming constructs used in network programming to establish communication channels between devices over a network. They provide an interface for sending and receiving data across different network protocols, such as TCP/IP or UDP.
|
||||
|
||||
In most programming languages, including Python, socket objects are used to create and manipulate sockets. Sockets enable communication between a client and a server or between two peers by providing methods and properties to establish connections, send and receive data, and manage network-related operations.
|
||||
|
||||
positional arguments:
|
||||
Positional arguments refer to the arguments passed to a function or method based on their position or order. When invoking a function or method, positional arguments are provided in the order specified by the function's definition or documentation.
|
||||
|
||||
In many programming languages, including Python, function parameters can be defined as positional parameters. When calling the function, you must provide values for these parameters in the same order they are defined.
|
||||
|
||||
nested functions:
|
||||
Nested functions, also known as inner functions, are functions defined inside another function. In many programming languages, including Python, functions can be defined within the scope of another function.
|
||||
|
||||
line numbers:
|
||||
In programming, line numbers are often associated with the lines of code within a file or program. They serve as a reference to locate specific lines for various purposes, such as debugging, error messages, or code navigation.
|
||||
|
||||
Many integrated development environments (IDEs) and text editors display line numbers alongside the code to make it easier for developers to refer to specific lines. These line numbers typically appear on the left-hand side of the code editor or in the margin.
|
||||
|
||||
#boolean context:
|
||||
#In programming, a boolean context refers to a situation where a condition or expression is evaluated as either true or false.
|
||||
#A boolean context typically occurs in control flow statements, such as if statements or while loops, where the condition determines whether
|
||||
#a certain block of code should be executed or repeated.
|
||||
|
||||
#Ellipsis:
|
||||
#an ellipsis (...) is a special token that represents an ellipsis object. It is often used as a placeholder in code or data structures where
|
||||
#you intend to fill in additional functionality or content later.
|
||||
|
||||
#machine-level double precision floating point numbers
|
||||
#Machine-level double precision floating-point numbers, often referred to as double, are a common representation of real numbers in computer systems.
|
||||
#They are a binary format used to store and manipulate floating-point values with higher precision compared to single precision.
|
||||
|
||||
#Callable types:
|
||||
#callable types refer to objects that can be called as functions. These objects are capable of executing code when invoked with parentheses, just
|
||||
#like a regular function.
|
||||
|
||||
#cell_contents:
|
||||
#the term "cell contents" refers to the value stored in a cell of a closure. A closure is a function object that retains references to variables
|
||||
#in its enclosing lexical scope, even when the outer function has finished executing.
|
||||
#When a closure is created, each variable it references is stored in a cell, which is an internal data structure associated with the closure.
|
||||
#The cell contents refer to the value stored within the cell associated with a particular variable in a closure. It represents the value of the
|
||||
#variable as seen by the closure, regardless of any changes made to the variable in the outer scope.
|
||||
|
||||
#example for "When an instance method object is created by retrieving a user-defined function object from a class via one of its instances,
|
||||
#its __self__ attribute is the instance, and the method object is said to be bound. The new method’s __func__ attribute is the original function
|
||||
#object."
|
||||
"""""
|
||||
class MyClass:
|
||||
def my_method(self):
|
||||
print("Hello, world!")
|
||||
|
||||
# Creating an instance of MyClass
|
||||
my_instance = MyClass()
|
||||
|
||||
# Retrieving the method object from the instance
|
||||
method_object = my_instance.my_method
|
||||
|
||||
# Accessing the attributes of the method object
|
||||
print(method_object.__self__) # Output: <__main__.MyClass object at 0x...>
|
||||
print(method_object.__func__) # Output: <function MyClass.my_method at 0x...>
|
||||
|
||||
# Calling the method through the method object
|
||||
method_object() # Output: Hello, world!
|
||||
"""""
|
||||
|
||||
#async def:
|
||||
# the async def syntax is used to define an asynchronous function, also known as a coroutine. An asynchronous function allows concurrent.
|
||||
# execution of multiple tasks by allowing the program to proceed to other tasks while waiting for certain operations to complete.
|
||||
"""""
|
||||
import asyncio
|
||||
|
||||
async def my_coroutine():
|
||||
print("Coroutine started")
|
||||
await asyncio.sleep(1) # Simulating an asynchronous operation
|
||||
print("Coroutine completed")
|
||||
|
||||
# Calling the coroutine
|
||||
asyncio.run(my_coroutine())
|
||||
"""""
|
||||
#Static method and class method:
|
||||
#In Python, static methods and class methods are two types of methods that can be defined within a class.
|
||||
#Static methods:
|
||||
#Static methods are defined using the @staticmethod decorator or by declaring them inside the class without any special decorator.
|
||||
#Static methods are not bound to a specific instance or the class itself. They behave like regular functions but are defined within the class for organizational purposes.
|
||||
#Static methods do not have access to the instance or class attributes and cannot modify them directly.
|
||||
#Static methods can be called on the class itself or on an instance of the class.
|
||||
#Class methods:
|
||||
#Class methods are defined using the @classmethod decorator.
|
||||
#Class methods are bound to the class itself rather than the instances. They receive the class as the first argument (usually named cls) instead of the instance (self).
|
||||
#Class methods have access to the class attributes and can modify them if needed.
|
||||
#Class methods can be called on the class itself or on an instance of the class.
|
||||
Reference in New Issue
Block a user