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 会跑
View Code

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岁
View Code

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岁
View Code

  属性可以在类的外部设置,但是如果调用属性在设置前面,则会报错,故不建议在类的外部设置类的属性。

技术图片
 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岁
View Code

  在对象方法内部,可以访问对象的属性。

技术图片
 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 汤姆会跑
View Code

  同一个类创建的多个对象之间,属性互不干扰。

技术图片
 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 杰瑞会跑
View Code

  一个对象的属性可以是另一个类创建的对象。

技术图片
 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 汤姆是狸花猫,会抓老鼠...
View Code

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
View Code

  __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(对象名)是否自定义修改...
View Code

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 会抓老鼠...
View Code

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 汤姆吃鱼
View Code

  当父类的方法同样有需求,但还有其他需求时,可调用父类的方法的同时,再进行扩展。

技术图片
 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 汤姆吃鱼
View Code

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 汤姆会吃
View Code

  子类对象不能在自己的方法内部,直接访问父类的私有属性或方法,可以在自己的内部访问父类的共有属性和公有方法。

技术图片
 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 汤姆会吃
View Code

  父类内部可以调用自己的私有属性和方法,子类可以调用父类的公有属性和方法,所以我们可以间接调用父类的私有属性和方法。即我们在父类的公有方法中调用其私有方法,子类中调用父类公有方法,从而达到调用父类私有方法的目的。

技术图片
 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岁了
View Code

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...
View Code

  当拥有多个父类,且具有相同方法和属性时,调用时不易区分调用的是哪个父类的方法,可用__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
View Code

  两种方法仅仅访问时,都能达到效果。但是当用 对象名.属性名 访问方法给类属性赋值时,会在对象中重新创建一个与类属性名相同的 对象属性,并且将值赋予对象属性,故不推荐使用。

技术图片
 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
View Code

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
View Code

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 静态方法...
View Code

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>
View Code

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>
View Code

  重写__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>
View Code

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 无论是否有异常,都会执行的代码
View Code

1)异常的传递

  为了让程序能够正常运行,方法中都应该有异常处理,但是如果每个方法都写入异常处理的代码,太繁琐。事实上,当函数/方法执行 出现异常,会将异常传递给函数/方法的调用一方,如果传递到主程序,仍然没有异常处理,程序才会被终止。即异常具有传递性,所以,当我们再主程序中增加异常处理,就不用每个方法中都增加。

2)主动抛出异常

  根据业务需求,会有主动抛出异常的情况,python中提供了Exception类。

1 ex = Exception("xx错误") #创建异常对象,括号内可以用错误信息作为参数
2 raise ex #主动抛出异常

  主动抛出异常类似于执行了错误代码,要与捕捉异常一起使用。

以上是关于Python之面向对象的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段——JS中的面向对象编程

VSCode自定义代码片段9——JS中的面向对象编程

PHP面向对象之选择工厂和更新工厂

python基础之面向对象

Python之面向对象:面向对象基础

python之面向对象编程一