一、随机整数生成类
#思路一:普通类实现,By me
import random
from matplotlib import pyplot as plt
class RandomNum:
def __init__(self,num,start=1,end=10):
self.num=num
self.start=start
self.end=end
def produce(self):
return [random.randint(self.start,self.end) for _ in range(self.num)]
l=RandomNum(20).produce()
print(l)
def coordinate(src):
for i in range(10):
x,y=src[i],src[-i-1]
plt.scatter(x,y)
plt.show()
coordinate(l)
可以认为生成一批随机数是一个工具,只是放在一个模块下一起管理,就像math模块一样;工具类简单调用就能出结果;以下为该思路的代码,也可改为@staticmethod,行参去掉cls即可,只要配好缺省值调用起来更方便,不用传参就可保证函数调用正常工作。
类方法、静态方法更像工具,不需实例即可工作。
#思路二:用工具类实现
class RandomNum:
@classmethod
def produce(cls,start=1,stop=10,patch=10):
return [random.randint(start,stop) for _ in range(self.patch)]
result=RandomNum.produce()
print(result)
生成器的取名最好以iter开头,方便使用方理解;生成器版本如下:
#思路三:生成器实现1
import random
class RandomGenerator:
def __init__(self,start=1,stop=100,patch=10):
self.start=start
self.stop=stop
self.patch=patch
self._gen=self._generate()
def _generate(self): #一次产生一个数据,不给看、不给调用
while True:
yield random.randint(self.start,self.stop)
def generate(self,count=0): #给用户使用,并自行决定一次产生多少个数字
patch=self.patch if count<=0 else count
return [next(self._gen) for _ in range(patch)]
# 注意:next(self._generate())这种写法每次都调用一次生成器、取其第一个随机数,不如先让 g=self._generate(),再写成next(g);或者在__init__中, self._gen=self._generate(),因为_generate()很早就定义好,实例化之后初始化,且在self.start=start、self.stop=stop、self.patch=patch之后再做self._gen=self._generate(),调用这个生成器对象,实例直接调用
a=RandomGenerator()
print(a.generate())
print(a.generate(5))
#思路四:生成器实现2,一次yield一批数据,而不是一次yield一个、攒一批
import random
class RandomGenerator:
def __init__(self,start=1,stop=100,patch=10):
self.start=start
self.stop=stop
self.patch=patch
self._gen=self._generate()
def _generate(self):
while True:
yield [random.randint(self.start,self.stop) for _ in range(self.patch)]
def generate(self,count=0):
if count>0:
self.patch=count
return next(self._gen)
a=RandomGenerator()
print(a.generate())
print(a.generate(5))
#此处需注意,改动了count,即self.patch,return next(self._gen)确实拿到了5个数据,所以生成一个生成器对象时,并不是把所有参数都固定好,每次执行到yield语句会停一下、看一下当前变量、重新算一次再送出一个数据。所以其实只是固定了一个函数对象,每用一次next都会再判断一次循环、到yield时再算一次。
思路五:使用property
import random
class RandomGenerator:
def __init__(self,start=1,stop=100,patch=10):
self.start=start
self.stop=stop
self._patch=patch
self._gen=self._generate()
def _generate(self):
while True:
yield [random.randint(self.start,self.stop) for _ in range(self.patch)]
def generate(self,count=0):
if count>0:
self.patch=count
return next(self._gen)
@property
def patch(self):
return self._patch
@patch.setter
def patch(self,value):
self._patch=value
a=RandomGenerator()
print(a.generate())
a.patch=5
print(a.generate())
二、打印坐标
注意,面向对象的思想,构建Point类,利用zip函数和参数解构
class Point:
def __init__(self,x,y):
self.x=x
self.y=y
points=[Point(x,y) for x,y in zip(RandomGenerator().generate(),RandomGenerator().generate())]
for p in points:
print('{}:{}'.format(p.x,p.y))
三、车辆信息
#By me,问题在于车没有增加车信息的功能,只有显示自己所有属性的功能,故应建两个类
class Cars:
def __init__(self,mark,color,price,speed):
self.mark=mark
self.color=color
self.price=price
self.speed=speed
def add_inf(self,attr,val):
self.attr=val
def all_inf(self):
print(self.__dict__) # 这种做法较简便,但需注意把保护成员、私有成员用filter函数过滤一下,返回一个新字典即可
honda=Cars('honda','red','30W','120')
honda.add_inf('seat','7')
honda.all_inf()
注意是两个类,一个类是纯粹车的信息;一个类用来管理:增减删改车辆信息、罗列车的属性信息等
# By Wayne
class Car: # 记录单一车辆
def __init__(self,mark,color,price,speed): #因为车的属性信息很多,此处最好设计成可变参数
self.mark=mark
self.color=color
self.price=price
self.speed=speed
class CarInfo:
def __init__(self):
self.info=[]
def addcar(self,car:Car): #命名时虽然下划线能省则省,但只要连在一起无歧义,直接写也ok
self.info.append(car.__dict__)
def getall(self): #这种返回总信息的业务,不需要把这种巨量的数据都返回回来、比如超大的列表,需考虑管理控制上下限范围,人眼不可能一次看几万行,到底怎么给,用分页、一次yield一批返回最为合适,而不是一次return一个大列表
return self.info
c=CarInfo()
car=Car('audi','red','100W','400km/h')
c.addcar(car)
print(c.getall())
以上CarInfo类的总列表可以设计为类属性、也可以设计为实例属性,但考虑到CarInfo是用来管理数据的类,类属性其实更为便利,即定义class CarInfo:后写cars=[ ],那么addcar也可写成类方法,传入cls而不是一个CarInfo实例,最后调用时CarInfo.addcar(Car())即可,因为只需要一个集中管理数据的数据中心,数据大家共用;
如果想每个实例有自己单独的数据管理容器,就需设计成上例,比如本市有3个车辆管理中心,数据直接不可共享、要分开管理,就要换一种写法进行设计。
稍作修改,如下:
# By Wayne
class Car: # 记录单一车辆
def __init__(self,mark,color,price,speed): #因为车的属性信息很多,此处最好设计成可变参数
self.mark=mark
self.color=color
self.price=price
self.speed=speed
def getcarinfo(self):
return self.__dict__
#用于呈现表达给人看的函数,方便在控制台调试;定义Car类型数据的字符串表现形式
def __repr__(self):
return '<{},{},{},{},{}>'.format(type(self).__name__,self.mark[:20],self.color,self.speed,self.price)
class CarInfo:
cars=[]
def addcar(self,car:Car):
self.cars.append(car)
def get_all_car_info(self):
return self.cars
c=CarInfo()
car=Car('audi','red','100W','400km/h')
print(car) # 看__repr__的呈现效果
c.addcar(car)
print(c.get_all_car_info())
#输出结果如下:
<Car,audi,red,400km/h,100W>
[<Car,audi,red,400km/h,100W>]
四、温度的转换处理
思路:温度转换可以使用实例的方法,也可以使用类方法(不创建对象,直接进行温度转换计算,这个类设计就像把温度转换工具做了一个大集合,封装成一个类),因此用classmethod和staticmethod就很合适,里面都不用构造__init__函数。
# 把convert函数作为内部函数供这6个快捷函数使用,真正转换用convert这个内部函数
class Temperature:
def c2f(self):
pass
def f2c(self,f):
return (f-32)*5/9
def c2k(self.c):
return c+273.15
def k2c(self.k):
return k-273.15
def k2f(self):
pass
def f2k(self):
pass
def _convert(self,temperature,mode) #mode='k' or 'c'
pass
另一种思考:先给一个温度值和单位
然后把温度都转换为中间量-摄氏度,再计算其他单位的温度值。
class Temperature:
def __init__(self,t,unit='c'):
self._c=None
self._f=None
self._k=None
if unit =='k':
self._k=t
self._c=self.k2c(t)
elif unit =='f':
self._f=t
self._c=self.f2c(t)
else:
self._c=t
#定义这3个property函数时因为考虑到用户更喜好t.c,t.k,t.f这样的方式调用,为防止初始化定义的属性和这里的函数重名、出现歧义和递归调用,将原属性加上下划线,统一改变命名可在选中名字后用pycharm中的右键Refactor-Rename,
@property
def c(self):
return self._c
@property
def k(self):
if self._k is None:
self._k=self.c2k(self._c)
return self._k
@property
def f(self):
if self._f is None:
self._k=self.c2f(self._c)
return self._f
@classmethod
def c2f(cls,c):
return 9*c/5+32
@classmethod
def f2c(cls,f):
return 5*(f-32)/9
@classmethod
def c2k(cls,c):
return c+273.15
@classmethod
def k2c(cls,k):
return k-273.15
@classmethod
def f2k(cls,f):
return cls.c2k(cls.f2c(f))
@classmethod
def k2f(cls,k):
return cls.c2f(cls.f2c(k))
print(Temperature.c2f(40))
print(Temperature.c2k(40))
print(Temperature.f2c(104))
print(Temperature.k2c(313.15))
print(Temperature.k2f(313.15))
print(Temperature.f2k(104))
t=Temperature(37)
print(t.c,t.k,t.f)
五、模拟购物车购物
#By me
class ShoppingCart:
def __init__(self,cart={},prices=0):
self.cart=cart
self.prices=prices
def buying(self,products):
for name,price,number in products:
self.cart[(name,price)]=self.cart.get((name,price),0)+number
self.prices+=price*number
return print('Cart has {}, all prices are {}.'.format(self.cart,self.prices))
class Product:
def __init__(self,name,price,number):
self.name=name
self.price=price
self.number=number
def inf(self):
return self.name,self.price,self.number
things=(Product('A',10,3).inf(),Product('B',20,2).inf(),Product('C',50,1).inf())
tom=ShoppingCart().buying(things)
#Teacher Wayne
class Item: #商品类
def __init__(self,**kwargs): #
self.__spec=kwargs
def __repr__(self):
return str(sorted(self.__spec.items()))
class Cart:
def __init__(self):
self.items=[]
def additem(self,item:Item):
self.items.append(item)
def getallitems(self):
return self.items
mycart=Cart()
myphone=Item(mark='Huawei',memory='4G')
mycart.additem(myphone)
mycar=Item(mark='Audi',year='2018')
mycart.additem(mycar)
print(mycart.getallitems())
#运行结果:
[[('mark', 'Huawei'), ('memory', '4G')], [('mark', 'Audi'), ('year', '2018')]]
六、二分法插入
# 算法实现:核心是折半至重合为止
src1=[37,25,99,73,48,47,40,40,25,99,51]
src2=[20,40,41,100]
orderlist=sorted(src1)
def insert_sort(orderlist,i):
ret=orderlist
low=0
high=len(ret) #注意insert插入索引应大于总长(尾部追加),否则low和high最多都只能取到length-1
while low<high:
mid=(low+high)//2
if orderlist[mid]<i:
low=mid+1
else:
high=mid
ret.insert(low,i)
return ret
for x in src2:
print(insert_sort(orderlist,x))
应用案例:
import bisect
def get_grade(score):
breakpoints=[60,70,80,90,100]
grades='EDCBA'
return grades[bisect.bisect(breakpoints,score)]
for student in (91,82,32,65,70,80,60):
print('{} -> {}'.format(student,get_grade(student)))
# 运行结果:
91 -> A
82 -> B
32 -> E
65 -> D
70 -> C
80 -> B
60 -> D