没有学习封装之前,效果如下:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
xiaoming = Person("alvin",16)
xiaoming.age = 1000
print(xiaoming.age)
xiaoming.age = -10
print(xiaoming.age)
# 可以看到,外界可以随意修改数据,并可能把数据设置成一个不合理的脏数据。
所谓的封装,就是对类中成员属性和方法进行保护,设置对应的访问权限控制外界对类的内部成员的访问,修改,删除等操作,有条件的开放外界对数据的操作。
常见的编程语言中对于类或对象的成员保护与访问机制,分3个等级:
访问权限 | 描述 | 格式 |
---|---|---|
私有的 (private) |
只能在当前类内部可以访问与操作,类的外部不可以。 | __方法名 __属性名 |
公有的 (public) |
在当前类内部和外部都可以访问操作。 | 方法名 属性名 |
受保护的 (protected) |
在当前类内部和子类内部可以访问,外界无法访问。 python原生不支持,但是python开发者都约定俗成了左边单个下划线开头属于受保护的 |
_方法名() _属性名 |
Python对成员的保护只有两个等级:私有的(private)和公有的(public)。在java,php,c++等编程语言里面就存在3种等级。
import re
class Person(object):
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_name(self, name):
if self.__check_name(name):
self.__name = name
else:
raise Exception("名字长度不能大于7个字符!")
def __check_name(self, name):
return len(re.split("", name)[1:-1]) < 5
xiaoming = Person("小明")
# print(xiaoming.__name) # 报错!
xiaoming.set_name("小红")
# xiaoming.__check_name("小红") # 报错!
print(xiaoming.get_name())
xiaoming.set_name("小红五一到此一游") # 报错!
所以,所谓的封装其实就是为了让一些属性和方法,不能被外界直接修改和调用而已。对数据的修改,可以通过提供公有方法的方式给外界操作,那么外界操作时,我们就可以设置一些判断了。而判断名字这种方法,外界没有必要使用到,所以我们可以设置为私有级别,这样,对于外界来说,就不存在这个判断名字的方法了。
注意:类中不仅可以把实例属性和实例方法设置私有的或公有的,类的类属性和类方法也可以这么设置,只是很少有人这么用而已,因此我们这里不作介绍。
使用接口函数获取修改数据 和 使用赋值设置数据相比, 赋值设置数据使用起来更方便,我们有什么方法达到 既能使用赋值方式,同时又能在赋值时直接调用到我们定义的方法接口对数据校验呢?有的,答案就是@property(属性装饰器)。
class Student(object):
def __init__(self, name, age):
self.__name = name
self.__sex = sex
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
if len(name) > 1 :
self.__name = name
else:
print("name的长度必须要大于1个长度")
注意,使用 @property 装饰器时,接口名不必与属性名相同。
python还提供了更加人性化的操作,可以通过property函数限制方式完成只读、只写、读写、删除等各种操作
class Person(object):
def __init__(self, name):
self.__name = name
def __get_name(self):
return self.__name
def __set_name(self, name):
self.__name = name
def __del_name(self):
del self.__name
# property()中定义了读取、赋值、删除的操作
# name = property(__get_name, __set_name, __del_name)
name = property(__get_name, __set_name)
xiaoming = Person("xiaoming")
print(xiaoming.name) # 合法:调用__get_name
xiaoming.name = "小明" # 合法:调用__set_name
print(xiaoming.name)
# property中没有添加__del_name函数,所以不能删除指定的属性
del xiaoming.name # 错误:AttributeError: can't delete Attribute
@property
广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
面向对象的编程带来的主要好处之一是复用代码,实现复用代码的方法之一是通过类的继承机制。
通过继承创建的新类称为子类、派生类,后代类,被继承的类称为基类、父类或超类。
class 子类名(父类名):
pass
继承是使用已有父类作为基础创建子类的一种方式。子类的定义可以增加新的属性或方法,也可以复用或覆盖父类已有的属性和方法。
注意:其他的语言,是可以选择性的复用父类属性和方法,而python中默认是全局复用的。
使用继承之前:
class Student(object):
"""学生类"""
def __init__(self, name, age, achievement):
self.name=name
self.age=age
self.achievement = achievement
def eat(self):
print("eating...")
def sleep(self):
print("sleep...")
def do_homework(self):
print("do_homework.....")
def do_read(self):
print("reading........")
class Teacher(object):
"""老师类"""
def __init__(self, name, age, salary):
self.name=name
self.age=age
self.salary = salary
def eat(self):
print("eating...")
def sleep(self):
print("sleep...")
def teaching(self):
print("teaching.....")
使用继承以后:
class Person(object):
"""人类"""
def eat(self):
print("eating...")
def sleep(self):
print("sleep...")
class Student(object):
"""学生类"""
def __init__(self, name, age, achievement):
self