Interface: abstract base class from protocol to.
In this chapter, we do not know the translation problem, or my ability, to see not really understand, can simply record your own understanding. After some time to return to read.
First informal protocol interface, each class (except abstract base class), both interfaces.
Protected property and private property is not in the interface.
The interface is a subset of the object of the disclosed method, so that objects play a particular role in the system
Interface is the way to achieve a specific set of roles, there is no agreement with the inheritance relationship, a class may implement multiple interfaces, thereby playing of roles.
Protocol sequence is one of the most basic Python agreement.
In [29]: from collections.abc import Sequence In [30]: class Foo: ...: def __getitem__(self, pos): ...: return range(0, 30, 10)[pos] ...: In [31]: f = Foo() In [32]: f[1] Out[32]: 10 In [33]: for i in f:print(i) 0 10 20 In [34]: 20 in f Out[34]: True In [35]: isinstance(f, Sequence) Out[35]: False In [36]:
__Getitem__ achieve the above definition of the part of the sequence of the agreement, it is clear that it is not a subclass of the Sequence, although there is no __iter__ and __Container__ but still be for the cycle call, and can be used in
In [35]: isinstance(f, Sequence) Out[35]: False In [36]: from collections import Iterable /usr/local/bin/ipython:1: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working #!/usr/local/opt/python/bin/python3.7 In [37]: isinstance(f, Iterable) Out[37]: False
I remember the teacher said, could be for the cycle call is iterable, obviously, f can be for the cycle call, but not iterables, or have strict __iter__ is the iterable.
11.3 Use monkey pudding implement the protocol.
Monkey patch before to find out about it, we will know the name, now the book is very detailed introduction, but also practical use.
Examples of the object is not initially have this property, by adding its class instance attribute, then it is with this method, generally less.
The In [46 is]: Import Collections ...: ...: Card collections.namedtuple = ( 'Card', 'Rank SUIT') ...: ...: class Frenchdeck: ...: ranks = [STR ( n) for n in range (2 , 11)] + list ( 'JQKA') # card numbers and the color assigned to the class attribute ...: ...: suits = 'SPADES hearts'.split Diamonds Clubs () ...: ...: DEF __init __ (Self): # generate a list of style production with a deck of cards ...: self._cards = [card (Rank, SUIT) for Rank in self.ranks ...: for SUIT self.suits in] ...: ...: DEF __len __ (Self): ...: return len (self._cards) ...: ...: def __getitem __ (self, item): # define the [] value will be used. ...: return self._cards [Item] ...: ...: DEF __repr __ (Self): ...: F return 'R & lt self._cards {!}' ...: the In [47]: Desk = Frenchdeck () the In [48]: Desk [:. 5] Out [48]: [Card (Rank = '2', SUIT = 'SPADES'), Card (Rank = '2', SUIT = 'Diamonds'), Card (Rank = '2', SUIT = 'Clubs'), Card (Rank = '2', SUIT = 'hearts'), In [49]: shuffle(desk) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-49-1b00429a849a> in <module> ----> 1 shuffle(desk) /usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/random.py in shuffle(self, x, random) 276 # pick an element in x[:i+1] with which to exchange x[i] 277 j = randbelow(i+1) --> 278 x[i], x[j] = x[j], x[i] 279 else: 280 _int = int TypeError: 'Frenchdeck' object does not support item assignment In [50]: def set_card(deck, position, card): ...: deck._cards[position] = card ...: ...: In [51]: Frenchdeck.__setitem__ = set_card In [52]: shuffle(desk) In [53]: desk[:5] Out[53]: [Card(rank='Q', suit='clubs'), Card(rank='4', suit='diamonds'), Card(rank='10', suit='hearts'), Card(rank='9', suit='spades'), Card(rank='5', suit='diamonds')]
Monkeys pudding by adding cards to the first chapter, the front __setitem__ lack of attributes, shuffle can not be used for alignment, implements the protocol part of the variable sequence either by adding __setitem__ behind the object.
So-called duck typing is no need to focus on specific types of objects, as long as the realization of a specific agreement either, no inheritance.
Subclass of an abstract base class defines 11.5
In [54]: from collections.abc import MutableSequence In [55]: class Mu(MutableSequence): ...: ... ...: In [56]: mu = Mu() --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-56-c234f3d4f57f> in <module> ----> 1 mu = Mu() TypeError: Can't instantiate abstract class Mu with abstract methods __delitem__, __getitem__, __len__, __setitem__, insert
There are 16 collections.abc abstract base class, where I inherited MutableSequence, it can be seen from the given __delitem__, __getitem__, __len__, __setitem__, insert, belonging to the abstract methods must be redefined subclass.
According to the book inherit MutalbeSquence FranchDeck
collections.abc Import Card collections.namedtuple = ( 'Card', 'Rank SUIT') class Frenchdeck2 (collections.abc.MutableSequence): ranks = [STR (n-) for n-in Range (2,. 11)] + List ( ' JQKA ') # card numbers and the color assigned to the class attribute suits =' SPADES hearts'.split Diamonds Clubs () DEF the __init __ (Self): # create a formula with a list of cards self._cards = [card (rank, SUIT) for Rank in self.ranks for SUIT in self.suits] DEF __len __ (Self): method # abstract class inheritance return len (self._cards) DEF the __getitem __ (Self, Item): # define the [] values will used. return self._cards [item] # abstract methods inherited class def __delitem __ (self, key) : Method # abstract class inheritance del self._cards [key] def __setitem __ (self, key, value): Method # abstract class inheritance self._cards [Key] = value DEF INSERT (Self, index: int, value) -: Method # abstract class inheritance> None self._cards.insert (index, value) DEF __repr __ (Self): return F 'R & lt self._cards {!}' IF the __name__ == '__main__': Deck = Frenchdeck2 () deck.insert (0,. 1)
All the abstract methods are defined, whatever you do not have to.
At the same time some of your abstract class method MutableSequence is also a process, such as remove, pop, extend, __ iadd__
In [78]: deck[0] Out[78]: 1 In [79]: deck.pop() Out[79]: Card(rank='A', suit='hearts') In [80]: deck.pop() Out[80]: Card(rank='A', suit='clubs') In [81]: deck.extend('123') In [82]: deck.remove('2')
collections.abc16 a base class and I am more interested in is the Callable Hashable is to test whether the object can be called hash.
In [83]: from collections.abc import Callable, Hashable In [84]: isinstance(print, Callable) Out[84]: True In [85]: isinstance(print, Hashable) Out[85]: True In [86]: isinstance(list, Hashable) Out[86]: True In [87]: isinstance(list(), Hashable) Out[87]: False In [88]: callable(list) Out[88]: True In [89]:
Abstract base class Callable callable function with the same effect, Hashable only tested with this abstract class.
11.6.2 digital abstract base class column
numbers of packages
The official explanation link:
https://docs.python.org/zh-cn/3.7/library/numbers.html#numbers.Rational.numerator
Number
Complex
Real
The Rational (subclass is Intergal)
Integral
In [103]: from numbers import Integral In [104]: isinstance(1,Integral) Out[104]: True In [105]: from fractions import Fraction In [106]: f = Fraction(3,4) In [107]: isinstance(f,Integral) Out[107]: False In [108]: from numbers import Rational In [109]: isinstance(f,Integral) Out[109]: False In [110]: isinstance(f,Rational) Out[110]: True In [111]:
Examples include Integral int, bool (int subclass)
Rational fraction containing more
11.7 and using the definition of an abstract base class.
In order to better learn abstract base class, the book defines an abstract base class, and inherits two subclasses, a virtual sub-columns.
abc Import class Tombila (abc.ABC): @ abc.abstractmethod DEF the Load (Self, Iterable): "" "add elements from iterable" "" @ abc.abstractmethod DEF Pick (Self): Print (of the type (Self) name__ + .__ 'iS Working Pick') "" "randomly delete elements and returns if the instance is null, this method throws" LookupError " " "" DEF loaded (Self): "" "If there is at least one element, returns True, otherwise False "" " return BOOL (self.inspect ()) DEF Inspect (Self): " "" returns a sorted tuples constituting a current element "" " items = [] the while True: the try: items.append(self.pick()) except LookupError: break self.load (items) # returns the read return tuple (sorted (items))
The above is an abstract class, I defined some of the features inside the pick, when you can still call inherited by super.
11.7.1 Syntax Interpretation abstract base class.
After Python3.4 can do, it is written above the direct successor abc.ABC it.
Before 3.4
class Demo(metaclass=abc.ABCMeta): ...
Python2 write:
class Demo(object): __metaclass__ = abc.ABCMeta
Before Python3.3 are:
@abc.abstractclassmethod @abc.abstractproperty @abc.abstractstaticmethod
In the new do not, according to the principle of multi-layer decorator, you just put @ AbstractMethod on the innermost layer, you need to write on the top decoration, the same can be inherited by subclasses.
11.7.2 subclassing Tombola abstract base class.
First pumping line on the base class:
abc Import class Tombila (abc.ABC): @ abc.abstractmethod DEF the Load (Self, Iterable): "" "add elements from iterable" "" @ abc.abstractmethod DEF Pick (Self): Print (of the type (Self) name__ + .__ 'iS Working Pick') "" "randomly delete elements and returns if the instance is null, this method throws" LookupError " " "" DEF loaded (Self): "" "If there is at least one element, returns True, otherwise False "" " return BOOL (self.inspect ()) DEF Inspect (Self): " "" returns a sorted tuples constituting a current element "" " items = [] the while True: the try: items.append(self.pick()) except LookupError: break self.load(items) # 返回读取 return tuple(sorted(items)) if __name__ == '__main__': print(dir(Tombila))
The following functions are used to achieve this succession of three ways.
The first change happened, two base class methods are inherited, the second change to understand more, the base class methods are changed, the third virtual direct subclass does not inherit any base class methods.
Binggo # Import Random from Tombola Import Tombila class BingoCage (Tombila): DEF the __init __ (Self, Item): self._randomizer = random.SystemRandom () self._items = [] self.load (Item) # call the load method to achieve initialization the Load DEF (Self, Iterable): self._items.extend (Iterable) self._randomizer.shuffle (self._items) DEF Pick (Self): the try: return self._items.pop () the except IndexError: # no data can pop up error, receiving IndexError, error reporting Look the raise LookupError ( 'empty BingoCage from Pick') DEF the __call __ (Self, args *, ** kwargs): # object becomes callable return self.pick () # book did not return, I added, otherwise the implementation of the object does not return a value IF __name__ == '__main__': Bingo = BingoCage (the Range (10)) Print (Bingo ()) Print (Bingo .inspect ())
/usr/local/bin/python3.7 / Users / shijianzhong / study / Fluent_Python / XI /bingo.py . 6 (0,. 1, 2,. 3,. 4,. 5,. 7,. 8,. 9) Process Finished with exit code 0
The second Inheritance:
Random Import from Tombola Import Tombila class LotteryBlower (Tombila): DEF the __init __ (Self, Iterable): self._balls = List (Iterable) DEF Load (Self, Iterable): self._balls.extend (Iterable) DEF Pick (Self): the try: position = random.randrange (len (self._balls)) # internal random numbers selected from a return self._balls.pop (position) the except a ValueError: # If len which is 0, a ValueError: empty for randrange Range () The raise LookupError ( 'pick from empty LotteryBlower') # front crawl error return error required DEF loaded (Self): return BOOL (self._balls) DEF Inspect (Self): return tuple (the sorted (self._balls)) if __name__ == '__main__': lottery = LotteryBlower(range(10)) print(lottery.pick()) print(lottery.inspect())
/usr/local/bin/python3.7 / Users / shijianzhong / study / Fluent_Python / XI /lotto.py . 4 (0,. 1, 2,. 3,. 4,. 5,. 6,. 7,. 8,. 9) Process finished with exit code 0
11.7.3 Tombola virtual subclass
Virtual subclass does not inherit the abstract base class registration, in other words, direct point, is the virtual sub-class with an abstract base class that was nothing to do.
You can not inherit or modify the abstract methods abstract base class, but in order to avoid operational errors, did not inherit it, so all the base class methods should rewrite it.
First on an extreme example does not inherit any base class.
from random import randrange from tombola import Tombila class A: ... Tombila.register(A) a = A() print(isinstance(a, Tombila)) print(issubclass(A, Tombila))
/usr/local/bin/python3.7 /Users/shijianzhong/study/Fluent_Python/第十一章/tombolist.py True True Process finished with exit code 0
You can see the code, the effect of virtual subclasses.
This is the code of the book:
Random Import randrange from from Tombola Import Tombila @ Tombila.register class TomboList (List): DEF Pick (Self): # Self is the list itself IF Self: position = randrange (len (Self)) return self.pop (position) the else : The raise LookupError ( 'empty Tombolist from POP') Load = Load # list.extend equal list.extend direct method DEF Loader (Self): return BOOL (Self) DEF Inspect (Self): return tuple (the sorted (Self)) # Tombila.register (TomboList) which is written before Python3.3 IF the __name__ == '__main__': Tombo = TomboList (Range (10)) Print (tombo.pick ()) Print (tombo.inspect ()) print(tombo.load(range(3))) # 等同与tombo.extend(range(3)) print(tombo.inspect()) print(TomboList.__mro__)
/usr/local/bin/python3.7 /Users/shijianzhong/study/Fluent_Python/第十一章/tombolist.py 1 (0, 2, 3, 4, 5, 6, 7, 8, 9) None (0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9) (<class '__main__.TomboList'>, <class 'list'>, <class 'object'>) Process finished with exit code 0
Can be seen, there is no longer seen __mro__ base class Tombila.
I then thought for a moment, and if the base class method does not list the same name (originally did not), you can double inheritance.
Random Import randrange from from Tombola Import Tombila class TomboList (Tombila, List): DEF Pick (Self): # Self is the list itself IF Self: position = randrange (len (Self)) return self.pop (position) the else: The raise LookupError ( 'empty Tombolist from POP') Load = Load # list.extend equal list.extend direct method DEF Loader (Self): return BOOL (Self) DEF Inspect (Self): return tuple (the sorted (Self)) # Tombila. register (TomboList) which is written before Python3.3 IF the __name__ == '__main__': Tombo = TomboList (Range (10)) Print (tombo.pick ()) Print (tombo.inspect ()) print(tombo.load(range(3))) # 等同与tombo.extend(range(3)) print(tombo.inspect()) print(TomboList.__mro__)
/usr/local/bin/python3.7 /Users/shijianzhong/study/Fluent_Python/第十一章/tombolist_1.py 9 (0, 1, 2, 3, 4, 5, 6, 7, 8) None (0, 0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 8) (<class '__main__.TomboList'>, <class 'tombola.Tombila'>, <class 'abc.ABC'>, <class 'list'>, <class 'object'>) Process finished with exit code 0
Such a method is not, but the back of the book describes a virtual base class, some uses Python.
11.8 Tombola subclass test methods.
Doctest test module, and how I did not used, so I do not write, including the search for a useful virtual subclass code.
Tombila._abc_registry
but I fail, no error this property.
11.9 Python using the register of the way.
Python will tuple, str, range, memoryview registered as a virtual sub-categories.
Squence.regiser(tuple)
....
This dictionary includes also registered to MutableMapple
MutableMapple.register(dict)
11.10 by the goose's behavior might like a duck
class Sruggle: def __len__(self): return 23 print(issubclass(Sruggle, Sized)) print(Sized.__subclasscheck__(Sruggle))
Returns are true
Virtual subclass of this Sruggle not SIzed, but can not be a subclass.
But because Sized special __subclasscheck__ class.
Here I transcribe in accordance with the above code Sized original code:
import abc class Sized(abc.ABC): __slots__ = () @abc.abstractmethod def __len__(self): return 0 @classmethod def __subclasshook__(cls, C): if cls is Sized: if any("__len__" in B.__dict__ for B in C._mro__): return True return NotImplemented
The book describes the principle issubclass no run, I think if there is __subclasshook__ priority should be to call the class method.
But generally __subclasshook__ with very little chance of their own with even less.