文章预览:
- 章节前导
- 1. 对象魔法
- 1.1 多态
- 1.1.1 多态和方法
- 1.2 封装
- 1.3 继承
- 2. 类
- 2.1 类到底是什么
- 2.2 创建自定义类
- 2.3 属性,函数,方法
- 2.3再谈隐藏
章节前导
在前几章学习了python的内置的主要对象类型(数,字符串,列表,元组和字典),大致了解了众多的内置函数和标准库。还创建了自定义的函数。不过有一点还没有学习,那就是创建自己定义对象。这是接下来的重点。
创建自定义对象(尤其是对象类型或类)是一个python的核心概念。事实上,这个概念非常重要,是的python被视为一种面向对象的语言。
1. 对象魔法
在面向对象编程中。术语对象大致意味着一些列数据(属性)以及一套访问和操作这些数据的方法。使用对象而非全局变量和函数的原因有多个,下面列出了使用对象的最重要的好处。
多态:可对不同类型的对象执行相同的操作,而这些操作就像被施了魔法一样能够正常运行
封装:对外部隐藏有关对象工作原理的细节。
继承:可基于通用类创建出专用类。
1.1 多态
术语多态,意思是多种形态。这大致意味着即便你不知道变量指向的是哪种对象,也能够对其执行操作,且操作的行为将随对象所属类型而异。
1.1.1 多态和方法
你收到一个对象,却根本不知道它是如何实现的——它可能是众多形态中的任何一种。你只知道可以询问其价格,但这就够了。至于询问价格的方式,你应该很熟悉。
f.get_price()
像这样与对象属性相关联的函数称为方法,你在本书前面见过这样的函数:字符串 ,函数,列表和字典的方法。多态你其实也见过。
如果有一个变量x,你无须知道它是字符串还是一个列表就能调用方法count;只要你向这个方法提供一个字符作为参数,它就能正常运行。
下面做个实验代码如下
>>> from random import choice
>>> x=choice(["sdada",[1,2,3]])
>>> x.count(1)
>1
标准库模块random包含一个名为choice的函数,它从序列中随机选择一个元素。
执行这个代码没有报错说明选择的是那个列表,如果选择的是字符串会报错,但是无论字符串还是列表都存在count函数,我们无需关注x到底是什么类型,这就是多态。
1.2 封装
封装指的向外部隐藏不必要的细节。听起来有点像多态,这俩个概念很像,因为它们都是抽象原则。
但封装不同于多态,多态让你无需知道对象所属类(对象的类型)就能调用其方法,而封装让你无需知道对象的构造就能使用它。
1.3 继承
继承是另一种偷懒的方式。程序员总是想避免多次输入同样的代码。如果你已经有了一个类,并要创建一个与之很像的类,该如何办呢,那便是继承
你可能已经有了一个shape类,他知道如何将自己绘制到屏幕上。现在你想创建一个名为Rectangle的类,但他不仅知道如何将自己绘制到屏幕上,而且还有其他新功能。你不想重新编写方法draw,那么就使用继承方法。
2. 类
2.1 类到底是什么
本书前面反复提到了类,并将其用作类型的同义词。从很多方面来说,这正是类的定义——一种对象。每个对象都属于特定的类,并被称为该类的实例。
例如,如果你在窗外看到一只鸟,这只鸟就是鸟类的一个实例。鸟类是一个非常通用(抽象类)的类,他有多个子类:你看到的那只鸟可能属于子类云雀。你可以将鸟类视为所有鸟的集合,而云雀是其中一个子集。一个类的对象为另一个类的对象的子集时,前者就是后者的子集,因此云雀是鸟类的子集,而鸟类为云雀的超类
2.2 创建自定义类
我们终于要创建自定义类了! 下面是一个简单的示例
class person:def set_name(self,name):self.name=namedef get_name(self):return self.namedef greet(self):print("hello world! I'm{}.".format(self.name))s=person()
s.set_name("dasda")
s.greet()
这个示例包含三个方法定义,它们类似于函数定义,但位于class语句内。person当然是类的名称。
class语句创建独立的命名空间,用于在其中定于函数。一切看起来都挺好,但你可能想知道参数self是什么。
通过调用s.set_name(“dasda”)和s.greet()时,s都会作为第一个参数自动传递给它们。我将这个参数命名为self。实际上随便给这个参数命名,但鉴于它总指向对象本身,因此习惯上将其命名为self
显然self很有用,甚至必不可少。如果没有它,所有的方法都无法访问对象本身——要操作的属性所属对象。
2.3 属性,函数,方法
实际上,方法和函数的区别表现在前一节提到的参数self上。方法(更准确地说是关联的方法)将其第一个参数关联到它所属的实力,因此无需提供这个参数。
class Class:def method(self):print("I have a self")
def function():print("I don;t..")
instance=Class()
instance.method()
instance.method=function
instance.method()
运行结果
I have a self
I don;t…
请注意,有没有参数self并不取决于是否以刚才使用的方式(如instace,method)调用方法。实际上,完全可以让另一个变量指向同一方法。
class Bird:song='squaawk!'def sing(self):print(self.song)
bird=Bird()
bird.sing()
birdsong=bird.sing
birdsong()
运行结果:
squaawk!
squaawk!
虽然最后一个方法调用看起来很像函数调用,但变量bird送指向的是关联的方法 bird.sing,这意味着它也能够访问参数self(即它也被关联到类的实例)
2.3再谈隐藏
属性可将其定义为私有,私有属性不能从对象外部访问,只能通过存取器方法来访问。
python没有为私有属性提供直接的支持,而是要求程序员知道在什么情况下从外部修改属性是安全的。毕竟,你必须在知道如何使用对象之后才能使用它。然而,通过玩点小花招,可以获得类似私有属性的效果。
要让方法或属性成为私有的(不能从外边访问),只需让其名称以俩个下划线打头即可。
class f:def __output(self):print('hello world')def public(self):self.__output()
现在从外部不能访问__output,但在类中依然可以使用它。
a=f()
a.__output()
Traceback (most recent call last):File "E:\python\python练习\私有.py", line 9, in <module>a.__output()
AttributeError: 'f' object has no attribute '__output'. Did you mean: '_f__output'?
a.public()
hello world
虽然以俩个下划线打头有点怪异,但这样的方法类似于其他语言的标准私有方法。然而。幕后的处理手法并不标准;在类定义中,对所有以俩个下划线打头的名称都进行了转换,即在开头加上了一个下划线和类名。
只要知道这种幕后处理手法,就能从类外访问私有方法,然而不应这样做,
a._f__output()hello world
总之,你无法禁止别人访问对象的私有方法和属性,但这种名称修改方式发出来强烈的型号,让他们不要这样做。