Slide 1

Slide 1 text

DescriptorΛ΋͏গ͠ 2020.05.08 Remote.py #1 @everes a.k.a tsuyukimakoto

Slide 2

Slide 2 text

ۦ͚ग़͠ YouTuber ʢνϟϯωϧొ࿥Φωγϟεʣ ͓લ୭Αʁ ͑἖͊͞ΜͬͯݺΜͰ͍ͩ͘͞ʢͱࡢ೥຤͔Βݴ͍࢝Ί·ͨ͠ʣ

Slide 3

Slide 3 text

͓લ୭Αʁ ͑἖͊͞ΜͬͯݺΜͰ͍ͩ͘͞ʢͱࡢ೥຤͔Βݴ͍࢝Ί·ͨ͠ʣ PythonΛ͞ΘΓ͸͡Ίͯ·ͩ 20೥ܦͬͯͳ͍͘Β͍ django-jaॳ୅୅ද https://twitter.com/everes #followme

Slide 4

Slide 4 text

2020೥6݄1೔ վగ2൛Ͱ·͢ʂ ύʔϑΣΫτPython վగ2൛ https://amzn.to/2zaJIiV ༧໿ड෇தʂ

Slide 5

Slide 5 text

INTERMEDIATE΁ͷೖΓޱతͳʁ ຊ೔ͷ͓୊ • Attribute • Property • Descriptor • Meta Class

Slide 6

Slide 6 text

ATTRIBUTEʢΞτϦϏϡʔτʣ

Slide 7

Slide 7 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>>

Slide 8

Slide 8 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> Spam.egg "I'm egg!" >>> spam = Spam() >>> spam.egg "I'm egg!"

Slide 9

Slide 9 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> Spam.egg "I'm egg!" >>> spam = Spam() >>> spam.egg "I'm egg!" >>> Spam.egg "I'm egg!" >>> spam = Spam() >>> spam.egg "I'm egg!"

Slide 10

Slide 10 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> Spam.egg "I'm egg!" >>> spam = Spam() >>> spam.egg "I'm egg!" >>> Spam.egg "I'm egg!" >>> spam = Spam() >>> spam.egg "I'm egg!" >>> Spam.egg "I'm egg!" >>> spam = Spam() >>> spam.egg "I'm egg!"

Slide 11

Slide 11 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg"

Slide 12

Slide 12 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg" >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg"

Slide 13

Slide 13 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg" >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg" >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg"

Slide 14

Slide 14 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg" >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg" >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg" >>> spam.egg = "I'm boiled egg" >>> Spam.egg "I'm egg!" >>> spam.egg "I'm boiled egg"

Slide 15

Slide 15 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> del spam.egg >>> spam.egg ʁʁʁ

Slide 16

Slide 16 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> spam.egg "I'm egg!" >>> Spam.egg = "I'm poached egg" >>> spam.egg "I'm poached egg"

Slide 17

Slide 17 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... egg = "I'm egg!" ... >>> spam.egg "I'm egg!" >>> Spam.egg = "I'm poached egg" >>> spam.egg "I'm poached egg" >>> spam.egg "I'm egg!" >>> Spam.egg = "I'm poached egg" >>> spam.egg "I'm poached egg"

Slide 18

Slide 18 text

Class Spam egg = “poached egg” spam1 (instance) egg = “boiled egg” spam2 (instance) >>> spam1.egg >>> spam2.egg

Slide 19

Slide 19 text

PROPERTYʢϓϩύςΟʣ

Slide 20

Slide 20 text

class C: def __init__(self): self._x = None def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x x = property(getx, setx, delx, "I'm the 'x' property.") ఆٛ: class property(fget=None, fset=None, fdel=None, doc=None) https://docs.python.org/3/library/functions.html#property

Slide 21

Slide 21 text

class C: def __init__(self): self._x = None def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x x = property(getx, setx, delx, "I'm the 'x' property.") ఆٛ: class property(fget=None, fset=None, fdel=None, doc=None) https://docs.python.org/3/library/functions.html#property >>> type(property) >>> type(int)

Slide 22

Slide 22 text

class C: def __init__(self): self._x = None def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x x = property(getx, setx, delx, "I'm the 'x' property.") ఆٛ: class property(fget=None, fset=None, fdel=None, doc=None) https://docs.python.org/3/library/functions.html#property

Slide 23

Slide 23 text

class C: def __init__(self): self._x = None @property def x(self): """I'm the 'x' property.""" return self._x @x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x ఆٛ: class property(fget=None, fset=None, fdel=None, doc=None) https://docs.python.org/3/library/functions.html#property

Slide 24

Slide 24 text

$ python Python 3.8.2 (default, Mar 11 2020, 00:29:50) >>> class Spam: ... def __init__(self): ... self.egg = None ... >>> spam = Spam() >>> spam.egg = “I’m egg!”

Slide 25

Slide 25 text

>>> class Spam: ... def __init__(self): ... self.__egg = None ... @property ... def egg(self): ... return self.__egg ... @egg.setter ... def egg(self, egg): ... self.__egg = egg ແҙຯͳ setter/getter͸࡞Βͳ͍

Slide 26

Slide 26 text

>>> class Spam: ... def __init__(self): ... self.__egg = None ... @property ... def egg(self): ... return self.__egg ... @egg.setter ... def egg(self, egg): ... self.__egg = egg >>> spam.egg = “I’m egg” લఏͱͯ͠ ແҙຯͳ setter/getter͸࡞Βͳ͍

Slide 27

Slide 27 text

>>> class Spam: ... def __init__(self): ... self.__egg = None ... @property ... def egg(self): ... return self.__egg ... @egg.setter ... def egg(self, egg): ... self.__egg = egg >>> spam.egg “I’m egg” લఏͱͯ͠ ແҙຯͳ setter/getter͸࡞Βͳ͍

Slide 28

Slide 28 text

DESCRIPTORʢσΟεΫϦϓλʔʣ

Slide 29

Slide 29 text

•descr.__get__(self, obj, type=None) -> value •descr.__set__(self, obj, value) -> None •descr.__delete__(self, obj) -> None •descr.__set_name__(self, owner, name) -> None
 ʢPython3.6Ҏ߱ʣ Descriptor ҎԼͷ্͔Β3ϝιουͷ͍ͣΕ͔1ͭҎ্Λ࣋ͭΦϒδΣΫτ

Slide 30

Slide 30 text

•descr.__get__(self, obj, type=None) -> value •descr.__set__(self, obj, value) -> None •descr.__delete__(self, obj) -> None •descr.__set_name__(self, owner, name) -> None
 ʢPython3.6Ҏ߱ʣ Descriptor ҎԼͷ্͔Β3ϝιουͷ͍ͣΕ͔1ͭҎ্Λ࣋ͭΦϒδΣΫτ __ ← double under ← dunderʢμϯμʔʣ

Slide 31

Slide 31 text

>>> var1 = SomeClass() >>> var2 = SomeClass() >>> var1.data1 = 3 >>> var1.data2 = -5 >>> var2.data1 = -2 >>> print(var1.data1) 3 >>> print(var1.data2) 5 >>> print(var2.data1) 2

Slide 32

Slide 32 text

def absolute_integer(value): if value is None: return 0 if not isinstance(value, int): raise TypeError if value < 0: return value * -1 return value

Slide 33

Slide 33 text

class AbsoluteInteger: def __set_name__(self, owner, name): self.name = '_' + name def __set__(self, instance, value): setattr(instance, self.name, absolute_integer(value)) def __get__(self, instance, owner): if not hasattr(instance, self.name): return self return getattr(instance, self.name) def __delete__(self, instance): if not hasattr(instance, self.name): return delattr(instance, self.name) self = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥεͷΞτϦϏϡʔτ (SomeClass.data1, SomeClass.data2) instance = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥεͷΠϯελϯε(var1, var2) owner = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥε(SomeClass)

Slide 34

Slide 34 text

class AbsoluteInteger: def __set_name__(self, owner, name): self.name = '_' + name def __set__(self, instance, value): setattr(instance, self.name, absolute_integer(value)) def __get__(self, instance, owner): if not hasattr(instance, self.name): return self return getattr(instance, self.name) def __delete__(self, instance): if not hasattr(instance, self.name): return delattr(instance, self.name) self = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥεͷΞτϦϏϡʔτ (SomeClass.data1, SomeClass.data2) instance = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥεͷΠϯελϯε(var1, var2) owner = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥε(SomeClass) >>> class SomeClass: >>> data1 = AbsoluteInteger() >>> data2 = AbsoluteInteger() ... >>> var1 = SomeClass() >>> var2 = SomeClass()

Slide 35

Slide 35 text

class AbsoluteInteger: def __set_name__(self, owner, name): self.name = '_' + name def __set__(self, instance, value): setattr(instance, self.name, absolute_integer(value)) def __get__(self, instance, owner): if not hasattr(instance, self.name): return self return getattr(instance, self.name) def __delete__(self, instance): if not hasattr(instance, self.name): return delattr(instance, self.name) self = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥεͷΞτϦϏϡʔτ (SomeClass.data1, SomeClass.data2) instance = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥεͷΠϯελϯε(var1, var2) owner = σΟεΫϦϓλʔ͕ొ࿥͞Ε͍ͯΔΫϥε(SomeClass) >>> class SomeClass: >>> data1 = AbsoluteInteger() >>> data2 = AbsoluteInteger() ... >>> var1 = SomeClass() >>> var2 = SomeClass() ← SomeClass.data1.name, SomeClass.data2.name

Slide 36

Slide 36 text

>>> class SomeClass: >>> data1 = AbsoluteInteger() >>> data2 = AbsoluteInteger() ... >>> var1 = SomeClass() >>> var2 = SomeClass() >>> var1.data1 = 3 >>> var1.data2 = -5 >>> var2.data1 = -2 >>> print(var1.data1) 3 >>> print(var1.data2) 5 >>> print(var2.data1) 2 >>> del var1.data1 >>> print(var1.data1) >>> print(var2.data2) >>> print(var1._data2) 5

Slide 37

Slide 37 text

https://github.com/python/cpython/blob/3.8/Objects/descrobject.c#L1380 property

Slide 38

Slide 38 text

META CLASSʢϝλΫϥεʣ

Slide 39

Slide 39 text

from django.db import models class SampleModel(models.Model): num = models.IntegerField()

Slide 40

Slide 40 text

from django.db import models class SampleModel(models.Model): num = models.IntegerField() >>> SampleModel.num

Slide 41

Slide 41 text

https://github.com/django/django/blob/3.0.6/django/db/models/base.py#L71 class ModelBase(type): """Metaclass for all models.""" def __new__(cls, name, bases, attrs, **kwargs): super_new = super().__new__ ... #লུ # Pass all attrs without a (Django-specific) contribute_to_class() # method to type.__new__() so that they're properly initialized # (i.e. __set_name__()). contributable_attrs = {} for obj_name, obj in list(attrs.items()): if _has_contribute_to_class(obj): contributable_attrs[obj_name] = obj else: new_attrs[obj_name] = obj new_class = super_new(cls, name, bases, new_attrs, **kwargs) ... #লུ

Slide 42

Slide 42 text

>>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020 https://github.com/django/django/blob/3.0.6/django/db/models/query_utils.py#L117 DeferredAttributeͷ __get__ ʹσόοάΞ΢τΛ࢓ࠐΜͰ΍ͬͯΈΔͱ໘ന͍͔΋ʙ

Slide 43

Slide 43 text

>>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020 https://github.com/django/django/blob/3.0.6/django/db/models/query_utils.py#L117 DeferredAttributeͷ __get__ ʹσόοάΞ΢τΛ࢓ࠐΜͰ΍ͬͯΈΔͱ໘ന͍͔΋ʙ >>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020

Slide 44

Slide 44 text

>>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020 https://github.com/django/django/blob/3.0.6/django/db/models/query_utils.py#L117 DeferredAttributeͷ __get__ ʹσόοάΞ΢τΛ࢓ࠐΜͰ΍ͬͯΈΔͱ໘ന͍͔΋ʙ >>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020 >>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020

Slide 45

Slide 45 text

>>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020 https://github.com/django/django/blob/3.0.6/django/db/models/query_utils.py#L117 DeferredAttributeͷ __get__ ʹσόοάΞ΢τΛ࢓ࠐΜͰ΍ͬͯΈΔͱ໘ന͍͔΋ʙ >>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020 >>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020 >>> sample = SampleModel(num=2020)
 >>> sample.save()
 >>> instance = SampleModel.objects.get(pk=1)
 >>> instance.num
 2020
 >>> del instance.num
 >>> instance.num
 2020

Slide 46

Slide 46 text

2020೥6݄1೔ վగ2൛Ͱ·͢ʂ ύʔϑΣΫτPython վగ2൛ https://amzn.to/2zaJIiV ༧໿ड෇தʂ