面向对象
Python中把具有相同属性和方法的对象归为一个类。
class ClassName:
语句
class Myclass: # 定义类Myclassdef pp(self): # 定义方法pp()print("这是产品说明书")myclass = Myclass() # 实例化类Myclass
myclass.pp() # 调用Myclass中的方法pp()打印文本信息
类是对象的抽象,而对象是类的具体实例。
class SmplClass:def info(self):print('abc')def mycacl(self,x,y):return x+ysc = SmplClass()
print('我的微信账号是:')
sc.info()
print('我的余额是:')
print(sc.mycacl(300,4),'元')
构造方法__init__()
class Complex:def __init__(self,XX,SX):self.r = XXself.i = SX
print('一碗米线的利润')
x = Complex(0.1,2.4)
print("在",x.r,'到',x.i,'之间')
构造方法用于类实例化时初始化相关数据,如果在这个方法中有相关参数,则实例化时就必须提供。
如果类中定义了__init__()方法,那么类的实例化操作会自动调用__init__()方法。
class Dog:def __init__(self,name,age):self.name = nameself.age = agedef wang(self):print(self.name.title()+"旺旺") # title()方法,首字母大写def shen(self):print(self.name.title()+"伸舌头")my_dog = Dog("将军",6)
your_dog = Dog("锤石", 3)print("我宠物的名字是" +my_dog.name.title()+'.')
print("我宠物已经"+str(my_dog.age)+"岁了")print("你宠物的名字是" +your_dog.name.title()+'.')
print("你宠物已经"+str(your_dog.age)+"岁了")
私有方法和属性
在python程序中声明的方法,默认都是共有的方法。
私有方法是指只能在声明它的类中调用,不能被外部调用。
想让某个方法为私有,只需将其名称以两个下划线开头即可。
class Site:def __init__(self,name,url):self.name = name # 公共属性self.__url = url # 私有属性def who(self):print('店名:', self.name)print('网址:',self.__url)def __foo(self): # 定义私有方法print('客服旺旺:123XXXX')def foo(self): # 定义公共方法print("联系地址:北京XXXX")self.__foo() # 在类中可以使用x = Site('XXX天猫旗舰店', 'www.XXXX.com')x.who()
x.foo()
# x.__foo() # 报错
__del__()析构方法
class NewClass(object):num_count = 0def __init__(self, name):self.name = nameNewClass.num_count += 1print(name, NewClass.num_count)def __del__(self):NewClass.num_count -=1print("Del",self.name, NewClass.num_count)def test(self):print("aa")aa = NewClass("普通客户")
bb = NewClass("大客户")
cc = NewClass("集团客户")
del aa
del bb
del cc
print('Over')
当使用内置方法del()删除对象时,会调用它本身的析构函数。
另外,当一个对象在某个作用域中调用完毕后,在跳出其作用域时,析构函数也会被调用一次,这样可以使用析构方法__del__()释放内存空间。
实例方法、类方法、静态方法
class Jing:def __init__(self,x = 0):self.x = x@staticmethoddef static_method(): # 定义静态类方法print("地铁即将进站")@classmethoddef class_method(cls): # 定义类方法,默认参数clsprint("请大家注意安全")Jing.static_method() # 没有实例化类,通过类名调用类方法
dm = Jing() # 实例化类
dm.static_method() # 通过类实例调用静态方法
dm.class_method() # 通过类实例调用类方法
实例方法:一般方法,其隐含调用的参数时类的实例。
类方法:隐含调用的参数是类。在定义类方法时,应使用装饰器@classmethod进行修饰,并且必须有默认参数“cls”。
静态方法:没有隐含调用的参数。在定义静态方法时,应该使用修饰符@staticmethod进行修饰,并且没有默认参数。
在调用静态方法和类方法时,可以直接由类名进行调用,在调用前无须实例化类。
也可以使用该类的任意一个实例进行调用。
属性
class Address:detail = "广州"post_code = '510660'def info(self):# print(detail) # 尝试直接访问类变量,报错print(Address.detail)print(Address.post_code)addr1 = Address()
addr1.info()
addr2 = Address()
addr2.info()
Address.detail = "佛山"
Address.post_code = '460110'
addr1.info()
addr2.info()
既可以在构造方法中定义属性,也可以在类中的其他方法中使用定义的属性。
类属性:是同一个类的所有实例所共有的,直接在类体中独立定义,引用格式为“类名.类变量名”,只要是某个实例对其进行了修改,就会影响这类所有其他的实例。
实例属性:同一个类的不同实例,其值是不相关联的,也不会互相影响,定义时格式为“self.属性名”,调用时也使用这个格式。
class Car():def __init__(self, manufacturer, model, year):self.manufacturer = manufacturerself.model = modelself.year = yearself.odometer_reading = 0def get_descriptive_name(self):long_name = str(self.year)+" "+self.manufacturer+" "+self.modelreturn long_name.title()def read_odometer(self):print("目前仪表显示行驶里程是"+str(self.odometer_reading)+"公里!")my_new_car = Car('Benz','E300L',2022)
print(my_new_car.get_descriptive_name())my_new_car.odometer_reading = 12 # 修改属性
my_new_car.read_odometer()
修改属性:通过实例进行修改。通过自定义方法修改。
继承
class Car(): # 父类,必须包含在当前文件中,且位于子类前面def __init__(self,manufacturer, model, year):self.manufacturer = manufacturerself.model = modelself.year = yeardef get_descriptive_name(self):long_name = str(self.year)+" "+self.manufacturer+" "+self.modelreturn long_nameclass Bmw(Car): # 子类def __init__(self,manufacturer,model,year):super().__init__(manufacturer,model,year) # 将父类和子类关联起来。可以让python调用父类Car的方法__init__(),可以让Bmw的实例包含父类Car中的所有属性。my_tesla = Bmw("宝马","525Li","2022款")
print(my_tesla.get_descriptive_name())
类的继承是指新类从已有的类中取得已有的特性,诸如属性、变量和方法等。
类的派生是指从已有的类产生新类的过程,这个已有的类称为基类或者父类,而新类则称为派生类或者子类。
子类不但可以继承使用父类中的数据成员和成员函数,而且也可以增加新的成员。
class ClassName1(ClassName2):
语句
ClassName1表示子类名,ClassName2表示父类名。
如果在父类中有一个方法名,而在子类使用时未指定,python会从左到右进行搜索。也就是说,当方法在子类中未找到时,将从左到右查找父类中是否包含该方法。
class Car():def __init__(self,manufacturer, model, year):self.manufacturer=manufacturerself.model = modelself.year = yearself.odometer = yeardef get_discriptive_name(self):long_name = str(self.year)+" "+ str(self.manufacturer)+" "+self.modelreturn long_name.title()class Bmw(Car):def __init__(self,manufacturer,model,year): super().__init__(manufacturer,model,year)self.Motor = Motor() # 每当方法__init__()被调用时都会执行这个操作,所以每个Bmw实例中都包含一个自动创建的Motor实例。class Motor(Bmw):def __init__(self,Motor_size=60):self.Motor_size = Motor_sizedef describe_motor(self):print("这款车的发动机参数是"+ str(self.Motor_size)+"24马力,3.0T涡轮增压,功率高达225KW。")my_tesla = Bmw("宝马","535Li","XX款")
print(my_tesla.get_discriptive_name())
my_tesla.Motor.describe_motor()
class PrntOne:namea = "PrintOne"def set_value(self,a):self.a = adef set_namea(self,namea):PrntOne.namea =nameadef info(self):print("PrntOne:%s,%s"%(PrntOne.namea,self.a))class PrntSecond:nameb = 'PrntSecond'def set_nameb(self,nameb):PrntSecond.nameb = namebdef info(self):print('Prntsecond:%s'%(PrntSecond.nameb))class Sub(PrntOne, PrntSecond):pass
class Sub2(PrntOne, PrntSecond):pass
class Sub3(PrntOne, PrntSecond):def info(self):PrntOne.info(self)PrntSecond.info(self)print('使用第一个子类:')
sub = Sub()
sub.set_value('11111')sub.info()
sub.set_nameb('22222')sub.info()
print('使用第二个子类')
sub2 = Sub2()
sub2.set_value('33333')sub2.info()
sub2.set_nameb('44444')sub2.info()
print('使用第三个子类')
sub3=Sub3()
sub3.set_value('55555')sub3.info()
sub3.set_nameb('66666')
sub3.info()
第一个子类Sub先后继承了PrntOne、PrntSecond,在实例化后,先调用PrntOne中的方法。因此在调用info()方法时,由于两个父类中有同名的方法info(),所以实际上调用了PrntOne()中的info()方法,因此只输出了从父类PrntOne中继承的相关信息。
第二个子类Sub2继承的顺序相反,当调用info()方法时,实际上调用的是属于PrntSecond中的info()方法,因此只输出从父类PrntSecond中继承的相关信息。
第三个子类Sub3继承的类及顺序和第一个子类Sub相同,但是修改了父类中info()方法,在其中分别调用了两个父类中的info()方法,因此,每次调用Sub3类实例的info()方法,两个被继承的父类中信息都会输出。
class Wai:def __init__(self,x=0,y=0,color='black'):self.x = xself.y = yself.color = colordef haijun(self,x,y):self.x = xself.y = yprint('发射鱼雷...')self.info()def info(self):print('定位目标:(%d,%d)' % (self.x,self.y))def gongji(self):print("导弹发射!")class FlyWai(Wai):def gongji(self):print("拦截导弹")def fly(self,x,y):print("发射火箭...")self.x = xself.y = yself.info()flyWai = FlyWai(color='red')
flyWai.haijun(100, 200)
flyWai.fly(12,15)
flyWai.gongji()
重载:当子类在使用父类中的方法时,如果发现父类中的方法不符合子类的需求,可以对父类中的方法进行重写。
模块和包
# module_test.py
print('《三体2.黑暗森林》上部 面壁者')
name = '这是小说的第一段'
def m_t_pr():print('序章')
# but.py
import module_test
module_test.m_t_pr()
print("褐蚁已经顽疾这里曾是他的家园。", module_test.name)
外部模块文件和调用文件在同一个目录中。
如果在当前目录没有找到要导入的模块,python解释器会从sys模块中的path变量指定的目录查找要导入的模块。
使用文件__init__.py创建一个包,然后创建多个python程序文件,实现包内成员函数的相互调用。
迭代器
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只能往前不会后退。
每当使用其中的数据时,每次从数据流中取出一个数据,直到数据被取完为止,而且这些数据不会被重复使用。
方法iter():返回对象本身,是for语句使用迭代器的要求。
方法next():用于返回容器中下一个元素或数据,当使用完容器中的数据时会引发StopIteration异常。
class Use:def __init__(self,x=2,max=50):self.__mul,self.__x = x,xself.__max = maxdef __iter__(self): # 定义迭代器协议方法return self # 返回类自身def __next__(self): # 定义迭代器协议方法if self.__x and self.__x != 1:self.__mul *= self.__xif self.__mul <= self.__max:return self.__mulelse:raise StopIterationelse:raise StopIteration
if __name__=='__main__':my = Use()for i in my:print('新专辑签售会的幸运者有:',i,'号')
定义迭代器类Use,在其构造方法中,初始化私有实例属性,功能是生成序列并设置序列中的最大值。这个迭代器总是返回所给整数的n次方,当其最大值超过参数max值时就会引发StopIteration异常。
from random import randint
def guess():return randint(0,10)num = 1
for i in iter(guess, 5):print("第%s次猜测,猜测数字为:%s"%(num, i))num += 1
iter(iterable):要求参数为可迭代类型,也可以使用各种序列类型。
iter(callable, sentinel):callable表示可调用类型,一般为函数;sentinel是一个标记,当第一个参数(函数)调用返回值等于第二个参数的值时,迭代或遍历会马上停止。
生成器
使用关键字yield定义的函数称为生成器。
通过生成器,可以生成一个值的序列用于迭代,并且这个值的序列不是一次生成的,而是使用一个,再生成一个。
def fib(max):a,b = 1,1while a< max:yield a # 当程序运行到yield这行时就不会继续往下执行a,b = b, a+bprint("某代表队金牌榜的变化")
for n in fib(15):print(n)
当向生成器索要一个数时,生成器就会执行,直至出现yield语句时,生成器把yield的参数传出,之后生成器就不会往下继续运行。
当向生成器索要下一个数时,它会从上次的状态开始运行,直至出现yield语句时把参数传出,然后停下。
def shengYield(n):while n>0:print("电梯开始运行...:")yield nprint("刚刚降落了一层!")n -= 1if __name__=="__main__":for i in shengYield(4):print("现在是",i,"楼")print()sheng_yield = shengYield(3)print('已经实例化生成器对象')sheng_yield.__next__() # 直接遍历自己创建的生成器print('第二次调用__next__()方法:')
生成器中包含yield语句时,不但可以用for直接遍历,而且也可以使用手工方式调用其方法__next__()进行遍历。
装饰器
@run_time
def han_fun():
pass
装饰器本质是一个python函数,它可以让其他函数在不需要任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数。
简单地讲,装饰器的作用就是为已经存在的对象添加额外的功能。
def deco(func): # 定义装饰器函数deco()def _deco(a,b):print("在函数myfunc()之前被调用")ret = func(a,b)print("在函数myfunc()之后被调用,结果是:%s"%ret)return _deco@deco
def myfunc(a,b):print("函数myfunc(%s,%s)被调用!"%(a,b))return a+bmyfunc(1, 2)myfunc(3, 4)
def zz(muclass): # 定义一个能够装饰类的装饰器zzclass InnerClass: # 定义一个内嵌类InnerClass来代替被装饰的类def __init__(self,z=0):self.z = 0self.wrapper = muclass() # 实例化被装饰的类def position(self):self.wrapper.position()print('z轴坐标:',self.z)return InnerClass # 返回新定义的类@zz
class coordination:def __init__(self,x = 0,y=0):self.x = xself.y = ydef position(self):print("x轴坐标:",self.x)print("y轴坐标:",self.y)if __name__=="__main__":print('下面是酒店x的3D坐标:')coor = coordination()coor.position()