1.常用的魔术方法
class DictC:
def __setitem__(self, key, value):
"""当通过字典方式赋值是调用, 比如a["abc"]=1"""
print("__setitem__")
# self.key = value # 这种方式会调用__setattr__方法
self.__dict__[key] = value
def __getitem__(self, item):
"""当通过字典方式取值时调用, 比如a["abc"]"""
print(getattr(self, item))
return self.__dict__[item]
if __name__ == '__main__':
d = DictC()
d["a"] = 1
print(d["a"])
class SkipIterator:
def __init__(self, wrapped):
self.wrapped = wrapped
self.offset = 0
def __next__(self):
"""调用next方法时调用"""
if self.offset >= len(self.wrapped):
raise StopIteration
else:
item = self.wrapped[self.offset]
self.offset += 2
return item
class SkipObject:
def __init__(self, wrapped):
self.wrapped = wrapped
def __iter__(self):
return SkipIterator(self.wrapped)
# if __name__ == '__main__':
# skiper = SkipObject("abcdef")
# I = iter(skiper)
# print(next(I))
# print(next(I))
# print(next(I))
# for x in skiper:
# for y in skiper:
# print(x + y, end=" ")
class Iters:
def __init__(self, value):
self.data = value
def __getitem__(self, item):
"""当不存在__iter__方法时调用, 优先级__contains__ > __iter__ > __getitem__"""
print("get[%s] :" % item, end=" ")
return self.data[item]
def __iter__(self):
"""当调用iter方法时, 返回一个可迭代对象, 之后调用__next__方法遍历元素"""
print("iter =>", end=" ")
self.ix = 0
return self
def __next__(self):
"""当调用next方法时执行, for循环自动调用__next__方法"""
print("next:", end=" ")
if self.ix == len(self.data): raise StopIteration
item = self.data[self.ix]
self.ix += 1
return item
# def __contains__(self, item):
# print("contains: ", end=" ")
# return item in self.data
# if __name__ == '__main__':
# x = Iters([1, 2, 3, 4, 5])
# print(3 in x)
# for i in x:
# print(i, end=" ")
# print()
# print([i ** 2 for i in x])
# print(list(map(bin, x)))
# I = iter(x)
# while True:
# try:
# print(next(I), end=" @ ")
# except StopIteration:
# break
# x = Iters("spam")
# print(x[0])
# print("spam"[1:])
# print("spam"[slice(1, None)])
# print(x[1:])
# print(x[:-1])
class Empty:
# .age 点语法取值时执行
def __getattr__(self, item):
if item == "age":
return 40
else:
raise AttributeError(item)
# .age=12, 点语法赋值时执行
def __setattr__(self, key, value):
if key == "age":
self.__dict__[key] = value
else:
raise AttributeError(key + " not allowed")
# if __name__ == '__main__':
# e = Empty()
# # print(e.age)
# # print(e.name)
# e.age = 40
# e.name = "mel"
class Commuter:
def __init__(self, val):
self.val = val
def __add__(self, other):
"""左加法, 当前对象在左边时执行, 比如c = Commuter(0) c + 10"""
print("__add__ 左加法")
if isinstance(other, Commuter):
other = other.val
return Commuter(self.val + other)
def __radd__(self, other):
"""右加法, 当前对象在右边时执行, 比如c = Commuter(0) 10 + c"""
print("__radd__ 右加法")
return Commuter(other + self.val)
def __str__(self):
return '<Commuter: %s>' %self.val
class Number:
def __init__(self, val):
self.val = val
def __add__(self, other):
"""左加法, 当前对象在左边时执行, 比如c = Commuter(0) c + 10"""
print("__add__ 左加法")
if isinstance(other, Commuter):
other = other.val
return Number(self.val + other)
def __iadd__(self, other):
"""原地加法, __iadd__不存在时执行__add__"""
print("__iadd__ 原地加法")
self.val += other
return self
# if __name__ == '__main__':
# x = Commuter(88)
# y = Commuter(99)
# print(x + 10)
# print(10 + y)
#
# z = x + y
# print(z)
# print(z + 10)
# print(z + z)
# n = Number(5)
# n += 1
# n += 1
# print(n.val)
class Mul:
def __init__(self, val):
self.val = val
def __mul__(self, other):
"""乘法类似于__add__方法, __rmul__, __imul__"""
print("__mul__ ")
self.val *= other
return self.val
# if __name__ == '__main__':
# mul = Mul(10)
# mul * 9
# print(mul.val)
class Callee:
def __call__(self, *args, **kwargs):
"""类实例对象加()时调用, c = Callee(), c(1, 2, 3)"""
print("called: ", args, kwargs)
class Prod:
def __init__(self, val):
self.val = val
def __call__(self, other):
return self.val * other
# if __name__ == '__main__':
# c = Callee()
# c(1, 2, 3)
# c(1, 2, 3, x=7, y=8)
# p = Prod(4)
# print(p(5))
class Callback:
def __init__(self, color):
self.color = color
def __call__(self):
print("turn", self.color)
class Button:
def __init__(self, command):
self.command = command
# if __name__ == '__main__':
# cb1 = Callback("blue")
# cb2 = Callback("green")
#
# b1 = Button(command=cb1)
# b2 = Button(command=cb2)
#
# print(cb1())
# print(cb2())
# cb3 = lambda color="red": "turn " + color
# print(cb3())
class C:
data = "spam"
def __gt__(self, other):
"""大于"""
return self.data > other
def __lt__(self, other):
"""小于"""
return self.data < other
"""
__cmp__方法已经在python3中删除
"""
# if __name__ == '__main__':
# c = C()
# print(c > "ham")
# print(c < "ham")
class Truth:
def __bool__(self):
"""
python3: 判断当前对象bool属性, 没有__bool__方法时执行__len__方法
python3: 判断当前对象bool属性, 将__bool__方法替换成__nonzero__方法即可, 其他类似python3
"""
return True
def __len__(self):
return 0
# if __name__ == '__main__':
# t = Truth()
# if t:
# print("yes!")
class Life:
def __init__(self, name="unknown"):
print("hello ", name)
self.name = name
def __del__(self):
"""对象引用清空被回收时执行, 析构函数__del__
比如 brain = "loretta"会导致life无引用, 此时触发__del__
"""
print("__del__ ", self.name)
print("Goodbye", self.name)
# if __name__ == '__main__':
# brain = Life("brain")
# brain = "loretta"
2. 继承, 委托, 组合
"""
方法和函数
python3 支持实例方法, 静态方法, 类方法
"""
import types
class Selfless:
def __init__(self, data):
self.data = data
@staticmethod
def selfless(arg1, arg2):
"""写在类中的不一定是方法, 可能是函数"""
return arg1 + arg2
def normal(self, arg1, arg2):
return self.data + arg1 + arg2
def square(arg):
return arg * 2
class Sum:
def __init__(self, val):
self.val = val
def __call__(self, arg):
return self.val + arg
class Product:
def __init__(self, val):
self.val = val
def method(self, arg):
return self.val + arg
# if __name__ == '__main__':
# x = Selfless(2)
# print(Selfless.normal(x, 2, 3))
# print(Selfless.selfless(3, 4))
# f1 = square # 函数
# f2 = Sum(3) # 类
# f3 = Product(2).method # 方法
# actions = [f1, f2, f3]
# for func in actions:
# print(func(5))
#
# # 打印对象
# table = {func(5): func for func in actions}
# for key, val in table.items():
# print("{0:2} => {1}".format(key, val))
"""混合类"""
class ListInstance:
def __str__(self):
return "<Instance of %s, address %s:\n%s>" %(
self.__class__.__name__,
id(self),
self.__attrnames2()
)
# def __repr__(self):
# return "<Instance of %s, address %s:\n%s>" %(
# self.__class__.__name__,
# id(self),
# self.__attrnames2()
# )
def __attrnames(self):
result = ""
for attr in sorted(self.__dict__):
result += "\tname %s=%s\n" %(attr, self.__dict__[attr])
return result
def __attrnames2(self):
result = ""
for attr in dir(self):
if attr.startswith("__") and attr.endswith("__"):
result += "\tname %s=<>\n" % attr
else:
# print(type(attr), attr)
"""
显示一个方法的值, 触发了该类的__repr__方法, 将导致循环引用, 因此使用__str__
print(type(type(getattr(self, attr))))
print(types.MethodType)
if not isinstance(getattr(self, attr), types.MethodType):
"""
result += "\tname %s=%s\n" % (attr, getattr(self, attr))
return result
class Spam(ListInstance):
def __init__(self):
self.data1 = "food"
class ListTree:
def __str__(self):
self.__visited = {}
return "<Instance of {0}, address {1}:\n{2}{3}>".format(
self.__class__.__name__,
id(self),
self.__attrnames(self, 0),
self.__listclass(self.__class__, 4)
)
def __listclass(self, aclass, indent):
dots = "." * indent
"""递归退出条件, 所有类的父类最终都回到object, 此时结束"""
if aclass in self.__visited:
# print("------------------------", aclass, self.__visited)
return "\n{0}<Class {1}:, address {2}: (see above)\n".format(
dots,
aclass.__name__,
id(aclass)
)
else:
self.__visited[aclass] = True
"""使用递归遍历所有父类属性"""
genabove = (self.__listclass(c, indent + 4) for c in aclass.__bases__)
return "\n{0}<Class {1}:, address {2}: \n {3}{4}{5}>\n".format(
dots,
aclass.__name__,
id(aclass),
self.__attrnames(aclass, indent),
"".join(genabove),
dots
)
def __attrnames(self, obj, indent):
spac = " " * (indent + 4)
result = ""
for attr in sorted(obj.__dict__):
if attr.startswith("__") and attr.endswith("__"):
result += spac + "{0} =<>\n".format(attr)
else:
result += spac + "{0}={1}\n".format(attr, getattr(obj, attr))
return result
class Super:
def __init__(self):
self.data = "10"
class Sub(Super, ListTree):
def __init__(self):
super(Sub, self).__init__()
self.age = 19
def ham(self):
pass
from tkinter import Button
class MyButton(ListTree, Button): pass
# if __name__ == '__main__':
# x = Spam()
# print(x)
# y = Sub()
# print(y)
# b = MyButton(text="spam")
# print(len(str(b)))
"""工厂模式"""
def factory(aclass, *args):
"""在java中其实就是一个动态创建对象的函数, 一般会使用泛型和继承来实现"""
return aclass(*args)
class Sp:
def doit(self, message):
print(message)
class Person:
def __init__(self, name, job):
self.name = name
self.job = job
if __name__ == '__main__':
obj1 = factory(Sp)
obj2 = factory(Person, "alex", 12)
"""
1. 什么是多继承?
当有一个以上超类是就称之为多继承
2. 什么是委托?
将对象伪装成另一个类的属性, 通过属性调用该对象
3.什么是组合?
通过多继承方式, 扩展子类的功能
4. 什么是绑定方法?
定义在类中, 默认第一个参数由实例传入
5. 什么是私有属性?
不想被直接访问的属性, 一中属性映射的方式, 比如将__x ->_classname__x
"""
3. slots, 内置类型扩展, 静态方法,类方法, 实例方法, 装饰器, 类特性, 新式类与经典类
"""
扩展内置类型
"""
class Set:
"""通过自定一个方式扩展列表, 将其当做一个集合使用"""
def __init__(self, value=[]):
self.data = value
self.concat(value)
def intersect(self, other):
res = []
for x in self.data:
if x in other:
res.append(x)
return Set(res)
def union(self, other):
res = self.data[:]
for x in self.data:
if x not in other:
res.append(x)
return Set(res)
def concat(self, value):
for x in value:
if x not in self.data:
self.data.append(x)
def __len__(self): return len(self.data)
def __getitem__(self, item): return self.data[item]
def __and__(self, other): return self.intersect(other)
def __or__(self, other): return self.union(other)
def __repr__(self): return "Set" + str(self.data)
class MyList(list):
"""
通过继承, 来扩展list, 将list从0开始索引改为从1开始索引
"""
def __getitem__(self, item):
print("index %s at %s" % (self, item))
return list.__getitem__(self, item - 1)
class MySet(list):
""""""
def __init__(self, value=[]):
super(MySet, self).__init__(value)
self.concat(value)
def intersect(self, other):
res = []
for x in self:
if x in other:
res.append(x)
return Set(res)
def union(self, other):
res = MySet(self)
res.concat(other)
return res
def concat(self, value):
for x in value:
if x not in self:
self.append(x)
def __and__(self, other): return self.intersect(other)
def __or__(self, other): return self.union(other)
def __repr__(self): return "Set" + list.__repr__(self)
# if __name__ == '__main__':
# x = Set([1, 3, 5, 7])
# print(x.union([1, 4, 7]))
# print(x | Set([1, 4, 6]))
# print(list('abc'))
# c = MyList('abc')
# print(c)
#
# print(c[1])
# print(c[3])
#
# c.append("spme")
# print(c)
# c.reverse()
# print(c)
# z = MySet([1, 3, 4, 6])
# n = MySet([2, 1, 4, 6, 9])
#
# print(z, n, len(z))
# print(z.intersect(n), n.union(z))
# print(z & n, n | z)
# z.reverse()
# print(z)
"""
新式类
python3之后所有的类不管是显示的还是隐式的都继承自object
python2.6之前的版本, 需要手动传入object
默认打印实例类型时显示创建它的类, 类即就是类型
每个类都是由元类type生成的, 也就是说类的类型是type
继承搜索广度优先
经典类
默认实例打印类型是显示instance类型
打印类类型时显示 classobj
比较实例类型无用, 因为都是instance类型; 因此㤇比较__class__属性
继承搜索深度优先, 然后从左向右
"""
"""
__slots__
"""
class Limiter:
"""通过__slots__限制属性, 可以通过增加__dict__属性放开限制"""
__slots__ = ["age", "name", "job", "__dict__"]
def __init__(self):
self.d = 4
class E:
__slots__ = ['c', 'd']
class D(E):
__slots__ = ["a", "__dict__"]
# if __name__ == '__main__':
# lm = Limiter()
# lm.age = 12
# print(lm.__dict__)
# print(lm.__slots__)
# print(getattr(lm, "age"))
# setattr(lm, "job", 1)
# lm.count = 10
# lm.data = 1
# d = D()
# d.a = 1
# d.b = 2
# d.c = 3
# print(d.a, d.c, d.b)
#
# print(E.__slots__)
# print(D.__slots__)
#
# print(d.__slots__)
# print(d.__dict__)
#
# for attr in list(getattr(d, "__dict__", [])) + getattr(d, "__slots__", []):
# print(attr, "=>", getattr(d, attr))
#
# print(dir(d))
"""
类特性
"""
class Classic:
def __getattr__(self, item):
if item == "age":
return 40
else:
raise AttributeError
def __setattr__(self, key, value):
print("set:",key, value)
if key == "age":
self.__dict__["_age"] = value
else:
self.__dict__[key] = value
class NewProps:
def getage(self):
print("getaget")
return 40
def setage(self, value):
print("set age:", value)
self._age = value
# 自动调用getxxx, setxxx, delxxx系列方法, 等价于如上的Classic
age = property(getage, setage, None, None)
# if __name__ == '__main__':
# cls = Classic()
# print(cls.age)
# print(cls.name)
# np = NewProps()
# print(np.age)
# # print(np.name)
# np.age = 30
# print(np._age)
#
# np.job = "trainer"
# print(np.job)
"""
类方法和静态方法
静态方法和显式类名称可能对于处理一个类本地的数据来说是更好的解决方案。
类方法可能更适合处理对层级中的每个类不同的数据。
"""
class Method:
def imeth(self, x):
print(self, x)
def smeth(x):
print(x)
def cmeth(cls, x):
print(cls, x)
# 使用特殊函数装饰原函数
smeth = staticmethod(smeth)
cmeth = classmethod(cmeth)
class Spam:
"""统计一个类有多少实例"""
ins = 0
def __init__(self):
Spam.ins += 1
def get_cls_ins():
print("Number of instances:", Spam.ins)
# 将get_cls_ins包装成一个静态方法, 不需要传入实例对象或对象, 和普通函数一样, 可以用过类或者实例直接调用
get_cls_ins = staticmethod(get_cls_ins)
class Sub(Spam):
def get_cls_ins():
print("Extra stuff...")
Spam.get_cls_ins()
get_cls_ins = staticmethod(get_cls_ins)
class Spam2:
ins = 0
def __init__(self):
Spam2.ins += 1
def get_cls_ins(cls):
"""直接通过类方法调用"""
print("Number of instances:", cls.ins)
get_cls_ins = classmethod(get_cls_ins)
class Sp:
ins = 0
def count(cls):
print(cls)
cls.ins += 1
def __init__(self):
self.count()
count = classmethod(count)
class Sb(Sp):
ins = 0
def __init__(self):
Sp.__init__(self)
class Ot(Sp):
ins = 0
# if __name__ == '__main__':
# 静态方法
# obj = Method()
# obj.imeth(1)
# Method.imeth(obj, 2)
# Method.smeth(3)
# Method.cmeth(00)
# obj.cmeth(.1)
#
# a = Spam()
# c = Spam()
# v = Spam()
# Spam.get_cls_ins()
# a.get_cls_ins()
# s = Sub()
# q = Sub()
# a.get_cls_ins()
# Sub.get_cls_ins()
# Spam.get_cls_ins()
# 类方法
# m = Spam2()
# m.get_cls_ins()
# Spam2.get_cls_ins()
# 类方法扩展
# x = Sp()
# y1, y2 = Sb(), Sb()
# z1, z2, z3 = Ot(), Ot(), Ot()
# # 实例调用类属性, 或从类中继承, 而且是就近查找, 而且因为是从类属性继承, 一次z1, z2, z3 ins都相同
# print(x.ins, y1.ins, z1.ins, z2.ins)
# # 通过类名直接调用类属性时, 此时也会发生继承, 如果没有就回去父类查找
# # Sp.ins =1 是因为Sb, Ot中都有ins属性, 不会继承自父类
# print(Sp.ins, Sb.ins, Ot.ins)
"""
装饰器和元类
"""
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
def spam(a, b, c): # spam = tracer(spam)
print(a, b, c)
def count(cls):
"""函数装饰器, 统计实例个数"""
print(cls.__dict__)
cls.ins += 1
print(cls.__dict__)
return cls
@count
class Spam3:
ins = 0
@count
class Sub2(Spam3):
pass
class C:
shared = []
def __init__(self):
self.obj = []
# if __name__ == '__main__':
# spam(1, 2, 3) # spam() -> 实例加()调用 __call__
# spam("a", "b", "c")
# spam(4, 5, 6)
# s1 = Spam3()
# sb1 = Sub2()
# # 修改类属性, 会影响所有的实例; 但是不影响子类, 因为cls.ins += 1 相当于一个赋值语句, 直接从父类中拷贝了一份
# Spam3.ins = 9
# print(s1.ins)
# print(sb1.ins)
# x = C()
# y = C()
#
# print(y.shared, y.obj)
# x.shared.append("spam")
# x.obj.append("spam")
# print(x.shared, x.obj)
# print(y.shared, y.obj)
# print(C.shared)
"""
本章习题
1.列举出两种能够扩展内置对象类型的方法?
2.函数修饰器是用来做什么的?
3.怎样编写新式类?
4.新式类与经典类有何不同?
5.正常方法和静态方法有何不同?
习题解答
1.妳你可以在包装类中内嵌内置对象,或者直接做内置类型的子类。后者显得更简单,
因为大多数原始的行为都被自动继承了。
2.函数修饰器通常是用来给现存的函数增加函数每次被调用时都会运行的一层逻辑。
它们可以用来记录函数的日志或调用次数、检查参数的类型等。它们同样可以用做“
静态方法”(一个在类中的函数,不需要传入实例)。
3.可以通过对对象的内置类(或者其他的内置类型)继承来编写新式类。在Python
4.新式类广度优先搜素, 经典类深度优先搜索, 针对内置操作, 没有运行__getattr__
这样的获取属性方法, 支持特性, 描述符, __slots__实例属性列表
5.正常方法实例方法, 静态方法实例和类都可以调用, 实例调用时需要加装饰方法说明,
类调用时不需要
"""
# 题目1
class Adder:
def __init__(self, data):
self.data = data
def add(self, x, y):
raise NotImplemented
def __add__(self, other):
return self.add(self, other)
class ListAdder(Adder):
def add(self, x, y):
if isinstance(y, Adder):
return x.data + y.data
return x + y
class DictAdder(Adder):
def add(self, x, y):
if isinstance(y, Adder):
return x.data.update(y.data)
return x.update(y)
# 题目2
class MyList:
def __init__(self, obj=None):
self.data = []
if obj:
if isinstance(obj, list):
self.data += obj
elif isinstance(obj, MyList):
self.data += obj.data
else:
assert Exception("obj must a list or MyList instance")
self.index = 0
def __add__(self, other):
if isinstance(other, MyList):
self.data += other.data
else:
self.data += other
return self.data
def __getitem__(self, item):
return self.data[item]
def __iter__(self):
print("__iter__")
return iter(self.data)
def __next__(self):
print("__next__")
if self.index < len(self.data):
ans = self.data[self.index]
self.index += 1
return ans
else:
raise StopIteration
def append(self, obj):
if isinstance(obj, list):
self.data += obj
elif isinstance(obj, MyList):
self.data += obj.data
else:
assert Exception("obj must a list or MyList instance")
def sort(self, reverse=False, key=None):
return sorted(self.data, reverse=reverse, key=key)
# 题目3
class MyListSub(MyList):
calls = 0
def __init__(self):
self.adds = 0
super(MyListSub, self).__init__()
def __add__(self, other):
MyListSub.calls += 1
self.adds += 1
return MyList.__add__(self, other)
def stats(self):
return self.calls, self.adds
# 题目4
class Meta:
def __new__(cls, *args, **kwargs):
return super(Meta, cls).__new__(cls, *args, **kwargs)
def __getattr__(self, item):
"""python3.0之后获取内置的属性不在经过__getattr__方法"""
print("get", item)
def __setattr__(self, key, value):
print("set", key, value)
# 题目6
class Lunch:
def __init__(self, cus, emp):
self.cus = cus
self.emp = emp
def order(self, foodName):
self.cus.placeOrder(foodName, self.emp)
def result(self):
self.cus.printFood()
class Customer:
def __init__(self, name):
self.name = name
self.foods = []
def placeOrder(self, foodName, employee):
self.foods.append(employee.takeOrder(foodName))
def printFood(self):
for food in self.foods:
print(food.name)
class Employee:
def takeOrder(self, foodName):
print("处理订单, 食物名称%s" % foodName)
return Food(foodName)
class Food:
def __init__(self, name):
self.name = name
class Animal:
def reply(self):
self.speak()
def speak(self):
raise NotImplemented
class Mammal(Animal):
def speak(self):
print("Mammal")
class Cat(Mammal):
def speak(self):
print("Cat")
class Dog(Mammal):
def speak(self):
print("Dog")
class Primate(Mammal):
def speak(self):
print("Primate")
class Hacker(Primate):
def speak(self):
print("Hacker")
class Cus:
def line(self):
print("customer: that`s one ex-bird!")
class Clerk:
def line(self):
print("Clerk: no is`nt...")
class Parrot:
def line(self):
print("Parrot:", None)
class Scene:
def __init__(self, *args):
self.actions = [*args]
def action(self):
for obj in self.actions:
obj.line()
"""
OOP优点:
代码重用
封装: 在对象接口后包装其实现的细节,从而隔离了代码的修改对用户产生的影响
结构: 类提供了一个新的本地作用域,最小化了变量名冲突。它们还提供了一种编写和查找实现代码,以及去管理对象状态的自然场所。
维护性: 类自然而然地促进了代码的分解,这让我们减少了冗余。多亏支持类的结构以及代码重用,这样每次只需要修改代码中一个拷贝就可以了。
一致性: 类和继承可以实现通用的接口。这样你的代码有了统一的外表和观感,这样也简化了代码的调试、理解以及维护。
多态: 这更像是一个OOP的属性。而不是一条使用它的理由,但是通过广泛地支持代码,多态让代码更灵活和有了广泛的适用性,因此有了更好的可重用性。
"""
if __name__ == '__main__':
# x = ListAdder([1, 2])
# y = ListAdder([1, 2])
# print(x + y)
# l2 = MyList([10, 1, 2, 3])
#
# print(l2 + [4, 5, 6])
# print(l2.sort(reverse=True))
# print(l2[1: 5])
# sblist = MyListSub()
# print(sblist+[1, 2, 3])
# m = Meta()
# m.append
# m.spam = "port"
# m[1]
# print(next(l2))
# for item in l2: # 调用__iter__方法, 但是没有调用__next__方法
# print(item)
# cus = Customer("bob")
# emp = Employee()
# lunch = Lunch(cus, emp)
#
# lunch.order("tomato")
# lunch.order("petato")
# lunch.result()
# spot = Dog()
# spot.reply()
#
# data = Hacker()
# data.reply()
c = Cus()
p = Parrot()
cl = Clerk()
s = Scene(c, p, cl)
s.action()