测试一个对象有多少个引用:
#测试一个对象有多少个引用,用sys.getrefcount()
#如果没有引用则抛异常
import sys
str=10
print(sys.getrefcount(str))
运行结果:17
若没有引用则报异常如下:
Traceback (most recent call last):
File "E:/python-workspace/python/Class/class-5.29.py", line 218, in <module>
print(sys.getrefcount(m))
NameError: name 'm' is not defined
面向对象的三大特征:封装、继承、多态
继承:子类继承父类,子类可以使用父类的属性和方法,简化代码.
当生成子类对象时,先初始化父类对象,所以如果父类有__init__()方法,并且有属性时,要通过子类的构造赋值
一个类可以有多个子类
在子类中,调用父类的属性时,在__init__()方法中使用
给父类传参的四种方式:
父类.属性,或self.属性或父类.__init__(self,参数)或super(父类,self).__init__(参数)四种方法
调用父类方法时:super().父类方法()
总结:当子类继承父类时,子类的构造方法应该包含父类和子类共同的属性,在子类的初始化方法中,将父类的属性传递给父类,子类的属性赋值给子类
方法重写:子类和父类同名不同参,子类重写了父类的方法,当生成子类对象时,调用的是子类重写的方法
如果子类重写的方法想调用父类的方法时,在子类方法中:父类.方法(self)或super().父类方法()
三代继承:子类初始化方法需要祖父类、父类及自己的属性,可以调用父类的初始化方法传参,可重写父类的方法
构造的顺序:祖父类、父类,本类
类继承object
私有属性、私有方法:均不能在类外面被调用
两个下划线开头,声明该方法为私有方法,只能在类的内部调用,不能在类地外部调用。
class JustCounter:
__secretCount = 0 #私有变量
publicCount = 0 #公有变量
def count(self):
self.__secretCount+=1
self.publicCount +=1
print(self.__secretCount)
counter = JustCounter()
counter.count()
print(counter.publicCount)
print(counter._secretCount)
运行结果:Traceback (most recent call last):
1
File"E:/python-workspace/python/Class_5_31/继承.py", line 77, in <module>
1
print(counter._secretCount) #报错,实例不能访问私有变量
AttributeError: 'JustCounter' object has no attribute'_secretCount'
Process finished with exit code 1
多继承:类同时继承多个父类,class C(A,B),当有AB均有相同方法,而子类又重写时,调用谁的方法,如果子类没有方法,则调用哪个父类的方法?A
class Person: def __init__(self,name=None,age=None,sex=None): print("------person") self.name=name self.age=age self.sex=sex def __str__(self): return "我的姓名:{0},我的年龄:{1},我的性别:{2}".format(self.name,self.age,self.sex) class Music: def __init__(self,piano=None): print("-------music") self.piano=piano class Student(Person,Music): def __init__(self,name=None,age=None,sex=None,score=None,piano=None): print("------student") #给父类传参四种方式————————方式一: # Person.name=name #方式二: # Person.__init__(self,name,age,sex,score) #方式三: #self.age=age #self.sex=sex #方式四: super(Student,self).__init__(name,age,sex) self.score=score self.piano=piano def __str__(self): return "我的姓名:{0},我的年龄:{1},我的性别:{2},我的成绩:{3},我喜欢:{4}".format(self.name,self.age,self.sex,self.score,self.piano) stu=Student("Mary",23,"女",88,"钢琴") print(stu)
注意:
1、super().__init__相对于类名.__init__,在单继承上用法基本无差
2、但在多继承上,super保证每个父类只会被重写一次,如果使用类名调用时,就会出现多次调用
3、多继承时,使用super方法,对父类的传参,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错
4、多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因。
类属性和方法
类属性:属于类成员,属于对象共有
类方法:在方法上添加@classmethod
可以通过类方法调用类属性,也可以通过对象调用类属性
__new__(cls):#用来创建对象,而且必须有返回值
return object.__new__(cls)
可以用id(cls)看地址
当有属性时,需要在__new__()中也添加属性
class A: @classmethod def __new__(cls,*args,**kwargs): print("-----new") return object.__new__(cls) @classmethod def test(abc): print("这是一个类方法")
静态方法:方法前加@staticmethod,静态方法没有参数,静态方法既和类没关系,也和对象没关系,也可以通过类和对象调用
@staticmethod def staticmethod(): print("这是一个静态方法")
单例模式:
要点:一是某个类只能有一个实例
二是它必须自行创建这个实例
三是它必须自行向整个系统提供这个实例
#实现__new__方法
#并在将一个类的实例绑定到类变量_instance上,
#如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回
#如果cls._instance不为None,直接返回cls._instance
class SingLeTone: __instance=None def __new__(cls): if cls.__instance==None: cls.__instance=object.__new__(cls) return cls.__instance else: return cls.__instance s=SingLeTone() ss=SingLeTone() print(id(s),id(ss))
运行结果:
91371440 91371440
对象列表排序:重写lt或gt方法
class Car: def __init__(self,brand=None,price=None): self.brand=brand self.price=price def __gt__(self,other): #支持中文排序:用encode()进行编码 return self.brand.encode("gbk")<other.brand.encode("gbk") #return self.price<other.price def __str__(self): return self.brand+str(self.price) lists=[Car("英菲尼迪",300000),Car("奥迪",350000),Car("奔驰",400000)] lists.sort() for i in lists: print(i)
多态
多态(从定义角度触发):同一类事物的多种形态。一个抽象类有多个子类,因而多态的概念依赖于继承
多态性(从使用角度触发):同一种调用方式,不同的执行效果。
class Animal:
def run(self):
raise AttributeError('子类必须实现这个方法')
class People(Animal):
def run(self):
print('人正在走')
class Pig(Animal):
def run(self):
print('pig is walking')
class Dog(Animal):
def run(self):
print('dog is running')
peo1=People()
pig1=Pig()
d1=Dog()
#实例化调用方法得到的结果
#peo1.run()
#pig1.run()
#d1.run()
#多态性:一种调用方式,不同的执行效果(多态性)
# 多态性依赖于:继承
##多态性:定义统一的接口,
def func(obj): #obj这个参数没有类型限制,可以传入不同类型的值
obj.run() #调用的逻辑都一样,执行的结果却不一样
func(peo1)
func(pig1)
func(d1)
多态性的实质:实质就是定义了一个函数接口,在这个函数中定义了所有类通用的函数功能,只要传入参数(即对象名),函数调用执行就能得到不同的结果。上述即一种调用方式,不同的执行结果。
异常:运行期检测到的错误
异常是python对象,表示一个错误
当脚本发生异常时需要捕获并处理,否则程序会终止执行
异常产生的时机,系统产生
异常处理
捕获异常:try/except语句
try..except..else
使用except可不带任何异常类型,也可带多种异常类型
try-finally 语句无论是否发生异常都将执行最后的代码。
eg:
def device():
try:
1/0
except ZeroDivisionError:
print("除数不能为0")
device()
运行结果:除数不能为0
也可用as定义别名,即输出自己的信息。
def device(): try: 1/0 except ZeroDivisionError as zd: print("除数不能为0") print(zd) device()
运行结果:division by zero
触发异常
使用raise语句
语法格式:
raise [Exception [, args [, traceback]]]
语句中Exception是异常类型(例如,NameError)参数标准异常中任一种,args是自已提供的异常参数
最后一个参数是可选的(在实践中很少使用),如果存在,是跟踪异常对象。
用户自定义异常:
创建一个新的异常类,程序可命名自己的异常。异常应该是典型的继承自Exception类,通过直接或间接的方式。
eg:实例中创建了一个类,基类为RuntimeError,用于在异常触发时输出更多的信息。
#自定义异常
class Networkrror(RuntimeError):
def __init__(self,args):
self.args=args
#触发异常
try:
raise Networkrror("Badhostname")
except Networkrror:
print(Networkrror.args)