The other day I learned about 100 Days Of Code, which was popular on Twitter for a while. The purpose of this article is to keep a record and output how much I, as a beginner, can grow through 100 days of study. I think there are many mistakes and difficult to read. I would appreciate it if you could point out!
--Chapter 8 structure --Page 216 of this chapter
--Progress: Pages 95-101 --Chapter 4: Metaclasses and Attributes ――I will write down what I often forget or didn't know about what I learned today.
@property
methods@staticmethod
Convert the method to a static method. Static methods do not take an implicit first argument. That is, it does not have self as its first argument. When you get a static method from a class or class instance, the actual returned object is a wrapped object and no further conversions are made.
__get__
methodobject.__get__(self, instance, owner)
The __get__
method is a method that is called every time the attributes of the owning class or the attributes of an instance of that class are retrieved.
Let's look at an example.
class SampleGet(object):
def __init__(self, x):
self._x = x
def __get__(self, instance, owner):
print('Hello')
print(instance)
print(owner)
return owner
class Sample(object):
sample_get = SampleGet(100)
obj = Sample()
print('print', obj.sample_get) #Because we got the attributes of an instance of the class__get__Call the method
Output result
Hello
<__main__.Sample object at 0x00000289EDAB11C8> # instance
<class '__main__.Sample'> # owner
print <class '__main__.Sample'> # obj.sample_get
__set__
methodobject.__set__(self, instance, value)
The __get__
method is the method that is called when setting the attribute on the instance of the owner class to a new value (value).
class SampleGet
Let's look at an example.
class SampleSet(object):
def __init__(self, x):
self._x = x
def __set__(self, instance, value):
print('World!')
print(instance)
print(value)
return self.value
class Sample(object):
sample_set = SampleSet(100)
obj = Sample() #Instantiation of Sample class
obj.sample_set = 200 #New value for attributes on the instance(200)Set to
# World! #Because the value of the attribute on the instance has changed__set__The method is called and World!And output
# <__main__.Sample object at 0x000002069D921188> # instance
# 200 # value
Descriptors define how attribute access is interpreted in the language.
Descriptor classes use the __get__
, __set__
, and __delete__
methods to override attribute access.
An object is said to be a scripter if any of these methods are defined for the object.
weakref
It is one of the Python built-in modules, and you can take measures against memory leaks. This module removes an instance from the last remaining reference of the instance programmatically at run time if it is only held in the key set of that dictionary.
@property
is very convenient because you can add necessary processing sequentially, but the disadvantage is that it cannot be reused.
The method you decorate cannot be reused for multiple attributes in the same class.
To solve this, use a descriptor.
As an example, suppose you want to create a class that manages the evaluation of each subject in a student's exam.
class Grade(object):
#descriptor
def __get__(self, instance, instance_type):
pass
def __set__(self, instance, value):
pass
class Exam(object):
#Generate a Grade instance for each subject
math_grade = Grade()
writing_grade = Grade()
science_grade = Grade()
exam = Exam()
exam.writing_grade = 40
print(exam.writing_grade)
exam.writing_grade = 40
is interpreted as follows:
Exam.__dict_['writing_grade'].__set__(exam, 40)
That is, __set__ ()
is called with an instance of __set__ (self, instance, value)
as an argument and a value of 40 as an argument.
print (exam.writing_grade)
is interpreted as follows:
print(Exam.__dict__['writing_grade'].__get__(exam, Exam))
In other words, __get__ ()
is called with exam insntace of __get__ (self, instance, value)
and value as an argument of Exam.
Now, let's proceed with the implementation.
from weakref import WeakKeyDictionary
class Grade(object):
def __init__(self):
# self._values = {} #With this, the instance reference never becomes zero, so memory cannot be recovered by garbage collection.
self._values = WeakKeyDictionary() #Delete the Exam instance if the only remaining reference at the end of the instance that replaces the dictionary is the key set for that dictionary.
def __get__(self, instance, instance_type):
if instance is None:
return self
return self._values.get(instance, 0)
def __set__(self, instance, value):
if not (0 <= value <= 100):
raise ValueError('Grade must be between 0 and 100')
self._values[instance] = value
first_exam = Exam()
first_exam.writing_grade = 80
first_exam.science_grade = 99
print('Writing', first_exam.writing_grade)
print('Science', first_exam.science_grade)
second_exam = Exam()
second_exam.writing_grade = 75
print('Second', second_exam.writing_grade)
Output result
Writing 80
Science 99
Second 75
By using the descriptor, I was able to write the code concisely without using @property
many times.
https://docs.python.org/ja/3.7/reference/datamodel.html#object
Recommended Posts