一、变量介绍
mo = 8 class Foo(): YY = 5 def __init__(self,x): self.age=2 #实例变量,Java中的public self.__priv=8 #私有变量,Java中的private a = 1 #局部变量 Foo.YY = 3 #类变量,所有实例共享。 mo = 9 #全局变量
二、多态、继承、聚集
''' 多态: 子类和父类中有相同的方法,将调用子类的方法,super()将调用父类的方法 继承----is a关系 继承的作用是进行代码的重用 继承里面遇到有重写的方法最好是每个方法之前都调用父类的方法。 因为这样会使继承变得有意义例如__init__() 最好的执行顺序是先执行父类的构造方法,再执行子类的构造方法 如果没有重写,调用子类的方法将直接调用父类的方法 聚集----某类里包含别的类对象has a关系 '''
三、经典类,新式类
#经典类:没有指定基类,所以是object的子类 class className: suite #新式类: class className(base_classes): suite
四、hash
''' 所有自定义对象都是可以hash的,(可以作为字典的键), 都可以进行hash运算。如果重新实现了__eq__()就不可hash了 '''
五、Point类
''' Shape.py 实例变量:self.x和self.y 实例变量可以通过对象直接访问,不是私有的。私有变量应该是__x和__y这种 私有方法是def __func(self): pass这种。也是不能直接通过对象访问的,只能在类里面使用 self表示本对象自己。 创建一个对象有两个步骤: 1、调用__new__()创建该对象 2、调用__init__()对其进行初始化 这里是object.__new__()然后point.__init__() 在实际编程中,我们只需要重新实现__init__()方法,new方法使用object.__new__()已经足够 某种编码风格--在自定义__init__()的起始处总是调用super().__init__()是一种合理的做法。 直接继承自object的类,没有必要这样处理。一般只在必须的时候才调用基类的方法 ''' class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def distance_from_origin(self): return (self.x ** 2 + self.y ** 2) ** 0.5 def __eq__(self, other): if not isinstance(other,Point): return NotImplemented #将调用other.__eq__(self)如果没有实现或也返回NotImplement将抛出TypeError错误 return self.x==other.x and self.y==other.y def __repr__(self): return "Point({0.x},{0.y})".format(self) def __str__(self): return "({0.x},{0.y})".format(self) a = Point() print(repr(a)) # Point(0,0) b = Point(3,4) print(str(b)) # (3,4) print(b.distance_from_origin()) # 5.0 b.x = -19 print(str(b)) # (-19,4) print(a==b,a!=b) # False True print(a == int(4)) # False ''' test.py ''' import Shape p = Shape.Point(3,4) print(repr(p)) # Point(3,4) q = eval(p.__module__+"."+repr(p)) print(p.__module__) # Shape s = "Shape.Point(3,4)" s1 = eval(s) print(q.x, s1.x) # 3 3
六、Circle类
''' 1、通过super()调用基类的方法 2、在super()调用中不需要传递self参数,因为Python会自动传递这一参数 3、多态,Circle对象在使用时都可以当成Point对象来使 4、@property:方法返回float,可以吧方法当做只读的属性使用 5、property修饰器函数有四个参数(获取者函数,设置者函数,删除者函数,docstring) 类似fset(func.__name__,func()) ''' from Shape import Point class Circle(Point): def __init__(self, radius, x=0, y=0): super().__init__(x, y) self.radius = radius def edge_distance_from_origin(self): #圆边缘到圆心的距离 return abs(self.edge_distance_from_origin() - self.radius) @property def area(self): return 3.14 * self.radius ** 2 def circumference(self): return 2 * 3.14 * self.radius def __eq__(self, other): return self.radius == other.radius and super().__eq__(other) def __repr__(self): return "Circle({0.radius},{0.x},{0.y})".format(self) def __str__(self): return repr(self) p = Point(3,4) c = Circle(2,3,4) print(p.distance_from_origin()) # 5.0 print(c.distance_from_origin()) # 5.0 print(c.area) # 12.56 #################################################################################################################### ''' 将radius属性变为特性实现: 初始化时radius也不能为负数 赋值时,radius也不能为负数 使用@property创建radius特性后, radius.setter radius.getter radius.deleter都可用 assert: 相当于raise-if-not ''' class C: def __init__(self, radius): self.__radius = radius @property def radius(self): '''以下是docstring: >>> c=C(-2) AssertionError:radius must be nonzero and non-negative ''' return self.__radius @radius.setter def radius(self, radius): assert radius > 0, "radius must be nonzero and non-negative" self.__radius = radius c = C(8) print(c.radius) # 8 c.radius = -3 # 报错"radius must be nonzero and non-negative" print(c.radius)
七、FuzzBool继承object
''' 说明 1、在Python中del函数是删除对象的一个引用,只有当对象的引用为0时才执行__del__()方法 2、Python中一般不使用静态方法,而是使用模块函数或者类方法 FuzzBool类 1、支持(==、!=、>、>=、<、<=)比较操作符 2、支持逻辑操作符not(~)、and(&)、or(|)、&=、|= 3、两种其他逻辑方法conjunction()、disjunction() 4、bool、int、float、str数据类型转换功能 5、可使用eval()评估的表象形式 6、str.format()格式规约支持 7、可作为字典的键(支持hash) ''' class FuzzBool: def __init__(self, value=0.0): self.__value = value if 1.0 >= value >= 0.0 else 0.0 # (==、!=、>、>=、<、<=)比较操作符 def __eq__(self, other): return self.__value == other.__value def __ne__(self, other): return self.__value != other.__value def __gt__(self, other): return self.__value > other.__value def __ge__(self, other): return self.__value >= other.__value def __lt__(self, other): return self.__value < other.__value def __le__(self, other): return self.__value <= other.__value # not(~)、and(&)、or(|)、&=、|= def __invert__(self): return FuzzBool(1.0 - self.__value) def __and__(self, other): return FuzzBool(min(self.__value, other.__value)) def __iand__(self, other): self.__value = min(self.__value, other.__value) return self def __or__(self, other): return FuzzBool(max(self.__value, other.__value)) def __ior__(self, other): self.__value = max(self.__value, other.__value) return self # 可使用eval()评估的表象形式 def __repr__(self): return "{0}({1})".format(self.__class__.__name__, self.__value) # bool、int、float、str数据类型转换 def __bool__(self): return self.__value > 0.5 def __int__(self): return round(self.__value) def __float__(self): return self.__value def __str__(self): return str(self.__value) # 可作为字典的键(支持hash) def __hash__(self): return hash(id(self)) # 格式规约支持 def __format__(self, format_spec): return self.__value.__format__(format_spec) # 两种其他逻辑方法conjunction()、disjunction() @staticmethod def conjunction(*fuzzies): return FuzzBool(min([float(f) for f in fuzzies])) @staticmethod def disjunction(*fuzzies): return FuzzBool(max([float(f) for f in fuzzies])) f1 = FuzzBool(0.2) f2 = FuzzBool(0.50001) f1 |= f2 print(f1 ) fx = eval("FuzzBool(0.3)") print(bool(f2)) print(hash(f2)) print("{0}".format(f1))
八、FuzzBool继承float
''' __new__()是一个类方法,但不需要用@classmethod特别指明 类方法的第一个参数是由Python指定的,也就是方法所属的类 ''' class FuzzBool(float): def __new__(cls, value): return super().__new__(cls, value if 1.0 >= value >= 0.0 else 0.0) def __invert__(self): return FuzzBool(1.0 - self) def __and__(self, other): return FuzzBool(min(self, other)) def __or__(self, other): return FuzzBool(max(self, other)) def __repr__(self): return "{0}({1})".format(self.__class__.__name__, super().__repr__()) # 取消float类的加法 def __add__(self, other): raise NotImplementedError # 这里还有很多类似的方法要取消... f1 = FuzzBool(0.3) f2 = FuzzBool(0.5) print(f1 | f2) # 0.5 print(f1 == eval("FuzzBool(0.3)")) # True
####比较:第一种使用聚集的方法创建FuzzBool更好, ####因为第二种需要关闭float类的不需要对FuzzBool对象开放的方法
九、Image类
import pickle ''' dict.get(key,default)如果value为None将取默认值 1、图片有背景色,像素颜色跟背景色一样的不保存 2、__colors属性保存所有不重复的颜色 ''' class CoordinateException(Exception): pass class NotFilenameException(Exception): pass class SaveException(Exception): pass class Image: def __init__(self, width, height,background="#FFFFFF", filename=""): self.filename = filename self.__background = background self.__width = width self.__height = height self.__data = {} self.__colors = {background} @property def width(self): return self.__width @property def height(self): return self.__height @property def background(self): return self.__background @width.setter def width(self, width): self.__width = width @height.setter def height(self, height): self.__height = height @background.setter def background(self, background): self.__background = background # 根据像素点的色值 例如:i[40,30] def __getitem__(self, item): assert len(item) == 2,"should be a 2-tuple" if (not (0 <= item[0] < self.width) or not(0 <= item[1] < self.height)): raise CoordinateException return self.__data.get(tuple(item), self.__background) # 设置像素点的色值 例如:i[40,30]="#000FFF" def __setitem__(self, key, value): assert len(key) == 2, "should be a 2-tuple" if (not (0 <= key[0] < self.width) or not (0 <= key[1] < self.height)): raise CoordinateException if value == self.background: self.__data.pop(tuple(key)) else: self.__data[tuple(key)] = value self.__colors.add(value) # 删除像素点 def __delitem__(self, key): assert len(key) == 2, "should be a 2-tuple" if (not (0 <= key[0] < self.width) or not (0 <= key[1] < self.height)): raise CoordinateException self.__data.pop(tuple(key)) def save(self, filename=None): if filename is not None: self.filename = filename if not self.filename: raise NotFilenameException f = None try: f = open(self.filename, "wb") data = [self.width, self.height, self.background, self.__data] pickle.dump(data, f, pickle.HIGHEST_PROTOCOL) except(EnvironmentError,pickle.PicklingError) as err: raise SaveException finally: if f is not None: f.close() def load(self, filename=None): if filename is not None: self.filename = filename if not self.filename: raise NotFilenameException f = None try: f = open(self.filename, "rb") data = pickle.load(f) self.width, self.height, self.background, self.__data = data self.__colors = (set(self.__data.values()) | {self.background}) except(EnvironmentError,pickle.PicklingError) as err: raise SaveException finally: if f is not None: f.close() i = Image(300, 400) # print(i.background) # print(i[200,33]) # i[200,33] = "#000FFF" i.load("img.png") print(i[200, 33])
十、SortedList排序列表(聚集list)
class SortedList: ''' 实现一个排序列表,列表初始化之后是排过序的。增删改查 ''' def __init__(self, sequence=None, key=None): __identity = lambda x:x self.__key = key or __identity assert hasattr(self.__key, "__call__") if sequence is None: self.__list = [] elif isinstance(sequence, SortedList) and self.__key == sequence.key: # key都为lambda时,表达式为False self.__list = sequence.__list[:] # 可以访问私有变量 else: self.__list = sorted(list(sequence), key=self.__key) @property def key(self): return self.__key def add(self, value): index = self.__bisect_left(value) self.__list.insert(index, value) def __bisect_left(self, value): ''' 二分法找下标: 如果key一直落在mid右边,left将以1,1/2,1/4,1/8的速度向右收缩 如果key一直落在mid左边或等于mid,right将以1,1/2,1/4,1/8的速度向左收缩 left和right哪边先到达mid=value的下标呢? 答案一定是left先等于value 因为left是一步一步向右移的 left += 1 可以看出,如果有相同的value,返回的下标一定是最左边的下标值。 如果value在list中不存在,将返回value在list中左边值的下标 ''' left, right = 0, len(self.__list) key = self.__key(value) while left < right: mid = (left + right) // 2 if self.__key(self.__list[mid]) < key: left += 1 else: right = mid return left def remove(self, value): index = self.__bisect_left(value) if len(self.__list) > index >= 0 and self.__list[index] == value: self.__list.pop(index) else: raise ValueError("{0}.remove(x):x not in list".format(self.__class__.__name__)) def remove_every(self, value): count = 0 index = self.__bisect_left(value) while (0<= index <len(self.__list) and self.__list[index] == value): self.__list.pop(index) count += 1 return count def count(self, value): count = 0 index = self.__bisect_left(value) while (0 <= index < len(self.__list) and self.__list[index] == value): index += 1 count += 1 return count def index(self, value): index = self.__bisect_left(value) if 0 <= index < len(self.__list) and self.__list[index] == value: return index else: raise ValueError("{0}.index(x):x not in list.".format(self.__class__.__name__)) def __delitem__(self, index): del self.__list[index] def __getitem__(self, index): return self.__list[index] def __setitem__(self, index, value): raise TypeError("use add() to insert a value and rely" " on the list to put it in the right place") def __iter__(self): return iter(self.__list) def __reversed__(self): return reversed(self.__list) def __contains__(self, value): index = self.__bisect_left(value) return (0 <= index < len(self.__list) and self.__list[index] == value) def clear(self): self.__list = [] def pop(self, index=-1): return self.__list.pop(index) def __len__(self): return len(self.__list) def __str__(self): return str(self.__list) def copy(self): # 将首先尝试使用对象的特殊方法__copy__(),如果没有该方法就执行自己的代码 return SortedList(self.__list) if __name__ == '__main__': s = SortedList([4,2,1,5,7,2,4,6,8]) print(s) # [1, 2, 2, 4, 4, 5, 6, 7, 8] print(s.index(1)) # 0 print(s[2]) # 2 print(s) # [1, 2, 2, 4, 4, 5, 6, 7, 8] del s[0] print(s) # [2, 2, 4, 4, 5, 6, 7, 8] print(600 in s) # False print(s.copy()) # [2, 2, 4, 4, 5, 6, 7, 8]
十一、SortedDict排序字典(继承dict聚集SortedList)
from SortedList import SortedList import copy class SortedDict(dict): def __init__(self, dictionary=None, key=None, **kwargs): dictionary = dictionary or {} super().__init__(dictionary) # 如果只到这一句,其实可以不写init方法 if kwargs: super().update(kwargs) self.__keys = SortedList(super().keys(), key) # 不能用SortedDict.keys()因为依赖于self.__keys此时还没有keys def update(self, dictionary=None, **kwargs): # dictionary可能为None,dict,其他有itmes迭代的类型 if dictionary==None: pass elif isinstance(dictionary, dict): super().update(dictionary) else: for key,value in dictionary.items(): super().__setitem__(key, value) if kwargs: super().update(kwargs) self.__keys = SortedList(super().keys(), self.__keys.key) # @classmethod # fromkeys方法被继承。类方法比静态方法好,使用类方法可以知道调用该方法的是子类还是父类 # def fromkeys(cls, iterable, value=None, key=None): # return cls({k: value for k in iterable}, key) def __setitem__(self, key, value): if key not in self: # dict类已经实现__contains__方法 self.__keys.add(key) return super().__setitem__(key, value) def __delitem__(self, key): try: self.__keys.remove(key) except ValueError: raise KeyError(key) return super().__delitem__(key) def setdefault(self, key, value=None): # 没有key就新增,有key就修改值 if key not in self: self.__keys.add(key) return super().setdefault(key, value) def pop(self, key, *args): # *args是为了不关注里面有多少参数都给super处理 ''' 如果key存在则删除键值对并返回value,如果不存在则返回args[0] 对比一下两种写法 if key in self: self.__keys.remove(key) return super().pop(key, args) ''' if key not in self: if len(args) == 0: raise KeyError(key) return args[0] self.__keys.remove(key) return super().pop(key, args) def popitem(self): item = super().popitem() self.__keys.remove(item[0]) return item def clear(self): super().clear() self.__keys.clear() def values(self): # values迭代器 for key in self.__keys: yield self[key] def items(self): # (key, value)迭代器 for key in self.__keys: yield (key, self[key]) def __iter__(self): # keys迭代器 return iter(self.__keys) keys = __iter__ # obj.keys() == iter(obj) def copy(self): ''' 比较这两种写法:这种需要再进行一次排序,影响效率. (ps:只有继承了基本数据类型的才能把self直接进行初始化????) return SortedDict(self) ''' d = SortedDict() super(SortedDict, d).update(self) # dict类的update方法 d.__keys = self.__keys.copy() return d __copy__ = copy # copy.copy(obj)将使用自定义的方法 def value_at(self, index): return self[self.__keys[index]] def set_value_at(self, index, value): self[self.__keys[index]] = value def __str__(self): return super().__str__() + ' ' + str(self.__keys) # def __repr__(self): # 不能提供eval()的表现形式 # return object.__repr__(self) # s = SortedDict(dict(A=1,b=2,C=3)) # print(s) if __name__ == '__main__': s = SortedDict(dict(A=1,b=2,c=3),m=5) s1 = SortedDict.fromkeys('abcde', 1) # 调用dict的fromkeys方法 s2 = dict.fromkeys('abcde', 1) print(s1) # {'a': 1, 'b': 1, 'c': 1, 'd': 1, 'e': 1} ['a', 'b', 'c', 'd', 'e'] print(type(s1)) # <class '__main__.SortedDict'> print(type(s2)) # <class 'dict'> s['u'] = 87 print(s) # {'A': 1, 'b': 2, 'c': 3, 'm': 5, 'u': 87} ['A', 'b', 'c', 'm', 'u'] del s['A'] print(s) # {'b': 2, 'c': 3, 'm': 5, 'u': 87} ['b', 'c', 'm', 'u'] print(s.popitem()) # ('u', 87) print(s) # {'b': 2, 'c': 3, 'm': 5} ['b', 'c', 'm'] print(s.keys()) # <list_iterator object at 0x0212F410> print(s.copy()) # {'b': 2, 'c': 3, 'm': 5} ['b', 'c', 'm'] print(copy.copy(s)) # {'b': 2, 'c': 3, 'm': 5} ['b', 'c', 'm'] print(s.value_at(1)) # 3 s.set_value_at(1, 99) print(s) # {'b': 2, 'c': 99, 'm': 5} ['b', 'c', 'm']