Compare commits
4
Commits
f4981fb8fd
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a335bc362 | ||
|
|
5440bf3773 | ||
|
|
57e46c4fce | ||
|
|
fe40d7f00e |
@@ -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,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,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,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.
|
||||||
Reference in New Issue
Block a user