在 Python 中想定义一个类是比较简单的,比如要定义一个 Person 类,如下代码即可:
- # -*- coding: utf-8 -*-
- # __author : Demon
- # date : 1/5/18 8:24 PM
- class Person(object):
- pass
- p1 = Person()
当然我们也可以给类添加相应的属性,比如 Person 的姓名,年龄,性别等,并且在 new 一个 Person 对象后可以对这些属性进行修改,如下代码所示:
- # -*- coding: utf-8 -*-
- # __author : Demon
- # date : 1/5/18 8:24 PM
- class Person(object):
- def __init__(self, name, age, sex):
- self.name = name #姓名
- self.age = age #年龄
- self.sex = sex #性别
- def __str__(self): #定义直接打印Person对象,输出的内容。相当于Java中的toString()方法
- return ('%s , %s , %s ' % (self.name, self.age, self.sex))
- p1 = Person('Demon', 18, 'M')
- print(p1) #Demon , 18 , M
- p1.age = 28 #修改对象的年龄
- print(p1) #Demon , 28 , M
Python 是面向对象的语言,我们都知道面向对象的三大特点:继承、封装和多态。而在上面的代码中,我们可以轻易地通过 person. 调用属性来访问和修改值,这明显不符合面向对象中封装的思想。比如对于 Person 类中的年龄属性,可能比较私人,所以我们不希望可以任意的访问和修改它的值。在 Java 中,我们是通过 private 关键字来装饰属性私有,那么在 Python 中有没有类似的关键字呢?显然是有的,在 Python 中采取在变量名前加__(两个下划线) 的方式来将属性私有。如下代码所示:
- # -*- coding: utf-8 -*-
- # __author : Demon
- # date : 1/5/18 8:24 PM
- class Person(object):
- def __init__(self, name, age, sex):
- self.name = name #姓名
- self.__age = age #年龄,将年龄私有
- self.sex = sex #性别
- def __str__(self): #定义直接打印Person对象,输出的内容。相当于Java中的toString()方法
- return ('%s , %s , %s ' % (self.name, self.__age, self.sex))
- p1 = Person('Demon', 18, 'M')
- print(p1) #Demon , 18 , M
- p1.age = 28 #这里只是给p1对象动态的增加了一个age属性
- print(p1) #Demon , 18 , M
- print(p1.age) #28
初看上面的代码,似乎感觉并没有达到私有的目的,因为我们通过 p1.age 还是成功地进行了赋值,程序并没有报错。其实这里是因为 Python 可以动态地给对象增加属性和方法,这句话相当于动态地给 p1 这个对象增加了一个 age 属性。所以在我们做了赋值操作之后,我们再次打印 p1,age 的值依然是 18。说明我们确实已经将类里的 age 属性进行的私有。同理方法的私有也是一样的处理。
在 Python 中,有几种方式来定义变量:
1、以单划线开头:这种类型的变量可以通过对象. 调用,但是它表示的意思是我可以调用,但请把我视为是私有的。而且如果是通过 from xxx_module import * 是无法访问的,但是如果是 import xxx_module 的方式,则可以访问到,类对象和子类也都可以访问。
2、仅以双划线开头:这种类型的变量就是私有。但是它可以通过__类名__变量名来访问,但强烈建议不要这样做
3、以双划线开头,并以它结尾:这种类型的变量在 Python 中通常都表示具有特殊意义的变量,比如__init__,__str__等。所以我们在定义变量时不要这样定义
4、仅以单划线结尾:这种类型的变量是用于避免与 Python 关键字进行冲突所采取的一种解决办法
如下图演示访问权限效果:
上面的介绍了,通过加双划线开头的方式实现了变量和方法。参照在学 Java 时的思路,如果想要访问私有变量,我们会给变量添加 get 和 set 方法。同样我们在 Python 中也是一样的处理,代码如下所示:
- class Person(object):
- def __init__(self, name, age, sex):
- self.name = name #姓名
- self.__age = age #年龄,将年龄私有
- self.sex = sex #性别
- def getAge(self):
- return self.__age
- def setAge(self, age):
- self.__age = age
- p1 = Person('Demon', 18, 'M')
- print(p1.getAge()) #18
- p1.setAge(28)
- print(p1.getAge()) #28
但是这样看着似乎不是很方便,每次都要调用一个方法。有没有可能像之前一样调用 p1. age = 28 就能直接赋值呢?显然在 Python 中是可以的,这就要用到 property。
property 的定义:
使用代码示例:
- class Person(object):
- def __init__(self, name, age, sex):
- self.name = name #姓名
- self.__age = age #年龄,将年龄私有
- self.sex = sex #性别
- def getAge(self):
- return self.__age
- def setAge(self, age):
- self.__age = age
- age = property(getAge, setAge, 'This is age property')
- p1 = Person('Demon', 18, 'M')
- print(p1.age) #18
- p1.age = 28
- print(p1.age) #28
说明:
1. property 接受四个参数,分别是 get, set, del, doc,前三个参数分别对应 get 方法,set 方法,del 方法,顺序不能出错。最后一个参数是 doc,相当于对方法进行说明。
2. property 返回一个 property 属性,返回值的变量名与最终对象. 后面的名称是一致的
观察上面的代码,我们仍然需要多写一行 property 的代码,而 Python 其实提供了一个更方便的实现方式来达到上述要求,即使用 @property。说明如下:
示例代码如下:
- class Person(object):
- def __init__(self, name, age, sex):
- self.name = name #姓名
- self.__age = age #年龄,将年龄私有
- self.sex = sex #性别
- @property
- def age(self): #注意方法名直接为变量名
- return self.__age
- @age.setter #注意方法名直接为变量名
- def age(self, age):
- self.__age = age
- p1 = Person('Demon', 18, 'M')
- print(p1.age) #18
- p1.age = 28
- print(p1.age) #28
说明:
1. @property 相当于对 age 方法进行了一个装饰,它使得我们能通过对象. 方法名来调用对应的属性
2. @property 所装饰的方法名与对象 . 调用的名称要保持一致
3. @property 会生成另外的装饰器,@方法名. setter, @方法名. getter, @方法名. deleter,分别对应 set, get, del 方法。这里 get 方法用得很少,因为已经通过 @property 直接对应到了 get 方法
来源: https://www.cnblogs.com/yrrAwx/p/8227715.html