Update page 'Day 5&6 Homework - Karen'
@@ -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)
|
||||
```
|
||||
@@ -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"]
|
||||
```
|
||||
Reference in New Issue
Block a user