微信公众号:码农充电站pro
我的主页:https://codeshellme.github.iohtml
那些能用计算机迅速解决的问题,就别用手作了。
—— Tom Duffpython
目录
git
上一节 咱们介绍了Python 面向对象
的相关概念,咱们已经知道类与对象
是面向对象编程
中很是重要的概念。github
类就是一个模板
,是抽象的。对象是由类建立出来的实例,是具体的。由同一个类建立出来的对象拥有相同的方法
和属性
,但属性的值能够是不一样的。不一样的对象是不一样的实例,互不干扰。shell
以下,是一个最简单的类,其实是一个空类
,不能作任何事情:编程
class People: pass
在Python 中定义一个类,须要用到class
关键字,后边是类名
,而后是一个冒号:
,而后下一行是类中的代码,注意要有缩进
。微信
People
虽然是一个空类
,但依然能够建立对象,建立一个对象的语法为:数据结构
对象名 = 类名(参数列表)
参数列表是跟__init__
构造方法相匹配的,若是没有编写__init__
方法,建立对象时,就不须要写参数,以下:函数
>>> p = People() >>> p <__main__.People object at 0x7fd30e60be80> >>> >>> p1 = People() >>> p1 <__main__.People object at 0x7fd30e60be48>
p
和 p1
都是People
类的对象。0x7fd30e60be80
是p
的地址,0x7fd30e60be48
是p1
的地址。能够看到不一样的对象的地址是不一样的,它们是两不一样的实例,互不干扰。this
类中能够包含属性
(类中的变量
),建立出来的对象就会拥有相应的属性,每一个对象的属性的值能够不一样。
建立好对象后,能够用以下方法给对象添加属性:
>>> p = People() >>> p.name = '小明' # 添加 name 属性 >>> p.sex = '男' # 添加 sex 属性 >>> p.name # 访问对象的属性 '小明' >>> p.sex # 访问对象的属性 '男'
虽然在技术上能够这样作,可是通常状况下,咱们并不这样为对象添加属性,这样会破坏类的封装性
,使得代码混乱,不利于维护。
当访问一个不存在的属性时,会出现异常:
>>> p.job # 一个不存在的属性 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'People' object has no attribute 'job'
咱们通常会在__init__
方法中为类添加属性并赋值。
__init__
方法在Python 的类中,以双下划线__
开头和结尾的方法,被称为魔法方法
,每一个魔法方法都有特定的含义。Python 为咱们规定了一些魔法方法,让咱们本身实现这些方法。
__init__
方法叫作构造方法
,用来初始化对象。Python 解释器会在生成对象
时,自动执行构造方法,而无需用户显示调用。
__init__
方法不须要有返回值。
类中的全部实例方法
方法,都至少有一个参数,就是self
。Python 中的self
至关于C++ 和Java 中的this
指针,都是表明当前对象。只是Python 中的self
须要显示写在方法的第一个参数,而this
指针则不须要写在方法参数中。
构造方法通常用于初始化对象的一些属性,构造函数能够不写,也能够只有一个self
参数。
当构造函数只有一个self
参数时,建立该类的对象时,不须要添加参数。当构造函数除了self
参数还有其它参数时,建立该类的对象时,则须要添加相匹配的参数。
好比,咱们定义一个People
类,它有三个属性,分别是name
,sex
,age
:
class People: def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age print('执行了 __init__ 方法') def print_info(self): print('people:%s sex:%s age:%s' % ( self.name, self.sex, self.age))
在这个People
类中除了有一个__init__
方法外,还有一个print_info
方法,每一个方法中的都有self
参数,而且是第一个参数,self
表明当前对象。
在建立该类的对象时,须要传递匹配的参数(self
参数不用传递):
>>> p = People('小明', '男', 18) 执行了 __init__ 方法 >>> p <People.People object at 0x7feb6276bda0> >>> p.print_info() people:小明 sex:男 age:18 >>> >>> p1 = People('小美', '女', 18) 执行了 __init__ 方法 >>> p1 <People.People object at 0x7fd54352be48> >>> p1.print_info() people:小美 sex:女 age:18
能够看到,在建立p
和p1
对象时,字符串执行了 __init__ 方法
被打印了出来,而咱们并无显示调用该方法,说明__init__
方法被默认执行了。
对象p
和p1
是两个不一样的对象,拥有相同的属性和方法,可是属性值是不同的。两个对象互不干扰,对象p
的地址为0x7feb6276bda0
,p1
的地址是0x7fd54352be48
。
执行代码p.print_info()
,是调用p
对象的print_info()
方法,由于,在定义该方法的时候,只有一个self
参数,因此在调用该方法的时候,不须要有参数。
私有属性
普通的属性,就像上面的name
,sex
和age
属性,都是公有属性
,在类的外部均可以被任意的访问,就是能够用对象.属性名
的方式来访问属性,以下:
>>> p = People('小明', '男', 18) 执行了 __init__ 方法 >>> p.name # 访问属性 '小明' >>> p.name = '小丽' # 修改属性 >>> p.name # 访问属性 '小丽'
这样就破坏了数据的封装性
,这种访问方式是不可控(会不受限制的被任意访问)的,不利于代码的维护,不符合面向对象的编程规范。
因此,一般咱们会将类中的属性,改成私有属性
,就是不能以对象.属性名
这样的方式访问类属性。
在Python 中,经过在属性名的前边添加双下划线__
,来将公有属性
变为私有属性
,以下:
#! /usr/bin/env python3 class People: def __init__(self, name, sex, age): self.__name = name # 两个下划线 self.__sex = sex # 两个下划线 self._age = age # 一个下划线 print('执行了 __init__ 方法') def print_info(self): print('people:%s sex:%s age:%s' % ( self.__name, self.__sex, self._age))
这样就没法经过对象.属性名
的方式来访问属性了,以下:
>>> p = People('小美', '女', 18) 执行了 __init__ 方法 >>> p.__name # 出现异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'People' object has no attribute '__name'
可是,Python 中这种私有属性
的方式,并非真正的私有属性,Python 只是将__name
转换为了_People__name
,便是在__name
的前边加上了_类名
(_People
),咱们依然能够这样访问__name
属性:
>>> p._People__name '小美'
但咱们并不提倡这种方式,这会让代码变得混乱难懂。
能够注意到,People
类中的_age
属性是以单下划线开头的,这种以单下划线开头的属性是能够在类的外部被访问的:
>>> p._age 18
可是根据Python 规范,以单下划线开头的属性,也被认为是私有属性
,也不该该在类的外部访问(虽然在技术上是能够访问的)。
注意:以双下划线
__
开头且结尾的属性__xxx__
,是特殊属性
,是公有的,可在类的外部访问
私有方法
私有方法与私有属性相似,也能够在方法名的前边加上双下划线__
,来将某个方法变成私有的,通常不须要被外部访问的方法,应该将其设置为私有方法
。
set
和 get
方法为了数据的封装性
,咱们不该该直接在类的外部以对象.属性名
的方式访问属性,那么若是咱们须要访问类的属性该怎么办呢?
这时咱们须要为每一个私有属性都提供两个方法:
为了减小代码量,这里只为__name
属性设置了这两个方法,代码以下:
#! /usr/bin/env python3 class People: def __init__(self, name, sex, age): self.__name = name self.__sex = sex self._age = age print('执行了 __init__ 方法') def print_info(self): print('people:%s sex:%s age:%s' % ( self.__name, self.__sex, self._age)) # set 和 get 方法 def set_name(self, name): self.__name = name def get_name(self): return self.__name
用户能够这样设置和访问类的属性:
>>> from People import People >>> p = People('小美', '女', 18) 执行了 __init__ 方法 >>> p.get_name() # 获取 name 值 '小美' >>> p.set_name('小丽') # 设置新的值 >>> p.get_name() # 再次获取name 值 '小丽'
由于这种set
和 get
方法,是由类的开发者提供的,是被开发者控制的。
类的开发者会根据须要,来控制类的使用者如何使用该类,即哪些类的属性和方法应该被使用者访问,以及如何被使用者访问。
如此,类的使用者就不能随便的访问类中的属性,这就达到了封装
的目的。
(完。)
推荐阅读:
Python 简明教程 --- 14,Python 数据结构进阶
Python 简明教程 --- 16,Python 高阶函数
Python 简明教程 --- 17,Python 模块与包
Python 简明教程 --- 18,Python 面向对象
欢迎关注做者公众号,获取更多技术干货。