如何理解 Python 中的面向对象编程?
现如今面向对象编程的使用非常广泛,本文我们就来探讨一下Python中的面向对象编程。作者 |Radek Fabisiak译者 |弯月,责编 | 郭芮出品 | CSDN(ID:CSDNnews)以下为译文:Python支持多种类型的编程范式,例如过程式编程、函数式编程、面向对象编程,而且还可以融合多种类型的范式。现如今面向对象编程的使用非常广泛。面向对象编程的基...
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/e05302bf15c1c109f686893ff6470fd7.gif)
![640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/5a4fdc2ab3ba2dc78c7ed5ca6585d2d1.png)
-
创建Python类
-
数据属性
-
实例方法
-
属性
-
类和静态方法
-
继承
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/fe1bebfcc6b5ca8a354ca8fea2c30183.png)
>>> class MyClass:
... pass
...
按照惯例,Python类的命名采用首字母大写(即PascalCase)。
>>> a = MyClass()
>>> a
<__main__.MyClass object at 0x7f32ef3deb70>
语句a = MyClass()创建了MyClass的一个实例,并将它的引用赋值给变量a。
>>> type(a)
<class '__main__.MyClass'>
>>> a.__class__
<class '__main__.MyClass'>
>>> a.__class__.__name__
'MyClass'
顺便提一句,Python类也是对象。它们是type的实例:
>>> type(MyClass)
<class 'type'>
下面,我们来定义一个方法。
>>> class MyClass:
... def __init__(self, arg_1, arg_2, arg_3):
... print(f'an instance of {type(self).__name__} created')
... print(f'arg_1: {arg_1}, arg_2: {arg_2}, arg_3: {arg_3}')
...
下面,我们来创建一个MyClass实例,看看这个初始化方法的具体工作。我们的.__init__()方法需要三个参数(arg_1、arg_2和arg_3),记住我们不需要传递与self对应的第一个参数。所以,在实例化对象时,我们需要传递三个参数:
>>> a = MyClass(2, 4, 8)
an instance of MyClass created
arg_1: 2, arg_2: 4, arg_3: 8
上述声明产生的结果如下:
-
创建一个MyClass类型的对象的实例。
-
自动调用该实例的方法.__init__()。
-
我们传递给MyClass()方法的参数:(2,4和8)会被传递给.__init__()。
-
.__init__()执行我们的请求,并输出结果。它利用type(self).__name__获取类的名称。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/40fc030759e63eaf44fb234c4685c42c.png)
>>> class MyClass:
... def __init__(self, arg_1, arg_2, arg_3):
... self.x = arg_1
... self._y = arg_2
... self.__z = arg_3
...
现在MyClass有三个数据属性:
-
.x可以获取arg_1的值
-
._y可以获取arg_2的值
-
.__ z可以获取arg_3的值
>>> class MyClass:
... def __init__(self, arg_1, arg_2, arg_3):
... self.x, self._y, self.__z = arg_1, arg_2, arg_3
...
属性名称中的下划线(_)是为了表明这些属性是“私有”属性:
-
开头没有下划线的属性(比如.x)通常可供对象外部的调用和修改。
-
开头拥有一个下划线的属性(比如._y)通常也可以从对象外部调用和修改。然而,下划线是一种惯用的标志,即该类的创建者强烈建议不要使用该变量。应该仅通过类的功能成员(比如方法和属性)调用和修改该变量。
-
开头拥有双下划线的属性(比如.__ z)将在名字修饰过程中被改名(在本例中它将被改名为._MyClass__z)。你也可以通过这个新名称从对象外部调用和修改它们。但是,我强烈反对这种做法。应该尽通过类的功能成员以其原始名称进行调用和修改。
>>> a = MyClass(2, 4, 8)
>>> vars(a)
{'x': 2, '_y': 4, '_MyClass__z': 8}
>>> a.__dict__
{'x': 2, '_y': 4, '_MyClass__z': 8}
名字修饰过程把键'__z'变成了'_MyClass__z'。
>>> a.x
2
>>> a._y
4
>>> a.__z
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyClass' object has no attribute '__z'
>>> a.x = 16
>>> a.x
16
>>> vars(a)
{'x': 16, '_y': 4, '_MyClass__z': 8}
请注意,我们无法访问.__ z,因为.__ dict__没有键'__z'。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/b721cd1340f1485668e190eb09ecea4c.png)
>>> class MyClass:
... def __init__(self, arg_1, arg_2, arg_3):
... self.x, self._y, self.__z = arg_1, arg_2, arg_3
...
... def set_z(self, value):
... self.__z = value
...
... def get_z(self):
... return self.__z
...
>>> b = MyClass(2, 4, 8)
方法.get_z()和.set_z()提供了传统的检索和修改.__ z值的方法:
>>> b.get_z()
8
>>> b.set_z(16)
>>> vars(b)
{'x': 2, '_y': 4, '_MyClass__z': 16}
你也可以在.get_z()和.set_z()中添加其他功能,例如检查数据的有效性。这种方法实现了面向对象编程中的一个主要概念:封装。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/93886f8435dcd82db17494dddcdb51ea.png)
>>> class MyClass:
... def __init__(self, arg_1, arg_2, arg_3):
... self.x, self._y, self.__z = arg_1, arg_2, arg_3
...
... @property
... def z(self):
... return self.__z
...
... @z.setter
... def z(self, value):
... self.__z = value
...
>>> b = MyClass(2, 4, 8)
如下,我们利用相应的属性.z来访问和修改数据属性.__ z:
>>> b.z
8
>>> b.z = 16
>>> vars(b)
{'x': 2, '_y': 4, '_MyClass__z': 16}
这段代码比上述示例更精简优雅。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/59d699b6d8dad72162b4be03dd909eba.png)
>>> class MyClass:
... def __init__(self, arg_1, arg_2, arg_3):
... self.x, self._y, self.__z = arg_1, arg_2, arg_3
...
... def f(self, arg):
... print('instance method f called')
... print(f'instance: {self}')
... print(f'instance attributes:\n{vars(self)}')
... print(f'class: {type(self)}')
... print(f'arg: {arg}')
...
... @classmethod
... def g(cls, arg):
... print('class method g called')
... print(f'cls: {cls}')
... print(f'arg: {arg}')
...
... @staticmethod
... def h(arg):
... print('static method h called')
... print(f'arg: {arg}')
...
>>> c = MyClass(2, 4, 8)
方法.f()是一个实例方法。实例方法的第一个参数是对象本身的引用。这些方法可以利用self访问对象,利用vars(self)或self.__dict__访问对象的数据属性,还可以利用type(self)或self.__class__访问对象对应的类,而且它们还可以拥有自己的参数。
>>> c.f('my-argument')
instance method f called
instance: <__main__.MyClass object at 0x7f32ef3def98>
instance attributes:
{'x': 2, '_y': 4, '_MyClass__z': 8}
class: <class '__main__.MyClass'>
arg: my-argument
通常,我们应该直接通过类(而不是实例)调用类方法和静态方法:
>>> MyClass.g('my-argument')
class method g called
cls: <class '__main__.MyClass'>
arg: my-argument
>>> MyClass.h('my-argument')
static method h called
arg: my-argument
请记住,我们不需要传递类方法的第一个参数:与cls相对应的参数。
>>> c.g('my-argument')
class method g called
cls: <class '__main__.MyClass'>
arg: my-argument
>>> c.h('my-argument')
static method h called
arg: my-argument
当我们调用c.g或c.h,但实例成员没有这样的名称时,Python会搜索类和静态成员。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/704d4e2bf713c39f01915354e1e5af62.png)
>>> class MyOtherClass(MyClass):
... def __init__(self, u, v, w, x, y, z):
... super().__init__(x, y, z)
... self.__u, self.__v, self.__w = u, v, w
...
... def f_(self, arg):
... print('instance method f_ called')
... print(f'instance: {self}')
... print(f'instance attributes:\n{vars(self)}')
... print(f'class: {type(self)}')
... print(f'arg: {arg}')
...
>>> d = MyOtherClass(1, 2, 4, 8, 16, 32)
如上,MyOtherClass拥有MyClass的成员:.x、._y、.__z以及.f()。你可以通过语句super().__init__(x, y, z)初始化基类的数据成员x、._y和.__z,该语句会调用基类的.__init__()方法。
>>> vars(d)
{'x': 8,
'_y': 16,
'_MyClass__z': 32,
'_MyOtherClass__u': 1,
'_MyOtherClass__v': 2,
'_MyOtherClass__w': 4}
我们可以调用基类和派生类中的所有方法:
>>> d.f('some-argument')
instance method f called
instance: <__main__.MyOtherClass object at 0x7f32ef3e7048>
instance attributes:
{'x': 8,
'_y': 16,
'_MyClass__z': 32,
'_MyOtherClass__u': 1,
'_MyOtherClass__v': 2,
'_MyOtherClass__w': 4}
class: <class '__main__.MyOtherClass'>
arg: some-argument
>>> d.f_('some-argument')
instance method f_ called
instance: <__main__.MyOtherClass object at 0x7f32ef3e7048>
instance attributes:
{'x': 8,
'_y': 16,
'_MyClass__z': 32,
'_MyOtherClass__u': 1,
'_MyOtherClass__v': 2,
'_MyOtherClass__w': 4}
class: <class '__main__.MyOtherClass'>
arg: some-argument
但是,如果派生类包含的某个成员与基类同名,则优先使用派生类的成员。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f68d156363c69e16b028b1066d784f50.png)
-
方法:.__repr__()和.__str__()
-
方法:.__new__()
-
操作符
-
方法:.__getattribute__()、.__getattr__()、.__setattr__()和.__delattr__()
-
生成器
-
可调用性
-
创建序列
-
描述器
-
上下文管理
-
抽象类和成员
-
多重继承
-
使用super()
-
拷贝
-
序列化
-
slot
-
类修饰器
-
数据类
【END】
如何在短时间内成为Python工程师?
![640?wx_fmt=jpeg](https://i-blog.csdnimg.cn/blog_migrate/9c559de341d88d59d92f702fc28aeed2.png)
热 文 推 荐
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/4745c549beceff6f6416a40097ce7a04.gif)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/af82729b6750d71f1102b847a172b5ea.png)
更多推荐
所有评论(0)