面向对象
Python中把具有相同属性和方法的对象归为一个类。
class ClassName:
语句
class Myclass: # 定义类Myclass
def 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+y
sc = SmplClass()
print('我的微信账号是:')
sc.info()
print('我的余额是:')
print(sc.mycacl(300,4),'元')
构造方法__init__()
class Complex:
def __init__(self,XX,SX):
self.r = XX
self.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 = name
self.age = age
def 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 = 0
def __init__(self, name):
self.name = name
NewClass.num_count += 1
print(name, NewClass.num_count)
def __del__(self):
NewClass.num_count -=1
print("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
@staticmethod
def static_method(): # 定义静态类方法
print("地铁即将进站")
@classmethod
def class_method(cls): # 定义类方法,默认参数cls
print("请大家注意安全")
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 = manufacturer
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
long_name = str(self.year)+" "+self.manufacturer+" "+self.model
return 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 = manufacturer
self.model = model
self.year = year
def get_descriptive_name(self):
long_name = str(self.year)+" "+self.manufacturer+" "+self.model
return long_name
class 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=manufacturer
self.model = model
self.year = year
self.odometer = year
def get_discriptive_name(self):
long_name = str(self.year)+" "+ str(self.manufacturer)+" "+self.model
return 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_size
def 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 = a
def set_namea(self,namea):
PrntOne.namea =namea
def info(self):
print("PrntOne:%s,%s"%(PrntOne.namea,self.a))
class PrntSecond:
nameb = 'PrntSecond'
def set_nameb(self,nameb):
PrntSecond.nameb = nameb
def 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 = x
self.y = y
self.color = color
def haijun(self,x,y):
self.x = x
self.y = y
print('发射鱼雷...')
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 = x
self.y = y
self.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,x
self.__max = max
def __iter__(self): # 定义迭代器协议方法
return self # 返回类自身
def __next__(self): # 定义迭代器协议方法
if self.__x and self.__x != 1:
self.__mul *= self.__x
if self.__mul <= self.__max:
return self.__mul
else:
raise StopIteration
else:
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,1
while a< max:
yield a # 当程序运行到yield这行时就不会继续往下执行
a,b = b, a+b
print("某代表队金牌榜的变化")
for n in fib(15):
print(n)
当向生成器索要一个数时,生成器就会执行,直至出现yield语句时,生成器把yield的参数传出,之后生成器就不会往下继续运行。
当向生成器索要下一个数时,它会从上次的状态开始运行,直至出现yield语句时把参数传出,然后停下。
def shengYield(n):
while n>0:
print("电梯开始运行...:")
yield n
print("刚刚降落了一层!")
n -= 1
if __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+b
myfunc(1, 2)
myfunc(3, 4)
def zz(muclass): # 定义一个能够装饰类的装饰器zz
class InnerClass: # 定义一个内嵌类InnerClass来代替被装饰的类
def __init__(self,z=0):
self.z = 0
self.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 = x
self.y = y
def position(self):
print("x轴坐标:",self.x)
print("y轴坐标:",self.y)
if __name__=="__main__":
print('下面是酒店x的3D坐标:')
coor = coordination()
coor.position()