def test_add(): a = spam.Spam(1) b = spam.Spam(2) c = a + b assert c.v == 3 with pytest.raises(TypeError): a + "spam"
def test_spam_send_value(): seq = ('spam', 'ham', 'eggs') value = 'spamspamspam' ins = spam.Spam(seq, value) co = spam_await(ins) assert co.send(None) == seq[0] assert co.send(2) == seq[1] * 2
def test_spam_throw(): seq = ('spam', 'ham', 'eggs') value = 'spamspamspam' ins = spam.Spam(seq, value) co = spam_await(ins) assert co.send(None) == seq[0] assert co.throw(ValueError) == seq[1] with pytest.raises(Exception) as exc_info: co.throw(Exception, 'err') assert exc_info.value.args[0] == 'err'
def test_spam(): a = spam.Spam(3) assert a.spam('spam') == 'spamspamspam' a.multiplier = 5 assert a.spam('spam') == 'spamspamspamspamspam' a.multiplier = 'spam' with pytest.raises(TypeError): a.spam('spam')
def test_spam(): seq = ('spam', 'ham', 'eggs') value = 'spamspamspam' ins = spam.Spam(seq, value) assert seq is ins.seq assert value is ins.value co = spam_await(ins) assert co.send(None) == seq[0] assert co.send(None) == seq[1] assert co.send(None) == seq[2] with pytest.raises(StopIteration) as exc_info: co.send(None) assert exc_info.value.value == value
def test_bufferproc(): b = b'a' s = spam.Spam(b) assert s.export_count == 0 v = memoryview(s) assert s.export_count == 1 assert v.tobytes() == b assert s.b == v[0] == b[0] assert spam.use_readonly_buffer(s) == b[0] s.b += 1 assert s.b == v[0] == b[0] + 1 v[0] += 1 assert s.b == v[0] == b[0] + 2 spam.use_writable_buffer(s) assert s.b == v[0] == b[0] + 3
def test_iterator_cls(): iterable = spam.Spam(b'spam') iterator = iter(iterable) assert iterator assert list(iterator) == list(b'spam')
# 정적 메서드의 대안 def printNumInstances(): print("Number of instances created: %s" % Spam.numInstances) class Spam: numInstances = 0 def __init__(self): Spam.numInstances = Spam.numInstances + 1 # py -3 import spam a = spam.Spam() b = spam.Spam() c = spam.Spam() spam.printNumInstances() # 하지만 함수는 극단적으로 제거될 수 있음 # Number of instances created: 3 # 그리고 상속에 의해 변경될 수 없음 spam.Spam.numInstances # 3 class Spam: numInstances = 0 def __init__(self): Spam.numInstances = Spam.numInstances + 1 def printNumInstances(self): print("Number of instances created: %s" % Spam.numInstances) # py -3 from spam import Spam
def test_undefined_protocol(): a = spam.Spam(1) b = spam.Spam(2) with pytest.raises(TypeError): c = a - b
# Test various properties of classes defined in separate modules print("Testing the %import directive") import base import foo import bar import spam # Create some objects print("Creating some objects") a = base.Base() b = foo.Foo() c = bar.Bar() d = spam.Spam() # Try calling some methods print("Testing some methods") print("", end=' ') print("Should see 'Base::A' ---> ", end=' ') a.A() print("Should see 'Base::B' ---> ", end=' ') a.B() print("Should see 'Foo::A' ---> ", end=' ') b.A() print("Should see 'Foo::B' ---> ", end=' ') b.B() print("Should see 'Bar::A' ---> ", end=' ')
print() status = spam.system("ls -l | wc") print("status: ", status) print() print('Expect spam.SpamError') try: status = spam.check_system("false") print("status: ", status) except spam.SpamError as ex: print(' ', ex) print(' ignored') print() s = spam.Spam("Real brand of SPAM") s.print() print(s) print() n1 = spam.Noddy1() print(n1) print() n2 = spam.Noddy2(first="Mike", last="Bentley") print(n2) print("Name: ", n2.name()) print() n2 = spam.Noddy2(first=2) print(n2)
>>> class E: ... __slots__ = ['c', 'd'] # Superclass has slots ... >>> class D(E): ... __slots__ = ['a', '__dict__'] # So does its subclass ... >>> X = D() >>> X.a = 1; X.b = 2; X.c = 3 # The instance is the union >>> X.a, X.c (1, 3) >>> E.__slots__ # But slots are not concatenated ['c', 'd'] >>> D.__slots__ ['a', '__dict__'] >>> X.__slots__ # Instance inherits *lowest* __slots__ ['a', '__dict__'] >>> X.__dict__ # And has its own an attr dict {'b': 2} >>> for attr in list(getattr(X, '__dict__', [])) + getattr(X, '__slots__', []): ... print(attr, '=>', getattr(X, attr)) ... b => 2 # Superclass slots missed! a => 1 __dict__ => {'b': 2} >>> dir(X) # dir() includes all slot names [...many names omitted... 'a', 'b', 'c', 'd'] >>> class classic: ... def __getattr__(self, name): ... if name == 'age': ... return 40 ... else: ... raise AttributeError ... >>> x = classic() >>> x.age # Runs __getattr__ 40 >>> x.name # Runs __getattr__ AttributeError >>> class newprops(object): ... def getage(self): ... return 40 ... age = property(getage, None, None, None) # get, set, del, docs ... >>> x = newprops() >>> x.age # Runs getage 40 >>> x.name # Normal fetch AttributeError: newprops instance has no attribute 'name' >>> class newprops(object): ... def getage(self): ... return 40 ... def setage(self, value): ... print('set age:', value) ... self._age = value ... age = property(getage, setage, None, None) ... >>> x = newprops() >>> x.age # Runs getage 40 >>> x.age = 42 # Runs setage set age: 42 >>> x._age # Normal fetch; no getage call 42 >>> x.job = 'trainer' # Normal assign; no setage call >>> x.job # Normal fetch; no getage call 'trainer' >>> class classic: ... def __getattr__(self, name): # On undefined reference ... if name == 'age': ... return 40 ... else: ... raise AttributeError ... def __setattr__(self, name, value): # On all assignments ... print('set:', name, value) ... if name == 'age': ... self.__dict__['_age'] = value ... else: ... self.__dict__[name] = value ... >>> x = classic() >>> x.age # Runs __getattr__ 40 >>> x.age = 41 # Runs __setattr__ set: age 41 >>> x._age # Defined: no __getattr__ call 41 >>> x.job = 'trainer' # Runs __setattr__ again >>> x.job # Defined: no __getattr__ call ### file: spam.py class Spam: numInstances = 0 def __init__(self): Spam.numInstances = Spam.numInstances + 1 def printNumInstances(): print("Number of instances created: ", Spam.numInstances) C:\misc> c:\python26\python >>> from spam import Spam >>> a = Spam() # Cannot call unbound class methods in 2.6 >>> b = Spam() # Methods expect a self object by default >>> c = Spam() >>> Spam.printNumInstances() TypeError: unbound method printNumInstances() must be called with Spam instance as first argument (got nothing instead) >>> a.printNumInstances() TypeError: printNumInstances() takes no arguments (1 given) C:\misc> c:\python30\python >>> from spam import Spam >>> a = Spam() # Can call functions in class in 3.0 >>> b = Spam() # Calls through instances still pass a self >>> c = Spam() >>> Spam.printNumInstances() # Differs in 3.0 Number of instances created: 3 >>> a.printNumInstances() TypeError: printNumInstances() takes no arguments (1 given) Spam.printNumInstances() # Fails in 2.6, works in 3.0 instance.printNumInstances() # Fails in both 2.6 and 3.0 ### file spam.py (changed) def printNumInstances(): print("Number of instances created: ", Spam.numInstances) class Spam: numInstances = 0 def __init__(self): Spam.numInstances = Spam.numInstances + 1 >>> import spam >>> a = spam.Spam() >>> b = spam.Spam() >>> c = spam.Spam() >>> spam.printNumInstances() # But function may be too far removed Number of instances created: 3 # And cannot be changed via inheritance >>> spam.Spam.numInstances 3 class Spam: numInstances = 0 def __init__(self): Spam.numInstances = Spam.numInstances + 1 def printNumInstances(self): print("Number of instances created: ", Spam.numInstances) >>> from spam import Spam >>> a, b, c = Spam(), Spam(), Spam() >>> a.printNumInstances() Number of instances created: 3 >>> Spam.printNumInstances(a) Number of instances created: 3 >>> Spam().printNumInstances() # But fetching counter changes counter! Number of instances created: 4 class Methods: def imeth(self, x): # Normal instance method: passed a self print(self, x) def smeth(x): # Static: no instance passed print(x) def cmeth(cls, x): # Class: gets class, not instance print(cls, x) smeth = staticmethod(smeth) # Make smeth a static method cmeth = classmethod(cmeth) # Make cmeth a class method >>> obj = Methods() # Make an instance >>> obj.imeth(1) # Normal method, call through instance <__main__.Methods object...> 1 # Becomes imeth(obj, 1) >>> Methods.imeth(obj, 2) # Normal method, call through class <__main__.Methods object...> 2 # Instance passed explicitly >>> Methods.smeth(3) # Static method, call through class 3 # No instance passed or expected >>> obj.smeth(4) # Static method, call through instance 4 # Instance not passed >>> Methods.cmeth(5) # Class method, call through class <class '__main__.Methods'> 5 # Becomes cmeth(Methods, 5) >>> obj.cmeth(6) # Class method, call through instance <class '__main__.Methods'> 6 # Becomes cmeth(Methods, 6) class Spam: numInstances = 0 # Use static method for class data def __init__(self): Spam.numInstances += 1 def printNumInstances(): print("Number of instances:", Spam.numInstances) printNumInstances = staticmethod(printNumInstances) >>> a = Spam() >>> b = Spam() >>> c = Spam() >>> Spam.printNumInstances() # Call as simple function Number of instances: 3 >>> a.printNumInstances() # Instance argument not passed Number of instances: 3 class Sub(Spam): def printNumInstances(): # Override a static method print("Extra stuff...") # But call back to original Spam.printNumInstances() printNumInstances = staticmethod(printNumInstances) >>> a = Sub() >>> b = Sub() >>> a.printNumInstances() # Call from subclass instance Extra stuff... Number of instances: 2 >>> Sub.printNumInstances() # Call from subclass itself Extra stuff... Number of instances: 2 >>> Spam.printNumInstances() Number of instances: 2 >>> class Other(Spam): pass # Inherit static method verbatim >>> c = Other() >>> c.printNumInstances() Number of instances: 3 class Spam: numInstances = 0 # Use class method instead of static def __init__(self): Spam.numInstances += 1 def printNumInstances(cls): print("Number of instances:", cls.numInstances) printNumInstances = classmethod(printNumInstances) >>> a, b = Spam(), Spam() >>> a.printNumInstances() # Passes class to first argument Number of instances: 2 >>> Spam.printNumInstances() # Also passes class to first argument Number of instances: 2 class Spam: numInstances = 0 # Trace class passed in def __init__(self): Spam.numInstances += 1 def printNumInstances(cls): print("Number of instances:", cls.numInstances, cls) printNumInstances = classmethod(printNumInstances) class Sub(Spam): def printNumInstances(cls): # Override a class method print("Extra stuff...", cls) # But call back to original Spam.printNumInstances() printNumInstances = classmethod(printNumInstances) class Other(Spam): pass # Inherit class method verbatim >>> x, y = Sub(), Spam() >>> x.printNumInstances() # Call from subclass instance Extra stuff... <class 'test.Sub'> Number of instances: 2 <class 'test.Spam'> >>> Sub.printNumInstances() # Call from subclass itself Extra stuff... <class 'test.Sub'> Number of instances: 2 <class 'test.Spam'> >>> y.printNumInstances() Number of instances: 2 <class 'test.Spam'> >>> z = Other() >>> z.printNumInstances() Number of instances: 3 <class 'test.Other'> class Spam: numInstances = 0 def count(cls): # Per-class instance counters cls.numInstances += 1 # cls is lowest class above instance def __init__(self): self.count() # Passes self.__class__ to count count = classmethod(count) class Sub(Spam): numInstances = 0 def __init__(self): # Redefines __init__ Spam.__init__(self) class Other(Spam): # Inherits __init__ numInstances = 0 >>> x = Spam() >>> y1, y2 = Sub(), Sub() >>> z1, z2, z3 = Other(), Other(), Other() >>> x.numInstances, y1.numInstances, z1.numInstances (1, 2, 3) >>> Spam.numInstances, Sub.numInstances, Other.numInstances (1, 2, 3) class C: @staticmethod # Decoration syntax def meth(): ... class C: def meth(): ... meth = staticmethod(meth) # Rebind name class Spam: numInstances = 0 def __init__(self): Spam.numInstances = Spam.numInstances + 1 @staticmethod def printNumInstances(): print("Number of instances created: ", Spam.numInstances) a = Spam() b = Spam() c = Spam() Spam.printNumInstances() # Calls from both classes and instances work now! a.printNumInstances() # Both print "Number of instances created: 3" class tracer: def __init__(self, func): self.calls = 0 self.func = func def __call__(self, *args): self.calls += 1 print('call %s to %s' % (self.calls, self.func.__name__)) self.func(*args) @tracer # Same as spam = tracer(spam) def spam(a, b, c): # Wrap spam in a decorator object print(a, b, c) spam(1, 2, 3) # Really calls the tracer wrapper object spam('a', 'b', 'c') # Invokes __call__ in class spam(4, 5, 6) # __call__ adds logic and runs original object def decorator(aClass): ... @decorator class C: ... def decorator(aClass): ... class C: ... C = decorator(C) def count(aClass): aClass.numInstances = 0 return aClass # Return class itself, instead of a wrapper @count class Spam: ... # Same as Spam = count(Spam) @count class Sub(Spam): ... # numInstances = 0 not needed here @count class Other(Spam): ... class Meta(type): def __new__(meta, classname, supers, classdict): ... class C(metaclass=Meta): ... class C: __metaclass__ = Meta ... >>> class X: ... a = 1 # Class attribute ... >>> I = X() >>> I.a # Inherited by instance 1 >>> X.a 1 >>> X.a = 2 # May change more than X >>> I.a # I changes too 2 >>> J = X() # J inherits from X's runtime values >>> J.a # (but assigning to J.a changes a in J, not X or I) 2 class X: pass # Make a few attribute namespaces class Y: pass X.a = 1 # Use class attributes as variables X.b = 2 # No instances anywhere to be found X.c = 3 Y.a = X.a + X.b + X.c for X.i in range(Y.a): print(X.i) # Prints 0..5 class Record: pass X = Record() X.name = 'bob' X.job = 'Pizza maker' >>> class C: ... shared = [] # Class attribute ... def __init__(self): ... self.perobj = [] # Instance attribute ... >>> x = C() # Two instances >>> y = C() # Implicitly share class attrs >>> y.shared, y.perobj ([], []) >>> x.shared.append('spam') # Impacts y's view too! >>> x.perobj.append('spam') # Impacts x's data only >>> x.shared, x.perobj (['spam'], ['spam']) >>> y.shared, y.perobj # y sees change made through x (['spam'], []) >>> C.shared # Stored on class and shared ['spam'] x.shared.append('spam') # Changes shared object attached to class in-place x.shared = 'spam' # Changed or creates instance attribute attached to x class ListTree: def __str__(self): ... class Super: def __str__(self): ... class Sub(ListTree, Super): # Get ListTree's __str__ by listing it first x = Sub() # Inheritance searches ListTree before Super class ListTree: def __str__(self): ... def other(self): ... class Super: def __str__(self): ... def other(self): ... class Sub(ListTree, Super): # Get ListTree's __str__ by listing it first other = Super.other # But explicitly pick Super's version of other def __init__(self): ... x = Sub() # Inheritance searches Sub before ListTree/Super class Sub(Super, ListTree): # Get Super's other by order __str__ = Lister.__str__ # Explicitly pick Lister.__str__ def generate(): # Fails prior to Python 2.2, works later class Spam: count = 1 def method(self): # Name Spam not visible: print(Spam.count) # not local (def), global (module), built-in return Spam() generate().method() C:\python\examples> python nester.py ...error text omitted... Print(Spam.count) # Not local (def), global (module), built-in NameError: Spam def generate(): global Spam # Force Spam to module scope class Spam: count = 1 def method(self): print(Spam.count) # Works: in global (enclosing module) return Spam() generate().method() # Prints 1 def generate(): return Spam() class Spam: # Define at top level of module count = 1 def method(self): print(Spam.count) # Works: in global (enclosing module) generate().method() def generate(): class Spam: count = 1 def method(self): print(self.__class__.count) # Works: qualify to get class return Spam() generate().method() ### lab code class Lunch: def __init__(self) # Make/embed Customer and Employee def order(self, foodName) # Start a Customer order simulation def result(self) # Ask the Customer what Food it has
def test_del(): a = spam.Spam(3) del a.multiplier with pytest.raises(AttributeError): a.spam('spam')