Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Metaclass?Descriptor?完全に理解した()あなたに / pyconjp2020

Metaclass?Descriptor?完全に理解した()あなたに / pyconjp2020

MetaclassやDescriptorについて概要を知ってる状態からなんとなくわかった状態になるために、順を追ってみていきます。

PyConJP 2020 Online の招待講演資料です
- https://pycon.jp/2020/timetable/?id=213322

サンプルコードのjupyter-notebookファイルはGitHubにあります。
- https://github.com/tsuyukimakoto/pyconjp2020

makoto tsuyuki

August 29, 2020
Tweet

More Decks by makoto tsuyuki

Other Decks in Programming

Transcript

  1. "dunders" (i.e. names with two leading and two trailing underscores)

    μϯμʔ https://www.python.org/dev/peps/pep-0008/#module-level-dunder-names
  2. "dunders" (i.e. names with two leading and two trailing underscores)

    https://www.python.org/dev/peps/pep-0008/#module-level-dunder-names __init__ __dict__
  3. class ModelBase(type): "Metaclass for all models" def __new__(cls, name, bases,

    attrs): # If this isn't a subclass of Model, don't do anything special. … https://github.com/django/django/blob/e27211a0deae2f1d402537f0ebb64ad4ccf6a4da/django/core/meta/__init__.py#L394 githubܦ༝Ͱ༰қʹͨͲΕͨi18nϒϥϯνͬͯݺ͹Εͯͨόʔδϣϯʢ2005/12ʣͷ΋ͷ ←typeΛܧঝ͍ͯͯ͠ɺ __new__ ϝιου͕ఆٛ͞Ε͍ͯΔ ϝλΫϥε
  4. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ॅॴ࿥ ౎ಓ෎ݝ
  5. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ←ϑΝΠϧ ॅॴ࿥ ౎ಓ෎ݝ
  6. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ←ϑΝΠϧ ↑γʔτ ॅॴ࿥ ౎ಓ෎ݝ
  7. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ←ϑΝΠϧ ↑γʔτ ↓ྻ ߦ→ ॅॴ࿥ ౎ಓ෎ݝ
  8. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ←ϑΝΠϧ ↑γʔτ ↓ྻ ߦ→ ॅॴ࿥ ౎ಓ෎ݝ RDBMS = Relational Database Management System
  9. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ←ϑΝΠϧ ↑γʔτ ↓ྻ ߦ→ ॅॴ࿥ ౎ಓ෎ݝ RDBMS = Relational Database Management System DjangoͷϞσϧ = Object Relational Mapper = O/R Mapper
  10. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ౎ಓ෎ݝʢϚελʔσʔλʣ ίʔυ ౎ಓ෎ݝ 13 13 ౦ژ౎ 14 14 ਆಸ઒ݝ 15 15 ৽ׁ 16 γʔτ = ද ʹςʔϒϧ
  11. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ౎ಓ෎ݝʢϚελʔσʔλʣ ίʔυ ౎ಓ෎ݝ 13 13 ౦ژ౎ 14 14 ਆಸ઒ݝ 15 15 ৽ׁ 16 ߦ γʔτ = ද ʹςʔϒϧ
  12. ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211

    ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ౎ಓ෎ݝʢϚελʔσʔλʣ ίʔυ ౎ಓ෎ݝ 13 13 ౦ژ౎ 14 14 ਆಸ઒ݝ 15 15 ৽ׁ 16 ߦ ྻ γʔτ = ද ʹςʔϒϧ
  13. Djangoͷॅॴ࿥Ϟσϧ from django.db import models # Create your models here.

    class Prefecture(models.Model): code = models.CharField(max_length=2) name = models.CharField(max_length=4) class Address(models.Model): zipcode = models.CharField(max_length=7) prefecture = models.ForeignKey(Prefecture, on_delete=models.PROTECT) name = models.CharField(max_length=25) memo = models.TextField(blank=True) ϞσϧΫϥε ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211 ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ౎ಓ෎ݝʢϚελʔσʔλʣ ίʔυ ౎ಓ෎ݝ 1 13 ౦ژ౎ 2 14 ਆಸ઒ݝ 3 15 ৽ׁ 4
  14. Djangoͷॅॴ࿥Ϟσϧ from django.db import models # Create your models here.

    class Prefecture(models.Model): code = models.CharField(max_length=2) name = models.CharField(max_length=4) class Address(models.Model): zipcode = models.CharField(max_length=7) prefecture = models.ForeignKey(Prefecture, on_delete=models.PROTECT) name = models.CharField(max_length=25) memo = models.TextField(blank=True) ϞσϧΫϥε from django.db import models # Create your models here. class Prefecture(models.Model): code = models.CharField(max_length=2) name = models.CharField(max_length=4) class Address(models.Model): zipcode = models.CharField(max_length=7) prefecture = models.ForeignKey(Prefecture, on_delete=models.PROTECT) name = models.CharField(max_length=25) memo = models.TextField(blank=True) ॅॴ࿥ ༣ศ൪߸ ౎ಓ෎ݝ ࢢ۠ொଜ 1 1008111 ౦ژ౎ ઍ୅ా۠ 2 6308211 ಸྑݝ ಸྑࢢ 3 3291224 ಢ໦ݝ Ԙ୩܊ 4 ౎ಓ෎ݝʢϚελʔσʔλʣ ίʔυ ౎ಓ෎ݝ 1 13 ౦ژ౎ 2 14 ਆಸ઒ݝ 3 15 ৽ׁ 4
  15. Djangoͷॅॴ࿥Ϟσϧ >>> Address.__dict__ mappingproxy({'__module__': 'address.models', '__doc__': 'Address(id, zipcode, prefecture, name,

    memo)', '_meta': <Options for Address>, 'DoesNotExist': address.models.Address.DoesNotExist, 'MultipleObjectsReturned': address.models.Address.MultipleObjectsReturned, 'zipcode': <django.db.models.query_utils.DeferredAttribute at 0x106706970>, 'prefecture_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute at 0x1068b1040>, 'prefecture': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor at 0x1068b10a0>, 'name': <django.db.models.query_utils.DeferredAttribute at 0x1068b1190>, 'memo': <django.db.models.query_utils.DeferredAttribute at 0x1068b11f0>, 'id': <django.db.models.query_utils.DeferredAttribute at 0x1068b1310>, 'objects': <django.db.models.manager.ManagerDescriptor at 0x1068b1250>}) ϞσϧΫϥεͷ __dict__ ← models.CharFieldͰ͸ͳ͘ͳͬͯΔ ϙΠϯτ
  16. Djangoͷॅॴ࿥Ϟσϧ >>> address.__dict__ {'_state': <django.db.models.base.ModelState at 0x107956220>, 'id': None, 'zipcode':

    '2480012', 'prefecture_id': 14, 'name': 'ח૔ࢢ໾ॴ', 'memo': ''} >>> kanagawa = Prefecture.objects.get(code='14') >>> address = Address(zipcode='2480012', prefecture=kanagawa, name=‘ח૔ࢢ໾ॴ')
  17. Djangoͷॅॴ࿥Ϟσϧ >>> address.save() >>> address.__dict__ {'_state': <django.db.models.base.ModelState at 0x107956220>, 'id':

    1, 'zipcode': '2480012', 'prefecture_id': 14, 'name': 'ח૔ࢢ໾ॴ', 'memo': ''} >>> kanagawa = Prefecture.objects.get(code='14') >>> address = Address(zipcode='2480012', prefecture=kanagawa, name=‘ח૔ࢢ໾ॴ')
  18. >>> del address.zipcode >>> address.__dict__ {'_state': <django.db.models.base.ModelState at 0x107956220>, 'id':

    1, 'prefecture_id': 14, 'name': 'ח૔ࢢ໾ॴ', 'memo': ''} Djangoͷॅॴ࿥Ϟσϧ ← zipcode͕ແ͘ͳ͍ͬͯΔ
  19. >>> address.zipcode '2480012' ← delͨ͠͸ͣͳͷʹɺΞΫηεͨ͠Β஋͕໭͖ͬͯͨ ϙΠϯτ Djangoͷॅॴ࿥Ϟσϧ >>> address.__dict__ {'_state':

    <django.db.models.base.ModelState at 0x107956220>, 'id': 1, 'zipcode': '2480012', 'prefecture_id': 14, 'name': 'ח૔ࢢ໾ॴ', 'memo': ''}
  20. class Spam: egg = 'ham' def bake(self): return f"Baked Spam

    Egg Ham from {self.__class__.__name__}" >>> Spam.__name__ 'Spam' >>> Spam.__bases__ (object,) >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': 'ham', 'bake': <function __main__.Spam.bake(self)>, '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) >>> spam = Spam() >>> spam.bake() 'Baked Spam Egg Ham from Spam' Class PythonͷClassͱtype https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/00.perfect_01.ipynb
  21. def bake_method(self): return f"Baked Spam Egg Ham from {self.__class__.__name__}" Spam

    = type('Spam', (), dict(egg='ham', bake=bake_method)) >>> Spam.__name__ 'Spam' >>> Spam.__bases__ (object,) >>> Spam.__dict__ mappingproxy({'egg': 'ham', 'bake': <function __main__.bake_method(self)>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) >>> spam = Spam() >>> spam.bake() 'Baked Spam Egg Ham from Spam' type PythonͷClassͱtype https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/00.perfect_02.ipynb
  22. class MyMeta(type): def __new__(cls, name, bases, class_dict): print(f"cls: {cls}") print(f"name:

    {name}") print(f"bases: {bases}") print(f"class_dict: {class_dict}") return type.__new__(cls, name, bases, class_dict) •__prepare__ •__new__ •__init__ https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/00.perfect_02.ipynb
  23. class Mine(metaclass=MyMeta): spam = "egg" def __init__(self): self.spam = None

    def bark(self): return f"bark from {self.__class__.__name__}" cls: <class '__main__.MyMeta'> bases: () class_dict: { '__module__': '__main__', '__qualname__': 'Mine', 'spam': ‘egg', '__init__': <function Mine.__init__ at 0x1118481f0>, ‘bark': <function Mine.bark at 0x111848280>} https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/00.perfect_02.ipynb
  24. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_01.ipynb class Spam: def __init__(self, egg): self.egg = egg >>>

    spam = Spam('ham') >>> spam.__dict__ {'egg': 'ham'} >>> print(spam.egg) ham Πϯελϯεଐੑ
  25. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_01.ipynb class Spam: def __init__(self, egg): self.egg = egg >>>

    spam = Spam('ham') >>> spam.__dict__ {'egg': 'ham'} >>> print(spam.egg) ham Πϯελϯεଐੑ ← selfͰΞΫηε͢Δݟ׳Εͨ΍ͭ
  26. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_01.ipynb class Spam: def __init__(self, egg): self.egg = egg >>>

    spam = Spam('ham') >>> spam.__dict__ {'egg': 'ham'} >>> print(spam.egg) ham Πϯελϯεଐੑ ← selfͰΞΫηε͢Δݟ׳Εͨ΍ͭ ← spam.egg Έ͍ͨʹΠϯελϯεܦ༝ͰΞΫηεͰ͖Δ
  27. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_02.ipynb class Spam: egg = "I'm egg" >>> Spam.__dict__ mappingproxy({'__module__':

    '__main__', 'egg': "I'm egg", '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεଐੑ
  28. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_02.ipynb class Spam: egg = "I'm egg" >>> Spam.__dict__ mappingproxy({'__module__':

    '__main__', 'egg': "I'm egg", '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεଐੑ ← Ϋϥεʹॻ͍ͯ͋Δ΍ͭ
  29. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_02.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    "I'm egg" >>> spam.egg = "ham" >>> spam.__dict__ {'egg': ‘ham'} >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': "I'm egg", '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεଐੑ
  30. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_02.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    "I'm egg" >>> spam.egg = "ham" >>> spam.__dict__ {'egg': ‘ham'} >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': "I'm egg", '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεଐੑ ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍
  31. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_02.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    "I'm egg" >>> spam.egg = "ham" >>> spam.__dict__ {'egg': ‘ham'} >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': "I'm egg", '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεଐੑ ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍ ← Πϯελϯεܦ༝Ͱ΋ΞΫηε͸Ͱ͖Δ
  32. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_02.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    "I'm egg" >>> spam.egg = "ham" >>> spam.__dict__ {'egg': ‘ham'} >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': "I'm egg", '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεଐੑ ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍ ← Πϯελϯεܦ༝Ͱ΋ΞΫηε͸Ͱ͖Δ ← ಉ໊ͷΠϯελϯεଐੑΛׂΓ౰ͯΔͱɺΠϯελϯεͷ __dict__ ʹݱΕΔ
  33. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_02.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    "I'm egg" >>> spam.egg = "ham" >>> spam.__dict__ {'egg': ‘ham'} >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': "I'm egg", '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεଐੑ ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍ ← Πϯελϯεܦ༝Ͱ΋ΞΫηε͸Ͱ͖Δ ← ಉ໊ͷΠϯελϯεଐੑΛׂΓ౰ͯΔͱɺΠϯελϯεͷ __dict__ ʹݱΕΔ ← Ϋϥεͷ __dict__ ͷ஋͸ݩͷ··
  34. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_03.ipynb class Spam: egg = "I'm egg" @classmethod def my_egg(cls):

    return cls.egg >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': "I'm egg", 'my_egg': <classmethod at 0x110a4a460>, '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) Ϋϥεϝιου
  35. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_03.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    = 'ham' >>> spam.my_egg() "I'm egg" >>> spam.egg 'ham' >>> spam.__dict__ {'egg': 'ham'} Ϋϥεϝιου
  36. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_03.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    = 'ham' >>> spam.my_egg() "I'm egg" >>> spam.egg 'ham' >>> spam.__dict__ {'egg': 'ham'} Ϋϥεϝιου ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍
  37. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_03.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    = 'ham' >>> spam.my_egg() "I'm egg" >>> spam.egg 'ham' >>> spam.__dict__ {'egg': 'ham'} Ϋϥεϝιου ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍ ← Πϯελϯεଐੑʹ ‘ham’ ΛׂΓ౰ͯ
  38. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_03.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    = 'ham' >>> spam.my_egg() "I'm egg" >>> spam.egg 'ham' >>> spam.__dict__ {'egg': 'ham'} Ϋϥεϝιου ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍ ← Πϯελϯεଐੑʹ ‘ham’ ΛׂΓ౰ͯ ← Ϋϥεϝιουܦ༝͸ɺΫϥεଐੑΛࢀর͢Δ
  39. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_03.ipynb >>> spam = Spam() >>> spam.__dict__ {} >>> spam.egg

    = 'ham' >>> spam.my_egg() "I'm egg" >>> spam.egg 'ham' >>> spam.__dict__ {'egg': 'ham'} Ϋϥεϝιου ← Πϯελϯεͷ __dict__ ʹ͸ݟ౰ͨΒͳ͍ ← Πϯελϯεଐੑʹ ‘ham’ ΛׂΓ౰ͯ ← Ϋϥεϝιουܦ༝͸ɺΫϥεଐੑΛࢀর͢Δ ← Πϯελϯεଐੑ͸ΫϥεଐੑΛࢀরͯ͠΋มΘΒͳ͍
  40. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_04.ipynb class BadSpam: def __init__(self, egg): self.setEgg(egg) def getEgg(self): return

    self.egg def setEgg(self, egg): self.egg = egg >>> spam = BadSpam('ham') >>> spam.__dict__ {'egg': 'ham'} ϓϩύςΟʢෆཁͳΞΫηα͸࡞Βͳ͍ʣ
  41. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_04.ipynb class BadSpam: def __init__(self, egg): self.setEgg(egg) def getEgg(self): return

    self.egg def setEgg(self, egg): self.egg = egg >>> spam = BadSpam('ham') >>> spam.__dict__ {'egg': 'ham'} ϓϩύςΟʢෆཁͳΞΫηα͸࡞Βͳ͍ʣ ಈ࡞͢Δ͚ΕͲμϝ PYTHONIC͡Όͳ͍
  42. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_04.ipynb ϓϩύςΟ class GoodSpam: def __init__(self, egg): self.egg = egg

    >>> spam = GoodSpam('boiled') >>> spam.egg += ‘ double’ 'boiled double' ΧϓηϧԽͱ͔͋ͱ͔ΒͰ͖ΔΜͰ ඞཁʹͳΔ·Ͱແବͳίʔυ͸ॻ͔ͳ͍
  43. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_04.ipynb class GoodSpam: def __init__(self, egg): self.egg = egg @property

    def egg(self): print('getter of egg') return self._egg @egg.setter def egg(self, egg): print('setter of egg') self._egg = egg ϓϩύςΟ >>> spam = GoodSpam('very good ham') setter of egg >>> spam.__dict__ {'_egg': 'very good ham'} >>> spam.egg getter of egg 'very good ham'
  44. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_04.ipynb class GoodSpam: def __init__(self, egg): self.egg = egg @property

    def egg(self): print('getter of egg') return self._egg @egg.setter def egg(self, egg): print('setter of egg') self._egg = egg ϓϩύςΟ >>> spam = GoodSpam('very good ham') setter of egg >>> spam.__dict__ {'_egg': 'very good ham'} >>> spam.egg getter of egg 'very good ham' ← ͜ͷ࣌఺Ͱ@egg.setter͕ಈ࡞͍ͯ͠Δ
  45. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_05.ipynb class Spam: def __init__(self, value): self.__value = value def

    spam_value(self): return self.__value class Egg(Spam): def __init__(self, value): super().__init__("from child: " + value) self.__value = value def egg_value(self): return self.__value ϓϥΠϕʔτʁ >>> egg = Egg('goo') >>> egg.egg_value() 'goo' >>> egg.spam_value() 'from child: goo’ >>> egg.__dict__ {'_Spam__value': 'from child: goo', '_Egg__value': 'goo'}
  46. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/02.classes_01.ipynb class BaseClass: def __init__(self): print(“1: I'm BaseClass __init__") class

    ChildA(BaseClass): def __init__(self): print("1: I'm ChildA __init__") super().__init__() print("2: I'm ChildA __init__") class ChildB(BaseClass): def __init__(self): print("1: I'm ChildB __init__") super().__init__() print("2: I'm ChildB __init__") class Spam(ChildA, ChildB): def __init__(self): print("1: I'm Concrete Class") super().__init__() print("2: I'm Concrete Class") >>> spam = Spam() 1: I'm Concrete Class 1: I'm ChildA __init__ 1: I'm ChildB __init__ 1: I'm BaseClass __init__ 2: I'm ChildB __init__ 2: I'm ChildA __init__ 2: I'm Concrete Class >>> Spam.mro() [__main__.Spam, __main__.ChildA, __main__.ChildB, __main__.BaseClass, object] μΠϠϞϯυܕଟॏܧঝ BaseClass ChildA ChildB Spam ܧঝ
  47. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/02.classes_01.ipynb class BaseClass: def __init__(self): print(“1: I'm BaseClass __init__") class

    ChildA(BaseClass): def __init__(self): print("1: I'm ChildA __init__") super().__init__() print("2: I'm ChildA __init__") class ChildB(BaseClass): def __init__(self): print("1: I'm ChildB __init__") super().__init__() print("2: I'm ChildB __init__") class Spam(ChildA, ChildB): def __init__(self): print("1: I'm Concrete Class") super().__init__() print("2: I'm Concrete Class") >>> spam = Spam() 1: I'm Concrete Class 1: I'm ChildA __init__ 1: I'm ChildB __init__ 1: I'm BaseClass __init__ 2: I'm ChildB __init__ 2: I'm ChildA __init__ 2: I'm Concrete Class >>> Spam.mro() [__main__.Spam, __main__.ChildA, __main__.ChildB, __main__.BaseClass, object] μΠϠϞϯυܕଟॏܧঝ BaseClass ChildA ChildB Spam ܧঝ ϝιου୳ࡧॱ
  48. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/02.classes_01.ipynb class BaseClass: def called_method(self): print(“1: I'm BaseClass called_method") class

    ChildA(BaseClass): def called_method(self): print("1: I'm ChildA called_method") super().called_method() print("2: I'm ChildA called_method") class ChildB(BaseClass): def called_method(self): print("1: I'm ChildB called_method") super().called_method() print("2: I'm ChildB called_method") class Spam(ChildA, ChildB): def called_method(self): print("1: I'm Concreat Class") super().called_method() print("2: I'm Concreat Class") >>> spam = Spam() >>> spam.called_method() 1: I'm Concreat Class 1: I'm ChildA called_method 1: I'm ChildB called_method 1: I'm BaseClass called_method 2: I'm ChildB called_method 2: I'm ChildA called_method 2: I'm Concreat Class μΠϠϞϯυܕଟॏܧঝ BaseClass ChildA ChildB Spam ܧঝ ϝιου୳ࡧॱ
  49. class BaseClass: def called_method(self, value): print(f”1: I'm BaseClass called_method with

    {value}") class ChildA(BaseClass): def called_method(self, value): print("1: I'm ChildA called_method") super().called_method("ChildA") print("2: I'm ChildA called_method") class ChildB(BaseClass): def called_method(self, value): print(f"1: I'm ChildB called_method with {value}") super().called_method("ChildB") print("2: I'm ChildB called_method") class Spam(ChildA, ChildB): def called_method(self, value): print("1: I'm Concreat Class") super().called_method(None) print("2: I'm Concreat Class") >>> spam = Spam() >>> spam.called_method(None) 1: I'm Concreat Class 1: I'm ChildA called_method 1: I'm ChildB called_method with ChildA 1: I'm BaseClass called_method with ChildB 2: I'm ChildB called_method 2: I'm ChildA called_method 2: I'm Concreat Class https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/02.classes_01.ipynb μΠϠϞϯυܕଟॏܧঝ BaseClass ChildA ChildB Spam ܧঝ ϝιου୳ࡧॱ
  50. class BaseClass: def __init__(self): print("I'm BaseClass __init__") class ChildA(BaseClass): def

    __init__(self): print("1: I'm ChildA __init__") super().__init__() print("2: I'm ChildA __init__") class ChildB(BaseClass): def __init__(self): print("1: I'm ChildB __init__") super().__init__() print("2: I'm ChildB __init__") class ChildX(ChildA, ChildB): def __init__(self): print("1: I'm ChildX __init__") super().__init__() print("2: I'm ChildX __init__") class ChildY(ChildA, ChildB): def __init__(self): print("1: I'm ChildY __init__") super().__init__() print("2: I'm ChildY __init__") class Spam(ChildX, ChildY): def __init__(self): print("1: I'm Concreat Class") super().__init__() print("2: I'm Concreat Class") >>> spam = Spam() 1: I'm Concreat Class 1: I'm ChildX __init__ 1: I'm ChildY __init__ 1: I'm ChildA __init__ 1: I'm ChildB __init__ I'm BaseClass __init__ 2: I'm ChildB __init__ 2: I'm ChildA __init__ 2: I'm ChildY __init__ 2: I'm ChildX __init__ 2: I'm Concreat Class >>> Spam.mro() [__main__.Spam, __main__.ChildX, __main__.ChildY, __main__.ChildA, __main__.ChildB, __main__.BaseClass, object] https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/02.classes_01.ipynb BaseClass ChildA ChildB Spam ܧঝ ChildX ChildY ϝιου୳ࡧॱ
  51. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/01.attributes_04.ipynb class BaseClass: def __init__(self): print("I'm BaseClass __init__") class ChildA(BaseClass):

    def __init__(self): print("1: I'm ChildA __init__") super().__init__() print("2: I'm ChildA __init__") class ChildB(BaseClass): def __init__(self): print("1: I'm ChildB __init__") super().__init__() print("2: I'm ChildB __init__") class ChildX(ChildA, ChildB): def __init__(self): print("1: I'm ChildX __init__") super().__init__() print("2: I'm ChildX __init__") class ChildY(ChildB, ChildA): def __init__(self): print("1: I'm ChildY __init__") super().__init__() print("2: I'm ChildY __init__") class Spam(ChildX, ChildY): def __init__(self): print("1: I'm Concreat Class") super().__init__() print("2: I'm Concreat Class") --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-17-7b3e0c160262> in <module> 30 print("2: I'm ChildY __init__") 31 ---> 32 class Spam(ChildX, ChildY): 33 def __init__(self): 34 print("1: I'm Concreat Class") TypeError: Cannot create a consistent method resolution order (MRO) for bases ChildA, ChildB
  52. class Spam: def __init__(self): self.value = 0 @property def value(self):

    return self._value @value.setter def value(self, value): if type(value) is not int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") self._value = value >>> spam = Spam() >>> spam.value = 1 >>> spam.__dict__ {'_value': 1} https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/03.property_01.ipynb >>> spam.value = "10" --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-3-e924802b48db> in <module> ----> 1 spam.value = "10" <ipython-input-1-abf3b6d8088e> in value(self, value) 10 def value(self, value): 11 if type(value) is not int: ---> 12 raise ValueError(f"value should be int, but {value}") 13 if value < 0: 14 raise ValueError(f"value souldn't be negative") ValueError: value should be int, but 10
  53. class Spam: def __init__(self): self.value = 0 @property def value(self):

    return self._value @value.setter def value(self, value): if type(value) is not int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") self._value = value >>> spam = Spam() >>> spam.value = 1 >>> spam.__dict__ {'_value': 1} https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/03.property_01.ipynb >>> spam.value = -1 --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-4-3b6deb05698c> in <module> ----> 1 spam.value = -1 <ipython-input-1-abf3b6d8088e> in value(self, value) 12 raise ValueError(f"value should be int, but {value}") 13 if value < 0: ---> 14 raise ValueError(f"value souldn't be negative") 15 self._value = value ValueError: value souldn't be negative >>> spam.value = 1 >>> spam.__dict__ {'_value': 1}
  54. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/03.property_02.ipynb def check_positive_integer(value): if type(value) is not int: raise ValueError(f"value

    should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") class Spam: def __init__(self): self.value1 = 0 self.value2 = 0 @property def value1(self): return self._value1 @value1.setter def value1(self, value): check_positive_integer(value) self._value1 = value @property def value2(self): return self._value2 @value2.setter def value2(self, value): check_positive_integer(value) self._value2 = value
  55. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/03.property_03.ipynb class PositiveInteger: def __init__(self, value): if type(value) is not

    int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") self.value = value class Spam: def __init__(self): self.value1 = None self.value2 = None >>> spam = Spam() >>> spam.value1 = PositiveInteger(10) >>> spam.value2 = PositiveInteger(20) >>> print(spam.value1.value, spam.value2.value) 10 20
  56. class PositiveInteger: def __set__(self, instance, value): if type(value) is not

    int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") self.value = value def __get__(self, instance, owner): if hasattr(self, 'value'): return self.value return self class Spam: value1 = PositiveInteger() value2 = PositiveInteger() >>> spam = Spam() >>> spam.value1 = 1 >>> spam.value2 = 10 >>> print(spam.value1, spam.value2) 10 20 https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_01.ipynb >>> spam.value1 = "10" --------------------------------------------------------------------------- ValueError Traceback (most recent call last) … ValueError: value should be int, but 10 >>> spam.value1 = -1 --------------------------------------------------------------------------- ValueError Traceback (most recent call last) … ValueError: value souldn't be negative Descriptor •__set__(self, obj, type=None) •__get__(self, obj, value) •__delete__(self, obj)
  57. class PositiveInteger: def __set__(self, instance, value): if type(value) is not

    int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") self.value = value def __get__(self, instance, owner): if hasattr(self, 'value'): return self.value return self class Spam: value1 = PositiveInteger() value2 = PositiveInteger() https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_02.ipynb >>> spam1 = Spam() >>> spam1.value1 = 10 >>> spam1.value2 = 20 >>> print(spam1.value1, spam1.value2) 10 20 >>> spam2 = Spam() >>> spam2.value1 = 100 >>> spam2.value2 = 200 >>> print( spam1.value1, spam1.value2, spam2.value1, spam2.value2) 100 200 100 200
  58. Πϯελϯε࡞Δͱ͖ʹΞαΠϯ͢Δͷͱಉ໊͡લΛ͚ͭΔ https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_03.ipynb class PositiveInteger: def __init__(self, name): self.name = name

    def __set__(self, instance, value): if type(value) is not int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") instance.__dict__[self.name] = value def __get__(self, instance, owner): if not instance: return self try: return instance.__dict__[self.name] except KeyError: raise AttributeError() class Spam: value1 = PositiveInteger("value1") value2 = PositiveInteger("value2") >>> spam1 = Spam() >>> spam1.value1 = 10 >>> spam1.value2 = 20 >>> spam2 = Spam() >>> spam2.value1 = 100 >>> spam2.value2 = 200 >>> print(spam1.value1, spam1.value2, spam2.value1, spam2.value2) 10 20 100 200
  59. Πϯελϯε࡞Δͱ͖ʹΞαΠϯ͢Δͷͱಉ໊͡લΛ͚ͭΔ https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_03.ipynb class PositiveInteger: def __init__(self, name): self.name = name

    def __set__(self, instance, value): if type(value) is not int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") instance.__dict__[self.name] = value def __get__(self, instance, owner): if not instance: return self try: return instance.__dict__[self.name] except KeyError: raise AttributeError() class Spam: value1 = PositiveInteger("value1") value2 = PositiveInteger("value2") >>> spam1 = Spam() >>> spam1.value1 = 10 >>> spam1.value2 = 20 >>> spam2 = Spam() >>> spam2.value1 = 100 >>> spam2.value2 = 200 >>> print(spam1.value1, spam1.value2, spam2.value1, spam2.value2) 10 20 100 200 value1 = PositiveInteger(“value1”) ᶃ ᶄ
  60. class ReusableDescriptor: def set_assigned_name(self, name): self.name = name class PositiveInteger(RecusableDescriptor):

    def __set__(self, instance, value): if type(value) is not int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") instance.__dict__[self.name] = value def __get__(self, instance, owner): if not instance: return self try: return instance.__dict__[self.name] except KeyError: raise AttributeError() class ReusableDescriptorMetaclass(type): def __new__(meta, name, bases, class_dict): for key, item in class_dict.items(): if isinstance(item, ReusableDescriptor): item.set_assigned_name(key) return type.__new__(meta, name, bases, class_dict) https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_metaclass_01.ipynb class Spam(metaclass=ReusableDescriptorMetaclass): value1 = PositiveInteger() value2 = PositiveInteger() >>> spam1 = Spam() >>> spam1.value1 = 10 >>> spam1.value2 = 20 >>> spam2 = Spam() >>> spam2.value1 = 100 >>> spam2.value2 = 200 >>> print( spam1.value1, spam1.value2, spam2.value1, spam2.value2) 10 20 100 200 MetaclassͰରԠ͢Δ໊લΛઃఆ͢Δ
  61. class ReusableDescriptor: def set_assigned_name(self, name): self.name = name class PositiveInteger(RecusableDescriptor):

    def __set__(self, instance, value): if type(value) is not int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") instance.__dict__[self.name] = value def __get__(self, instance, owner): if not instance: return self try: return instance.__dict__[self.name] except KeyError: raise AttributeError() class ReusableDescriptorMetaclass(type): def __new__(meta, name, bases, class_dict): for key, item in class_dict.items(): if isinstance(item, ReusableDescriptor): item.set_assigned_name(key) return type.__new__(meta, name, bases, class_dict) https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_metaclass_01.ipynb class Spam(metaclass=ReusableDescriptorMetaclass): value1 = PositiveInteger() value2 = PositiveInteger() >>> spam1 = Spam() >>> spam1.value1 = 10 >>> spam1.value2 = 20 >>> spam2 = Spam() >>> spam2.value1 = 100 >>> spam2.value2 = 200 >>> print( spam1.value1, spam1.value2, spam2.value1, spam2.value2) 10 20 100 200 MetaclassͰରԠ͢Δ໊લΛઃఆ͢Δ ←ׂΓ౰ͯΒΕͨม਺໊
  62. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_04.ipynb class SetGetNothingDescriptor: def __set__(self, instance, value): print("SetGetNothingDescriptor.__set__") def __get__(self,

    instance, owner): print("SetGetNothingDescriptor.__get__") return None class Spam: egg = SetGetNothingDescriptor() def __init__(self): self.ham = SetGetNothingDescriptor() >>> spam = Spam() >>> Spam.__dict__ 'egg': <__main__.SetGetNothingDescriptor at 0x106e09910>, … >>> spam.__dict__ {'ham': <__main__.SetGetNothingDescriptor at 0x106e097f0>} >>> spam.ham <__main__.SetGetNothingDescriptor at 0x106e097f0> >>> spam.ham = 'bacon' >>> spam.__dict__ {'ham': ‘bacon'} >>> spam.ham ‘bacon'
  63. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_04.ipynb class SetGetNothingDescriptor: def __set__(self, instance, value): print("SetGetNothingDescriptor.__set__") def __get__(self,

    instance, owner): print("SetGetNothingDescriptor.__get__") return None class Spam: egg = SetGetNothingDescriptor() def __init__(self): self.ham = SetGetNothingDescriptor() >>> spam = Spam() >>> Spam.__dict__ 'egg': <__main__.SetGetNothingDescriptor at 0x106e09910>, … >>> spam.__dict__ {'ham': <__main__.SetGetNothingDescriptor at 0x106e097f0>} >>> spam.ham <__main__.SetGetNothingDescriptor at 0x106e097f0> >>> spam.ham = 'bacon' >>> spam.__dict__ {'ham': ‘bacon'} >>> spam.ham ‘bacon' ← Πϯελϯεͷଐੑʹ
  64. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_05.ipynb class SetGetNothingDescriptor: def __set__(self, instance, value): print("SetGetNothingDescriptor.__set__") def __get__(self,

    instance, owner): print("SetGetNothingDescriptor.__get__") return None class Spam: egg = SetGetNothingDescriptor() >>> spam = Spam() >>> Spam.__dict__ 'egg': <__main__.SetGetNothingDescriptor at 0x107a2b910>, … >>> spam.__dict__ {} >>> spam.egg SetGetNothingDescriptor.__get__ >>> spam.egg = ‘ham' SetGetNothingDescriptor.__set__ >>> spam.__dict__ {} # Πϯελϯεଐੑʹ egg Λແཧ໼ཧ௥Ճͯ͠ΈΔ >>> spam.__dict__['egg'] = None >>> spam.__dict__ {'egg': None} >>> spam.egg SetGetNothingDescriptor.__get__ >>> spam.egg = 'ham' SetGetNothingDescriptor.__set__
  65. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_06.ipynb class SetNothingDescriptor: def __set__(self, instance, value): print("SetNothingDescriptor.__set__") class Spam:

    egg = SetNothingDescriptor() >>> spam = Spam() >>> Spam.__dict__ mappingproxy({'__module__': '__main__', 'egg': <__main__.SetNothingDescriptor at 0x104e11f70>, '__dict__': <attribute '__dict__' of 'Spam' objects>, '__weakref__': <attribute '__weakref__' of 'Spam' objects>, '__doc__': None}) >>> spam.__dict__ {} >>> spam.egg <__main__.SetNothingDescriptor at 0x104e11f70> >>> spam.egg = 'ham' SetNothingDescriptor.__set__ >>> spam.egg <__main__.SetNothingDescriptor at 0x104e11f70> >>> spam.__dict__['egg'] = 'ham' >>> spam.egg 'ham' >>> spam.egg = 'ham' SetNothingDescriptor.__set__ __set__ / __delete__ ͷ͍ͣΕ͔͕͋Δ৔߹͸ σʔλσΟεΫϦϓλ(data descriptor)
  66. https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_07.ipynb class GetNothingDescriptor: def __get__(self, instance, value): print("GetNothingDescriptor.__get__") class Spam:

    egg = GetNothingDescriptor() >>> spam = Spam() >>> spam.egg GetNothingDescriptor.__get__ >>> spam.egg = 'ham' >>> spam.__dict__ {'egg': 'ham'} >>> spam.egg 'ham' https://docs.python.org/ja/3/reference/datamodel.html#invoking-descriptors __set__ / __delete__ ͷ͍ͣΕ΋ແ͍৔߹͸ ඇσʔλσΟεΫϦϓλ(non-data descriptor)
  67. registry = {} def register(cls): registry[cls.__name__] = cls class AutoRegisterMeta(type):

    def __new__(cls, name, bases, class_dict): newclass = type.__new__(cls, name, bases, class_dict) register(newclass) return newclass class MyClassA(metaclass=AutoRegisterMeta): pass class MyClassB(metaclass=AutoRegisterMeta): pass >>> registry {'MyClassA': __main__.MyClassA, 'MyClassB': __main__.MyClassB} https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/05_subclasshook_01.ipynb
  68. μϯμʔset_name͕࣮͸͋Δɻmetaclassͷ༻్ͷ1͕ͭແ͘ͳͬͨɻ ࣮͸descriptorͱ͸ؔ܎ͳ͘ɺμϯμʔset_name͕͋Ε͹ݺ͹ΕΔ class PositiveInteger: def __set_name__(self, owner, name): self.name =

    name def __set__(self, instance, value): if type(value) is not int: raise ValueError(f"value should be int, but {value}") if value < 0: raise ValueError(f"value souldn't be negative") instance.__dict__[self.name] = value def __get__(self, instance, owner): if not instance: return self try: return instance.__dict__[self.name] except KeyError: raise AttributeError() class Spam: value1 = PositiveInteger() value2 = PositiveInteger() https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/04.descriptor_metaclass_02.ipynb >>> spam1 = Spam() >>> spam1.value1 = 10 >>> spam1.value2 = 20 >>> spam2 = Spam() >>> spam2.value1 = 100 >>> spam2.value2 = 200 >>> print(spam1.value1, spam1.value2, spam2.value1, spam2.value2) 10 20 100 200 __set_name__ (Python3.6͔Β)
  69. registry = {} def register(cls): registry[cls.__name__] = cls class RegisterBase:

    def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) register(cls) class MyClassA(RegisterBase): pass class MyClassB(RegisterBase): pass >>> registry {'MyClassA': __main__.MyClassA, 'MyClassB': __main__.MyClassB} __init_subclass__ https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/05_subclasshook_01.ipynb
  70. from abc import ABC, abstractmethod registry = {} def register(cls):

    registry[cls.__name__] = cls class AutoRegisterMeta(type): def __new__(cls, name, bases, class_dict): newclass = type.__new__(cls, name, bases, class_dict) register(newclass) return newclass class AbstractPlugin(ABC): @abstractmethod def run(self): pass class MyClassA(AbstractPlugin, metaclass=AutoRegisterMeta): def run(self): return f"return from {self.__class__.__name__}.run" --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-19-daaad246990d> in <module> 18 19 ---> 20 class MyClassA(AbstractPlugin, metaclass=AutoRegisterMeta): 21 def run(self): 22 return f"return from {self.__class__.__name__}.run" TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/06_metaclass_01.ipynb
  71. from abc import ABC, abstractmethod registry = {} def register(cls):

    registry[cls.__name__] = cls class RegisterBase: def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) register(cls) class AbstractPlugin(ABC): @abstractmethod def run(self): pass class MyClassA(AbstractPlugin, RegisterBase): def run(self): return f"return from {self.__class__.__name__}.run" class MyClassB(AbstractPlugin, RegisterBase): def run(self): return f"return from {self.__class__.__name__}.run" >>> registry {'MyClassA': __main__.MyClassA, 'MyClassB': __main__.MyClassB} >>> ma = MyClassA() >>> ma.run() 'return from MyClassA.run' https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/06_metaclass_02.ipynb
  72. from abc import ABC, ABCMeta, abstractmethod registry = {} def

    register(cls): registry[cls.__name__] = cls class AutoRegisterMeta(ABCMeta): def __new__(cls, name, bases, class_dict): newclass = super().__new__(cls, name, bases, class_dict) register(newclass) return newclass class AbstractPlugin(ABC): @abstractmethod def run(self): pass class MyClassA(AbstractPlugin, metaclass=AutoRegisterMeta): def run(self): return f"return from {self.__class__.__name__}.run" class MyClassB(AbstractPlugin, metaclass=AutoRegisterMeta): pass >>> registry {'MyClassA': __main__.MyClassA, 'MyClassB': __main__.MyClassB} >>> mb = MyClassB() --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-15-f914df2d7a56> in <module> ----> 1 mb = MyClassB() TypeError: Can't instantiate abstract class MyClassB with abstract methods run https://github.com/tsuyukimakoto/pyconjp2020/blob/master/notebook/06_metaclass_03.ipynb
  73. Djangoͷॅॴ࿥Ϟσϧ >>> Address.__dict__ mappingproxy({'__module__': 'address.models', '__doc__': 'Address(id, zipcode, prefecture, name,

    memo)', '_meta': <Options for Address>, 'DoesNotExist': address.models.Address.DoesNotExist, 'MultipleObjectsReturned': address.models.Address.MultipleObjectsReturned, 'zipcode': <django.db.models.query_utils.DeferredAttribute at 0x106706970>, 'prefecture_id': <django.db.models.fields.related_descriptors.ForeignKeyDeferredAttribute at 0x1068b1040>, 'prefecture': <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor at 0x1068b10a0>, 'name': <django.db.models.query_utils.DeferredAttribute at 0x1068b1190>, 'memo': <django.db.models.query_utils.DeferredAttribute at 0x1068b11f0>, 'id': <django.db.models.query_utils.DeferredAttribute at 0x1068b1310>, 'objects': <django.db.models.manager.ManagerDescriptor at 0x1068b1250>}) ϞσϧΫϥεͷ __dict__ ← models.CharFieldͰ͸ͳ͘ͳͬͯΔ ϙΠϯτ class Address(models.Model): zipcode = models.CharField(max_length=7) prefecture = models.ForeignKey(Prefecture, on_delete=models.PROTECT) name = models.CharField(max_length=25) memo = models.TextField(blank=True)
  74. >>> del address.zipcode >>> address.zipcode '2480012' ← delͨ͠͸ͣͳͷʹɺΞΫηεͨ͠Β஋͕໭͖ͬͯͨ ϙΠϯτ Djangoͷॅॴ࿥Ϟσϧ

    >>> address.__dict__ {'_state': <django.db.models.base.ModelState at 0x107956220>, 'id': 1, 'zipcode': '2480012', 'prefecture_id': 14, 'name': 'ח૔ࢢ໾ॴ', 'memo': ''}
  75. • @everes follow me on twitter • גࣜձࣾσΟʔɾΤψɾΤʔ γεςϜຊ෦CTOࣨ •

    ύʔϑΣΫτPythonʦվగ2൛ʧग़ͯ·͢ ͓·͑୭Αʁ πϢΩϚίτ https://amzn.to/2zaJIiV
  76. • @everes follow me on twitter • גࣜձࣾσΟʔɾΤψɾΤʔ γεςϜຊ෦CTOࣨ •

    ύʔϑΣΫτPythonʦվగ2൛ʧग़ͯ·͢ ͓·͑୭Αʁ πϢΩϚίτ https://amzn.to/2zaJIiV ͑͏ʃ͊͞Μ ͬͯݺΜͰͶʂ