Update page 'Day 5&6 Homework - Karen'

2023-04-12 00:38:30 +02:00
parent 55f1fc0f7a
commit 00a9b22589
2 changed files with 116 additions and 30 deletions
-30
@@ -1,30 +0,0 @@
**The assignment for tonight is to write a class named Vault containing an attribute named "treasure" which returns "gold" under normal circumstances, but a warning message such as "attribute deleted!" if it detects any of its attributes have been changed. You can use the descriptor protocol (__set__, etc) to detect if its attributes have been changed, and it will have to check its own __dict__ against a known good copy before accessing the treasure attribute to make sure that the attributes are what they're supposed to be.**
```
class Vault:
def __init__(self):
self._treasure = "gold"
self._original_dict = dict(self.__dict__)
def __setattr__(self, name, value):
if name != "_treasure" and name in self.__dict__ and self._original_dict.get(name) != value:
print("attribute deleted!")
self.__dict__[name] = value
@property
def treasure(self):
if self.__dict__ != self._original_dict:
print("attribute deleted!")
return self._treasure
v = Vault()
print(v.treasure)
```
To assess other's Vault (although it may not be ethical), we can use `__getattribute__` method like:
```
class EvilVault(Vault):
def __getattribute__(self, name):
if name == "treasure":
return "gold"
return super().__getattribute__(name)
```
+116
@@ -0,0 +1,116 @@
**The assignment for tonight is to write a class named Vault containing an attribute named "treasure" which returns "gold" under normal circumstances, but a warning message such as "attribute deleted!" if it detects any of its attributes have been changed. You can use the descriptor protocol (__set__, etc) to detect if its attributes have been changed, and it will have to check its own __dict__ against a known good copy before accessing the treasure attribute to make sure that the attributes are what they're supposed to be.**
```
class Vault:
def __init__(self):
self._treasure = "gold"
self._original_dict = dict(self.__dict__)
def __setattr__(self, name, value):
if name != "_treasure" and name in self.__dict__ and self._original_dict.get(name) != value:
print("attribute deleted!")
self.__dict__[name] = value
@property
def treasure(self):
if self.__dict__ != self._original_dict:
print("attribute deleted!")
return self._treasure
v = Vault()
print(v.treasure)
```
Here is another method using `__getattribute__` and `__setattr__`.
```
class Vault:
def __init__(self):
self._treasure = "gold"
self._known_good_copy = self.__dict__.copy()
def __getattribute__(self, name):
if name == "treasure":
if self.__dict__ != self._known_good_copy:
print("Attribute deleted!")
return self._treasure
else:
return object.__getattribute__(self, name)
def __setattr__(self, name, value):
if name != "_treasure" and name != "_known_good_copy":
print("Attribute deletion detected!")
self._known_good_copy = self.__dict__.copy()
object.__setattr__(self, name, value)
v = Vault()
print(v.treasure)
```
Also, we can define a descriptor by implementing the `__get__`, `__set__`, and `__delete__` methods.
```
class Vault:
def __init__(self):
self._treasure = "gold"
self._known_good_copy = self.__dict__.copy()
def __get__(self, instance, owner):
if instance is None:
return self
else:
if instance.__dict__ != self._known_good_copy:
print("Attribute deleted!")
return self._treasure
def __set__(self, instance, value):
print("Attribute deletion detected!")
self._known_good_copy = instance.__dict__.copy()
def __delete__(self, instance):
print("Attribute deletion detected!")
self._known_good_copy = instance.__dict__.copy()
def __set_name__(self, owner, name):
self.name = name
v = Vault()
print(v._treasure)
```
Unfortunately, I didn't figure out what happened to the code that I used `super().__setattr__` last week, so I create a question on stack overflow to see if someone can help me with this issue.
https://stackoverflow.com/questions/75990535/attributeerror-and-recursionerror-happened-when-using-setattr-in-python
```
class Vault:
def __init__(self):
self._treasure = "gold"
self._attributes = dict(self.__dict__)
def __setattr__(self, name, value):
if name != "_attributes" and name not in self._attributes:
print("attribute deleted!")
self._attributes[name] = value
super().__setattr__("_attributes", dict(self.__dict__))
@property
def treasure(self):
if self.__dict__ != self._attributes:
print("attribute deleted!")
return self._treasure
v = Vault()
print(v.treasure)
```
To assess other's Vault (although it may not be ethical), we can use `__getattribute__` method like:
```
class EvilVault(Vault):
def __getattribute__(self, name):
if name == "treasure":
return "gold"
return super().__getattribute__(name)
```
Or I think we can use another easier way as accessing the attribute through the class's dictionary:
```
Vault.__dict__["_treasure"]
```