Python之面向对象
Posted foxshu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python之面向对象相关的知识,希望对你有一定的参考价值。
1.面向对象相关的几个名词
类:具有相同特征的一类事物。
对象:也就是实例,具体的事物,例如动物类,那么猫就是对象,具体的实例。
实例化:创建对象的过程,类---->对象。
类的三要素:
类名:类事物的名字。
属性:类事物具体的特征。
方法:类事物具体的行为。
2.定义类
类名的命名规则要符合大驼峰命名法,格式如下:
class 类名:
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
1 class Animal: 2 3 def eat(self,name): 4 print("%s会吃"% name) 5 6 def run(self,name): 7 print("%s会跑"% name)
3.创建对象
对象变量 = 类名(),调用有参数的方法即可。
1 class Animal: 2 3 def eat(self): 4 print("会吃") 5 6 def run(self): 7 print("会跑") 8 9 tom = Animal() 10 tom.eat() 11 tom.run() 12 结果: 13 会吃 14 会跑
4.初始化方法
当一个对象创建后,会自动执行以下操作:
为对象在内存中分配空间。
为对象的属性设置初始值。
同时__init__方法被自动调用。
1 class Animal: 2 3 def __init__(self): 4 self.name = "汤姆" 5 self.age = "2岁" 6 print("检测是否被自动调用...") 7 8 def eat(self): 9 print("会吃") 10 11 def run(self): 12 print("会跑") 13 14 tom = Animal() 15 print(tom) 16 print(tom.name) 17 print(tom.age) 18 结果: 19 检测是否被自动调用... 20 <__main__.Animal object at 0x0000013AB6F04160> 21 汤姆 22 2岁
5.__init__方法内部定义属性
上述定义的属性过于死板,可传入形参,此时在创建方法时直接传入属性值即可,且在对象内部可直接访问的对象的属性。
1 class Animal: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 7 def eat(self): 8 print("会吃") 9 10 def run(self): 11 print("会跑") 12 13 tom = Animal("汤姆","2岁") 14 print(tom.name,tom.age) 15 结果: 16 汤姆 2岁
属性可以在类的外部设置,但是如果调用属性在设置前面,则会报错,故不建议在类的外部设置类的属性。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("会吃") 8 9 def run(self): 10 print("会跑") 11 12 tom = Animal("汤姆") 13 print(tom.name) 14 # print(tom.age) #结果:AttributeError: ‘Animal‘ object has no attribute ‘age‘ 15 tom.age = "2岁" 16 print(tom.age) 17 结果: 18 汤姆 19 2岁
在对象方法内部,可以访问对象的属性。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 tom = Animal("汤姆") 13 tom.eat() 14 tom.run() 15 结果: 16 汤姆会吃 17 汤姆会跑
同一个类创建的多个对象之间,属性互不干扰。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 jerry = Animal("杰瑞") 13 tom = Animal("汤姆") 14 tom.eat() 15 tom.run() 16 jerry.eat() 17 jerry.run() 18 结果: 19 汤姆会吃 20 汤姆会跑 21 杰瑞会吃 22 杰瑞会跑
一个对象的属性可以是另一个类创建的对象。
1 class Animal: 2 3 def __init__(self,name,cat_lihua): 4 self.name = name 5 self.cat_type = cat_lihua 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 class Type_cat: 13 14 def __init__(self,name): 15 self.name = name 16 17 def catch(self): 18 print("%s是%s,会抓老鼠..."%(tom.name,self.name)) 19 20 cat_lihua = Type_cat("狸花猫") 21 tom = Animal("汤姆",cat_lihua) 22 tom.cat_type.catch() 23 结果: 24 汤姆是狸花猫,会抓老鼠...
6.__del__方法
当一个对象被从内存中销毁前,会自动调用__del__方法,del 对象名,可以删除一个对象。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 def __del__(self): 13 print("检测是否有调用...") 14 15 tom = Animal("汤姆") 16 print("abc") 17 del tom #删除 tom对象时,立即执行了 __del__方法... 18 print("123") 19 结果: 20 abc 21 检测是否有调用... 22 123
__del__是对象在生命周期内调用的最后一个方法,如果对一个对象在销毁前有需求,可以使用。
7.__str__方法
当print(对象名)时,默认情况下,会显示的是对象的类,以及以十六进制表示的内存中的地址,而__str__方法就是自定义print(对象名)现实的内容,此方法返回的必须是字符串。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 def __del__(self): 13 print("检测是否有调用...") 14 15 def __str__(self): 16 return "检测print(对象名)是否自定义修改..." 17 18 tom = Animal("汤姆") 19 print(tom) 20 结果: 21 检测print(对象名)是否自定义修改...
8.继承
子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发。
子类中应该根据职责,封装子类特有的属性和方法。
继承的传递性,即子类不仅拥有父类的方法和属性,还拥有父类的父类的属性和方法。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 def __str__(self): 13 return "检测print(对象名)是否自定义修改..." 14 15 class Cat(Animal): 16 17 18 def catch(self): 19 print("会抓老鼠...") 20 21 tom = Cat("汤姆") 22 tom.eat() #Cat类继承自父类Animal的方法 23 tom.run() #Cat类继承自父类Animal的方法 24 tom.catch() #Cat类特有方法 25 结果: 26 汤姆会吃 27 汤姆会跑 28 会抓老鼠...
9.方法的重写
当父类的方法实现不能满足子类需求时,可以对方法进行重写。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 13 class Cat(Animal): 14 15 def catch(self): 16 print("会抓老鼠...") 17 18 def eat(self): 19 print("%s吃鱼"% tom.name) 20 21 tom = Cat("汤姆") 22 tom.eat() 23 结果: 24 汤姆吃鱼
当父类的方法同样有需求,但还有其他需求时,可调用父类的方法的同时,再进行扩展。
1 class Animal: 2 3 def __init__(self,name): 4 self.name = name 5 6 def eat(self): 7 print("%s会吃"% self.name) 8 9 def run(self): 10 print("%s会跑"% self.name) 11 12 13 class Cat(Animal): 14 15 def catch(self): 16 print("会抓老鼠...") 17 18 def eat(self): 19 super().eat() 20 print("%s吃鱼"% tom.name) 21 22 tom = Cat("汤姆") 23 tom.eat() 24 结果: 25 汤姆会吃 26 汤姆吃鱼
10.私有属性和方法
私有属性、方法就是对象不希望公开的属性、方法,在属性名和方法名前加两个下划线,定义的就是私有属性或方法,在类的外部无法访问,在对象的方法内部可以访问。
1 class Animal: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.__age = age 6 7 def eat(self): 8 print("%s会吃"% self.name) 9 10 def __run(self): 11 print("%s会跑"% self.name) 12 13 tom = Animal("汤姆","2岁") 14 print(tom.name) 15 # print(tom.age) #结果:AttributeError: ‘Animal‘ object has no attribute ‘age‘ 16 tom.eat() 17 # tom.run() #结果:AttributeError: ‘Animal‘ object has no attribute ‘run‘ 18 结果: 19 汤姆 20 汤姆会吃
子类对象不能在自己的方法内部,直接访问父类的私有属性或方法,可以在自己的内部访问父类的共有属性和公有方法。
1 class Animal: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.__age = age 6 7 def eat(self): 8 print("%s会吃"% self.name) 9 10 def __run(self): 11 print("%s会跑"% self.name) 12 13 class Cat(Animal): 14 15 def catch(self): 16 print("%s是狸花猫..."% self.name) 17 # print("%s%s了"%(self.name,self.age)) #结果:AttributeError: ‘Cat‘ object has no attribute ‘age‘ 18 19 tom = Cat("汤姆","2岁") 20 tom.catch() 21 tom.eat() 22 # tom.__run() #结果:AttributeError: ‘Cat‘ object has no attribute ‘__run‘ 23 结果: 24 汤姆是狸花猫... 25 汤姆会吃
父类内部可以调用自己的私有属性和方法,子类可以调用父类的公有属性和方法,所以我们可以间接调用父类的私有属性和方法。即我们在父类的公有方法中调用其私有方法,子类中调用父类公有方法,从而达到调用父类私有方法的目的。
1 class Animal: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.__age = age 6 7 def eat(self): 8 print("%s会吃"% self.name) 9 10 def __run(self): 11 print("%s会跑"% self.name) 12 13 def run(self): 14 self.__run() 15 print("%s%s了"%(self.name,self.__age)) 16 17 18 class Cat(Animal): 19 20 def catch(self): 21 print("%s是狸花猫..."% self.name) 22 23 tom = Cat("汤姆","2岁") 24 tom.run() 25 结果: 26 汤姆会跑 27 汤姆2岁了
11.多继承
子类可以拥有多个父类,并且具有所有父类的属性和方法,尽量避免父类之间出现同名的属性和方法。
1 class A: 2 3 def foo(self): 4 print("fool A...") 5 6 def bar(self): 7 print("bar A...") 8 9 10 class B: 11 12 def foo(self): 13 print("fool B...") 14 15 def bar(self): 16 print("bar B...") 17 18 19 class C(A,B): 20 pass 21 22 cc = C() 23 cc.foo() 24 cc.bar() 25 结果: 26 fool A... 27 bar A... 28 29 30 ----------分割线----------- 31 class A: 32 33 def foo(self): 34 print("fool A...") 35 36 def bar(self): 37 print("bar A...") 38 39 40 class B: 41 42 def foo(self): 43 print("fool B...") 44 45 def bar(self): 46 print("bar B...") 47 48 49 class C(B,A): 50 pass 51 52 cc = C() 53 cc.foo() 54 cc.bar() 55 结果: 56 fool B... 57 bar B...
当拥有多个父类,且具有相同方法和属性时,调用时不易区分调用的是哪个父类的方法,可用__mro__方法搜素查找调用父类方法的顺序。
12.新式类和经典类
新式类:以object为基类的是新式类,具有object类的内置封装的方法,推荐使用。
经典类:不以object为基类的类。
13.多态
不同的子类对象调用相同的父类方法,产生不同的执行结果,多态是以继承和重写父类方法为前提下,同一个方法会产生不同的形态。
14.类属性
在类中定义属性,通常用来记录与类有关的特征,类属性不会记录具体对象的特征。
有两种访问方法:
类名.属性名
对象名.属性名 (不推荐使用)
1 class Animal: 2 count = 0 3 4 def __init__(self,name,age): 5 self.name = name 6 self.age = age 7 Animal.count += 1 8 9 def eat(self): 10 print("%s贼贪吃..."% self.name) 11 12 dog = Animal("金毛","1岁") 13 cat = Animal("汤姆","2岁") 14 print(Animal.count) 15 print(dog.count) 16 print(cat.count) 17 结果: 18 2 19 2 20 2
两种方法仅仅访问时,都能达到效果。但是当用 对象名.属性名 访问方法给类属性赋值时,会在对象中重新创建一个与类属性名相同的 对象属性,并且将值赋予对象属性,故不推荐使用。
1 class Animal: 2 count = 0 3 4 def __init__(self,name,age): 5 self.name = name 6 self.age = age 7 Animal.count += 1 8 9 def eat(self): 10 print("%s贼贪吃..."% self.name) 11 12 dog = Animal("金毛","1岁") 13 cat = Animal("汤姆","2岁") 14 cat.count = 10 15 print(Animal.count) 16 print(dog.count) 17 print(cat.count) 18 结果: 19 2 20 2 21 10
15.类方法
如果一个方法内部值需要访问类属性时,即可定义成类方法。
语法格式:
@classmethod
def 类方法名(cls):
pass
1 class Animal: 2 count = 0 3 4 def __init__(self,name,age): 5 self.name = name 6 self.age = age 7 Animal.count += 1 8 9 def eat(self): 10 print("%s贼贪吃..."% self.name) 11 12 @classmethod 13 def obj_num(cls): 14 print("创建的对象数:%s"%Animal.count) 15 16 dog = Animal("金毛","1岁") 17 cat = Animal("汤姆","2岁") 18 Animal.obj_num() 19 cat.obj_num() 20 结果: 21 创建的对象数:2 22 创建的对象数:2
16.静态方法
如果一个方法内部既不需要访问实例属性或者调用实例方法,也不需要访问类属性或者调用类方法,此时,可以把这个方法封装成一个静态方法。
@staticmethod
def 静态方法():
pass
调用静态方法时不用创建对象,通过 类名.静态方法名() 调用即可。
1 class Animal: 2 count = 0 3 4 def __init__(self,name,age): 5 self.name = name 6 self.age = age 7 Animal.count += 1 8 9 def eat(self): 10 print("%s贼贪吃..."% self.name) 11 12 @classmethod 13 def obj_num(cls): 14 print("创建的对象数:%s"%cls.count) 15 16 @staticmethod 17 def fun(): 18 print("静态方法...") 19 20 Animal.fun() 21 结果: 22 静态方法...
17.单例模式
目的:让类在创建对象时,系统中只存在唯一的一个实例,即每次执行时,返回对象的地址都是相同的。
正常情况,每创建一个对象,其地址都是不同的。
1 class Animal: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 7 cat = Animal("汤姆","2岁") 8 dog = Animal("二哈","1岁") 9 print(cat) 10 print(dog) 11 结果: 12 <__main__.Animal object at 0x000001C3BDAA9550> 13 <__main__.Animal object at 0x000001C3BDAB42B0>
1)__new__方法
我们知道,当创建一个对象时,python解释器会自动执行两个方法,__new__方法为对象分配空间,__init__方法初始化对象。
__new__方法是一个静态方法,为对象在内存中分配空间,并且返回对象的引用。
2)重写__new__方法
重写时,要调用父类方法,赋值给一个变量,再将变量返回。固定的代码。
1 instance = None 2 def __new__(cls, *args, ""kwargs): 3 if isstance is None: 4 cls.instance = super().__new__(cls) 5 return cls.instance
1 class Animal: 2 3 def __init__(self,name,age): 4 self.name = name 5 self.age = age 6 print("检测__init__方法调用次数...") 7 8 instance = None 9 10 def __new__(cls, *args, **kwargs): 11 if cls.instance is None: 12 cls.instance = super().__new__(cls) 13 return cls.instance 14 15 cat = Animal("汤姆","2岁") 16 dog = Animal("二哈","1岁") 17 print(cat) 18 print(dog) 19 结果: 20 检测__init__方法调用次数... 21 检测__init__方法调用次数... 22 <__main__.Animal object at 0x0000021187C84160> 23 <__main__.Animal object at 0x0000021187C84160>
重写__new__方法后,不管创建多少个对象,返回的地址都是创建的第一个对象的地址,但是__init__方法每创建一个对象会初始化一次。我们可以设置一个 类属性,将False 赋值给他,然后在__init__方法内用if判断,如果为False则执行初始化方法,执行后将类属性的值改为True,再次调用__init__方法时就不会被多次执行。
1 class Animal: 2 3 init_fun = False 4 5 def __init__(self,name,age): 6 if Animal.init_fun is False: 7 self.name = name 8 self.age = age 9 print("检测__init__方法调用次数...") 10 Animal.init_fun = True 11 return 12 13 instance = None 14 15 def __new__(cls, *args, **kwargs): 16 if cls.instance is None: 17 cls.instance = super().__new__(cls) 18 return cls.instance 19 20 cat = Animal("汤姆","2岁") 21 dog = Animal("二哈","1岁") 22 print(cat) 23 print(dog) 24 结果: 25 检测__init__方法调用次数... 26 <__main__.Animal object at 0x0000022EA09742B0> 27 <__main__.Animal object at 0x0000022EA09742B0>
18.异常
抛出异常:程序执行时遇到一个错误,会停止程序的执行,并且提示一些错误信息。
1 try: 2 pass 3 except 异常类型1: 4 pass 5 except 异常类型2: 6 pass 7 except Excetion as e: 8 print("未知错误,%s",%e) 9 else: #没有出现异常才会执行的代码 10 pass 11 finally: #无论是否有异常,都会执行的代码 12 pass
异常类型为触发异常后抛出的异常信息中的第一个单词,用以捕捉异常。
1 try: 2 int_put = int(input("输入数字>>>")) 3 num = 10 / int_put 4 print(num) 5 except ValueError: 6 print("输入错误的值,请输入数字>>>") 7 except ZeroDivisionError: 8 print("除数为0错误...") 9 except Exception as e: 10 print("未知错误,%s"%e) 11 else: 12 print("没有出现异常才会执行的代码") 13 finally: 14 print("无论是否有异常,都会执行的代码") 15 结果: 16 输入数字>>>10 17 1.0 18 没有出现异常才会执行的代码 19 无论是否有异常,都会执行的代码 20 21 ------------结果分割线 22 23 结果: 24 输入数字>>>0 25 除数为0错误... 26 无论是否有异常,都会执行的代码
1)异常的传递
为了让程序能够正常运行,方法中都应该有异常处理,但是如果每个方法都写入异常处理的代码,太繁琐。事实上,当函数/方法执行 出现异常,会将异常传递给函数/方法的调用一方,如果传递到主程序,仍然没有异常处理,程序才会被终止。即异常具有传递性,所以,当我们再主程序中增加异常处理,就不用每个方法中都增加。
2)主动抛出异常
根据业务需求,会有主动抛出异常的情况,python中提供了Exception类。
1 ex = Exception("xx错误") #创建异常对象,括号内可以用错误信息作为参数 2 raise ex #主动抛出异常
主动抛出异常类似于执行了错误代码,要与捕捉异常一起使用。
以上是关于Python之面向对象的主要内容,如果未能解决你的问题,请参考以下文章