+-
[Python]-8-对象与类(上)
首页 专栏 python 文章详情
0
头图

[Python]-8-对象与类(上)

发布于 4 月 30 日

引言

这篇文章介绍Python如何将函数与数据整合成类,并通过一个对象名称来访问它们。

文章目录

0×1.什么是python中的对象
0×2.python中如何创建类
0×3.类私有属性访问限制
0×4.继承与多态

0×1.什么是python中的对象

Python中每条数据都是对象,每个对象都由三部分组成:标识,数据,类型;

标识是对象的名称,也储存了该对象的内存地址(对象引用),类型规定了这个对象所能储存的值的类型,内存中的某块区域保存了对象的数据值;

在之前的文章中,我们定义的字符串,列表,字典等,都是对象,每个对象都有其内置的一些方法,例如对字符串对象使用len()方法可以求出字符串的长度,我们可以在IDLE中使用dir()方法来查看某个对象可以使用的方法,如下:

>>> s="www.qingsword.com" >>> dir(s) ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] #上面中括号中的所有输出,以逗号分隔,每一个都是字符串对象可以使用的方法,其中带双下划线的为"内部方法",不带下划线的为"外部方法"也叫"接口函数","内部方法"通常对用户是不可见的,但这并不意味着内部方法就是不可调用的,实际上我们对某个字符串对象使用len()函数的时候,就是调用了其内部的__len__方法,通过下面的实例可以看到,两者的输出是相同的 >>> print(len(s)) 17 >>> print(s.__len__()) 17

在定义一个字符串对象的时候,python在其内部初始化了一个str类,这个类中包含了python提供的对字符串处理的内置方法,等大家看完本文第2部分,自己手动创建了一个类之后,就自然会明白上面这些内部方法和接口函数的工作原理了。

0×2.python中如何创建类

python中的类,实际上是完成某个工作的对象和函数的集合,当一个类被调用时,它创建了绑定到一个名称的对象,请看下面的实例,这是一个经典的电冰箱实例,我们假设要创建一个类,用于将食物放入冰箱,查询冰箱中有哪些食物,然后提供取出食物的一系列方法:

#!/usr/bin/env python3 #coding=utf-8 ######## class Fridge:     """电冰箱类实例"""     #--------     def __init__(self,items={}):         """类初始化"""         if type(items)!=type({}):             raise TypeError("传入参数错误:%s"%items)         self.items=items ######## #python使用class关键字来定义一个类,本例定义了一个Fridge类,在这个类中有一个内部方法__init__,每个类都可以包含这个方法,也可以不包含,这个方法的作用是,当使用名称初始化一个Fridge对象时,自动执行__init__函数中的代码,相当于类的初始化操作 #注意def __init__(self,items={})部分中的self参数,这是python独有的语法,self总是代表类对象本身,这段初始化代码初始化了一个空字典对象,如果不好理解self,可以尝试着将代码中的self省去,然后观察这段函数,实际上__init__就接收一个参数,这个参数必须是一个字典对象,如果省去这个参数,那么默认初始化一个空自字典,并且在Fridge内部使用items对象保存这个字典的数据,但实际情况下self参数不能省略 #现在我们已经有了一个Fridge类,可以通过下面的方法创建这个类的对象实例,下面的语法没有给Fridge传递参数,所以将初始化一个空的字典,如果想要传递参数,可以这么写p=Fridge({"apple":1,"orange":3}),如果这样,那么Fridge中的items对象就将保存{"apple":1,"orange":3}这个字典 p=Fridge() #现在有一个新的对象p,他是一个完整的Fridge类对象,在上面的创建过程中,Fridge类执行了__init__方法,这将创建一个空的字典对象,可以通过"类实例名称.类对象名称"来访问到这些数据 print(p.items) #输出 {}

现在,可以给Fridge类添加一系列方法来提供必要的功能了,在Fridge类中补充下面的内容,用于添加查询或删除食物:

#!/usr/bin/env python3 #coding=utf-8 ######## class Fridge:     """电冰箱类实例"""     #--------     def __init__(self,items={}):         """类初始化"""         if type(items)!=type({}):             raise TypeError("传入参数错误:%s"%items)         self.items=items           #--------     def __add_multi(self,food_name,quantity):         """内部方法,向items字典添加键值,如果food_name不在items字典的键列表中,说明这是一个新添加的食物,将数量初始化为0,然后加上传递给这个函数的quantity的值(可能是一个或者多个)"""         if (not food_name in self.items.keys()):             self. items[food_name]=0         self.items[food_name]+=quantity           #--------     def add_one(self,food_name):         """向items字典添加单个食物,这就是一个接口函数,通过调用内部方法__add_multi完成添加食物到冰箱的工作"""         if type(food_name)!=type(""):             raise TypeError("食物名称类型错误:%s,正确的数据类型:%s"\                             %(type(food_name),type("")))         else:             self.__add_multi(food_name,1)         return True           #--------     def add_many(self,food_dict):         """像items字典添加多个食物,这个接口函数接收一个字典参数food_dict,使用for循环遍历这个传递过来的字典中的键名,然后将名称和数量传递给__add_multi函数"""         if type(food_dict)!=type({}):             raise TypeError("食物名称和数量必须使用字典,错误的数据输入:%s"%food_dict)         else:             for food_name in food_dict.keys():                 self.__add_multi(food_name,food_dict[food_name])                       #--------     def has(self,food_name,quantity=1):         """查看items中是是否还有某个食物,如果只向这个接口函数传递一个食物名称,那么quantity默认为1,他将调用下面的has_various函数,将食物名称和食物数量传递过去,用于判断冰箱中还有没有这么多的食物"""         return self.has_various({food_name:quantity})           #--------     def has_various(self,foods):         """查看食物是否低于输入值,这个接口函数接受一个字典类型的传入参数,通过遍历这个传入的字典中的键名,判断Fridge的items字典中对应键的值是否小于传递进来的这个列表中的每个食物的值,如果小于就返回False,代表冰箱中没有那么多食物了,如果传入的食物名称不存在,会产生一个KeyError异常,同样返回False"""         try:             for food in foods.keys():                 if self.items[food]<foods[food]:                     return False                 return True         except KeyError:             return False                   #--------     def __get_multi(self,food_name,quantity):         """取出食物的内部方法,这个方法接受两个值,一个为食物名称,一个为食物数量,首先if判断冰箱中是否存在这种食物,如果有将其从类实例的items字典中减去对应数量,减去数量后再判断这种食物库存是否为0,如果为0,将其从items字典中删除,如果冰箱中没有这种食物或者库存不足(这些都在has_various方法中判断),跳转到else语句,判断是库存不足还是根本没有这种食物"""         if self.has(food_name,quantity):             self.items[food_name]-=quantity             print("成功取出%s,数量%s"%(food_name,quantity))             if self.items[food_name]==0:                 self.items.pop(food_name)            else:             if not food_name in self.items.keys():                 print("冰箱中并没有这种食物:%s"%food_name)             else:                 print("食物'%s'库存不足,现有数量:%s"%(food_name,self.items[food_name]))            #--------     def get_one(self,food_name):         """取出某个食物,调用内部方法__get_multi取出单个食物"""         if type(food_name)!=type(""):             raise TypeError("食物名称类型错误:%s,正确的数据类型:%s"\                                         %(type(food_name),type("")))         else:             self.__get_multi(food_name, 1)         return True            #--------     def get_many(self,food_dect):         """取出多个食物,这个函数接收一个字典参数,for循环遍历这个传入的字典中的键列表,调用__get_multi取出这些食物和对应的数量"""         if type(food_dect)!=type({}):             raise TypeError("食物名称和数量必须使用字典,错误的数据输入:%s"%food_dict)         for food in food_dect.keys():             self.__get_multi(food,food_dect[food]) ########       #初始化Fridge类 p=Fridge() #添加食物 p.add_one("orange") p.add_many({"apple":2,"banana":5}) print(p.items) #输出 {'apple': 2, 'orange': 1, 'banana': 5} #判断食物是否存在 print(p.has("orange"))  #True print(p.has("apple",3)) #False #取出食物 if p.has("orange"):     p.get_one("orange") p.get_many({"banana":4,"apple":4}) p.get_one("www.qingsword.com") print(p.items) #输出 成功取出orange,数量1 成功取出banana,数量4 食物'apple'库存不足,现有数量:2 冰箱中并没有这种食物:www.qingsword.com {'apple': 2, 'banana': 1}

0×3.类私有属性访问限制

在上面的电冰箱实例中,我们已经创建过了私有方法,python中所谓的私有方法和属性,就是在这些方法或属性名前添加两个"下划线"(例如__items),这样的属性或方法是不能用正常的方法访问到的,但不包括前后双下划线的那些(例如__len__),下面用一个实例来演示这些私有属性和方法的特性:

#!/usr/bin/env python #coding=utf-8 ######## class Kitty(object):     """私有属性__name和__age的类"""     #--------     def __init__(self,name="hello",age=1):         """初始化"""         self.__name=name         self.__age=age     #私有属性可以通过接口函数来调用     #--------     def get_age(self):         """返回年龄"""         return self.__age     #--------     def set_age(self,age):         """设置年龄"""         self.__age=age     #--------     def get_name(self):         """返回名字"""         return self.__name     #--------     def set_name(self,name):         """设置名字"""         self.__name=name     #前后双下划线的方法,不是私有方法,外部可以直接访问,只有前置双下划线的属性或方法才是私有的,自能通过内部接口函数调用     #--------     def __get_name_len__(self):         return len(self.__name) #实例化      kt=Kitty() #通过接口函数设置年龄和姓名 kt.set_age(2) kt.set_name("www.qingsword.com") #通过接口函数打印姓名和年龄 print(kt.get_name()) print(kt.get_age()) #打印出名字长度 print(kt.__get_name_len__()) #程序输出 www.qingsword.com 2 17 #从这个实例可以看出,前后带双下划线的方法或属性,都能直接访问到,而如果我们输入下面这3句,发现并没有报错,不是说私有属性不能直接访问吗,为什么可以直接kt.__name设置私有属性的值呢?这是因为,实际上我们使用实例kt.__name这种语法的时候,是对kt这个类实例,创建了一个新的属性__name,这个属性和Kitty内部的私有属性并不是一个属性,内部的__name属性已经被python解释器自动改名为_Kitty__name了 kt.__name="qingsword.com" print(kt.__name) print(kt._Kitty__name) #从下面的程序输出可以看到,两者保存的数据并不相同 qingsword.com www.qingsword.com #这并不意味着外部就真的无法调用这些私有属性或方法,只是python解释器自动对这些私有数据添加了类名前缀,可以给私有属性添加带但下划线的类名前缀来直接访问他们,但并不推荐这么做 kt._Kitty__name="www.qingsword.com" #可能大家会觉得很奇怪,为什么要添加这些私有的属性或方法,直接提供访问不好吗?实际上,可以通过创建接口函数,对私有数据进行过滤处理,例如     #--------     def set_age(self,age):         """设置年龄"""         if 0<=age<=150:             self.__age=age         else:             print("年龄不科学")

0×4.继承与多态

我们在创建类的时候,默认情况下都是继承了python的基类object,除此之外,我们还能让新建的类继承现有的类,继承后子类将拥有被继承的父类所有的属性和方法,下面用一个实例来演示这一特性:

#!/usr/bin/env python #coding=utf-8 ######## class Parent(object):     """父类,继承了object类,如果一个类是继承基类object,可以省略(object)不写,但写上看起来更加的规范"""     #--------     def print_website(self):         """打印网址"""         print("www.qingsword.com")     #--------     def print_author(self):         """打印作者名称"""         print("QingSword") ######## class Sub_A(Parent):     """继承Parent的子类,将父类写在子类后面的括号中,表示继承其所有的方法和属性,Sub_A重写了父类的print_website方法"""     #--------     def print_website(self):         """打印网址"""         print("qingsword.com") ######## class Sub_B(Parent):     """继承Parent的子类,仅仅是一个空类,但却可以使用父类所有属性或方法(注意,对空类最好添加一个这样的注释,否则在某些编辑器下可能会出现缩进IndentationError错误)""" ######## class Sub_C(object):     """继承object的子类"""     #--------     def print_author(self):         print("qingsword")           #-------- def print_info(x):     """打印作者信息"""     x.print_author() #首先实例化四个类 p=Parent() a=Sub_A() b=Sub_B() c=Sub_C() #访问父类的两个方法 p.print_website() p.print_author() #程序输出 www.qingsword.com QingSword #访问子类A的两个方法,如果一个子类中有与父类同名的属性或方法,那么它将覆盖父类的属性或方法,A类中重写了父类的print_website(),所以会优先被调用,虽然A类并没有print_author()方法,但是它将从父类Parent中继承这个方法,除非重写这个方法,否则就将直接调用父类的方法打印出作者信息 a.print_website() a.print_author() #程序输出 qingsword.com QingSword #B类中什么都没写,但他继承了父类Parent b.print_author() b.print_website() #程序输出 www.qingsword.com QingSword #再来看看这些对象他们的类型都是什么 #Parent类是继承object的,所以它可以是object类型,也可以是Parent类型,但不能是其子类型 print(isinstance(p,Parent)) print(isinstance(p,object)) print(isinstance(p,Sub_A)) #程序输出 TRUE TRUE FALSE #所有的子类型,可以是其父类型或Python基类object,也可以是其自身,所以下面的输出都是True print(isinstance(a,Parent)) print(isinstance(a,Sub_A)) print(isinstance(b,Parent)) print(isinstance(b,Sub_B)) #像print_info()方法传递四个类,四个类可以是不同类型,甚至可以像print_info()传递其他方法名称,这是高级动态语言的一个最强大的地方——多态:print_info()方法接收一个变量,它不管接收的变量是什么类型,只关心这个变量能不能访问print_author()方法,这就是为什么C类虽然是继承了object,但它也有print_author()方法,所以程序不会报错 print_info(p) print_info(a) print_info(b) print_info(c) #程序输出 QingSword QingSword QingSword qingsword
python linux 运维 ubuntu
阅读 64 更新于 5 月 3 日
举报
收藏
分享
本作品系原创, 采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议
avatar
1 声望
0 粉丝
关注作者
0 条评论
得票数 最新
提交评论
avatar
1 声望
0 粉丝
关注作者
宣传栏
目录

引言

这篇文章介绍Python如何将函数与数据整合成类,并通过一个对象名称来访问它们。

文章目录

0×1.什么是python中的对象
0×2.python中如何创建类
0×3.类私有属性访问限制
0×4.继承与多态

0×1.什么是python中的对象

Python中每条数据都是对象,每个对象都由三部分组成:标识,数据,类型;

标识是对象的名称,也储存了该对象的内存地址(对象引用),类型规定了这个对象所能储存的值的类型,内存中的某块区域保存了对象的数据值;

在之前的文章中,我们定义的字符串,列表,字典等,都是对象,每个对象都有其内置的一些方法,例如对字符串对象使用len()方法可以求出字符串的长度,我们可以在IDLE中使用dir()方法来查看某个对象可以使用的方法,如下:

>>> s="www.qingsword.com" >>> dir(s) ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill'] #上面中括号中的所有输出,以逗号分隔,每一个都是字符串对象可以使用的方法,其中带双下划线的为"内部方法",不带下划线的为"外部方法"也叫"接口函数","内部方法"通常对用户是不可见的,但这并不意味着内部方法就是不可调用的,实际上我们对某个字符串对象使用len()函数的时候,就是调用了其内部的__len__方法,通过下面的实例可以看到,两者的输出是相同的 >>> print(len(s)) 17 >>> print(s.__len__()) 17

在定义一个字符串对象的时候,python在其内部初始化了一个str类,这个类中包含了python提供的对字符串处理的内置方法,等大家看完本文第2部分,自己手动创建了一个类之后,就自然会明白上面这些内部方法和接口函数的工作原理了。

0×2.python中如何创建类

python中的类,实际上是完成某个工作的对象和函数的集合,当一个类被调用时,它创建了绑定到一个名称的对象,请看下面的实例,这是一个经典的电冰箱实例,我们假设要创建一个类,用于将食物放入冰箱,查询冰箱中有哪些食物,然后提供取出食物的一系列方法:

#!/usr/bin/env python3 #coding=utf-8 ######## class Fridge:     """电冰箱类实例"""     #--------     def __init__(self,items={}):         """类初始化"""         if type(items)!=type({}):             raise TypeError("传入参数错误:%s"%items)         self.items=items ######## #python使用class关键字来定义一个类,本例定义了一个Fridge类,在这个类中有一个内部方法__init__,每个类都可以包含这个方法,也可以不包含,这个方法的作用是,当使用名称初始化一个Fridge对象时,自动执行__init__函数中的代码,相当于类的初始化操作 #注意def __init__(self,items={})部分中的self参数,这是python独有的语法,self总是代表类对象本身,这段初始化代码初始化了一个空字典对象,如果不好理解self,可以尝试着将代码中的self省去,然后观察这段函数,实际上__init__就接收一个参数,这个参数必须是一个字典对象,如果省去这个参数,那么默认初始化一个空自字典,并且在Fridge内部使用items对象保存这个字典的数据,但实际情况下self参数不能省略 #现在我们已经有了一个Fridge类,可以通过下面的方法创建这个类的对象实例,下面的语法没有给Fridge传递参数,所以将初始化一个空的字典,如果想要传递参数,可以这么写p=Fridge({"apple":1,"orange":3}),如果这样,那么Fridge中的items对象就将保存{"apple":1,"orange":3}这个字典 p=Fridge() #现在有一个新的对象p,他是一个完整的Fridge类对象,在上面的创建过程中,Fridge类执行了__init__方法,这将创建一个空的字典对象,可以通过"类实例名称.类对象名称"来访问到这些数据 print(p.items) #输出 {}

现在,可以给Fridge类添加一系列方法来提供必要的功能了,在Fridge类中补充下面的内容,用于添加查询或删除食物:

#!/usr/bin/env python3 #coding=utf-8 ######## class Fridge:     """电冰箱类实例"""     #--------     def __init__(self,items={}):         """类初始化"""         if type(items)!=type({}):             raise TypeError("传入参数错误:%s"%items)         self.items=items           #--------     def __add_multi(self,food_name,quantity):         """内部方法,向items字典添加键值,如果food_name不在items字典的键列表中,说明这是一个新添加的食物,将数量初始化为0,然后加上传递给这个函数的quantity的值(可能是一个或者多个)"""         if (not food_name in self.items.keys()):             self. items[food_name]=0         self.items[food_name]+=quantity           #--------     def add_one(self,food_name):         """向items字典添加单个食物,这就是一个接口函数,通过调用内部方法__add_multi完成添加食物到冰箱的工作"""         if type(food_name)!=type(""):             raise TypeError("食物名称类型错误:%s,正确的数据类型:%s"\                             %(type(food_name),type("")))         else:             self.__add_multi(food_name,1)         return True           #--------     def add_many(self,food_dict):         """像items字典添加多个食物,这个接口函数接收一个字典参数food_dict,使用for循环遍历这个传递过来的字典中的键名,然后将名称和数量传递给__add_multi函数"""         if type(food_dict)!=type({}):             raise TypeError("食物名称和数量必须使用字典,错误的数据输入:%s"%food_dict)         else:             for food_name in food_dict.keys():                 self.__add_multi(food_name,food_dict[food_name])                       #--------     def has(self,food_name,quantity=1):         """查看items中是是否还有某个食物,如果只向这个接口函数传递一个食物名称,那么quantity默认为1,他将调用下面的has_various函数,将食物名称和食物数量传递过去,用于判断冰箱中还有没有这么多的食物"""         return self.has_various({food_name:quantity})           #--------     def has_various(self,foods):         """查看食物是否低于输入值,这个接口函数接受一个字典类型的传入参数,通过遍历这个传入的字典中的键名,判断Fridge的items字典中对应键的值是否小于传递进来的这个列表中的每个食物的值,如果小于就返回False,代表冰箱中没有那么多食物了,如果传入的食物名称不存在,会产生一个KeyError异常,同样返回False"""         try:             for food in foods.keys():                 if self.items[food]<foods[food]:                     return False                 return True         except KeyError:             return False                   #--------     def __get_multi(self,food_name,quantity):         """取出食物的内部方法,这个方法接受两个值,一个为食物名称,一个为食物数量,首先if判断冰箱中是否存在这种食物,如果有将其从类实例的items字典中减去对应数量,减去数量后再判断这种食物库存是否为0,如果为0,将其从items字典中删除,如果冰箱中没有这种食物或者库存不足(这些都在has_various方法中判断),跳转到else语句,判断是库存不足还是根本没有这种食物"""         if self.has(food_name,quantity):             self.items[food_name]-=quantity             print("成功取出%s,数量%s"%(food_name,quantity))             if self.items[food_name]==0:                 self.items.pop(food_name)            else:             if not food_name in self.items.keys():                 print("冰箱中并没有这种食物:%s"%food_name)             else:                 print("食物'%s'库存不足,现有数量:%s"%(food_name,self.items[food_name]))            #--------     def get_one(self,food_name):         """取出某个食物,调用内部方法__get_multi取出单个食物"""         if type(food_name)!=type(""):             raise TypeError("食物名称类型错误:%s,正确的数据类型:%s"\                                         %(type(food_name),type("")))         else:             self.__get_multi(food_name, 1)         return True            #--------     def get_many(self,food_dect):         """取出多个食物,这个函数接收一个字典参数,for循环遍历这个传入的字典中的键列表,调用__get_multi取出这些食物和对应的数量"""         if type(food_dect)!=type({}):             raise TypeError("食物名称和数量必须使用字典,错误的数据输入:%s"%food_dict)         for food in food_dect.keys():             self.__get_multi(food,food_dect[food]) ########       #初始化Fridge类 p=Fridge() #添加食物 p.add_one("orange") p.add_many({"apple":2,"banana":5}) print(p.items) #输出 {'apple': 2, 'orange': 1, 'banana': 5} #判断食物是否存在 print(p.has("orange"))  #True print(p.has("apple",3)) #False #取出食物 if p.has("orange"):     p.get_one("orange") p.get_many({"banana":4,"apple":4}) p.get_one("www.qingsword.com") print(p.items) #输出 成功取出orange,数量1 成功取出banana,数量4 食物'apple'库存不足,现有数量:2 冰箱中并没有这种食物:www.qingsword.com {'apple': 2, 'banana': 1}

0×3.类私有属性访问限制

在上面的电冰箱实例中,我们已经创建过了私有方法,python中所谓的私有方法和属性,就是在这些方法或属性名前添加两个"下划线"(例如__items),这样的属性或方法是不能用正常的方法访问到的,但不包括前后双下划线的那些(例如__len__),下面用一个实例来演示这些私有属性和方法的特性:

#!/usr/bin/env python #coding=utf-8 ######## class Kitty(object):     """私有属性__name和__age的类"""     #--------     def __init__(self,name="hello",age=1):         """初始化"""         self.__name=name         self.__age=age     #私有属性可以通过接口函数来调用     #--------     def get_age(self):         """返回年龄"""         return self.__age     #--------     def set_age(self,age):         """设置年龄"""         self.__age=age     #--------     def get_name(self):         """返回名字"""         return self.__name     #--------     def set_name(self,name):         """设置名字"""         self.__name=name     #前后双下划线的方法,不是私有方法,外部可以直接访问,只有前置双下划线的属性或方法才是私有的,自能通过内部接口函数调用     #--------     def __get_name_len__(self):         return len(self.__name) #实例化      kt=Kitty() #通过接口函数设置年龄和姓名 kt.set_age(2) kt.set_name("www.qingsword.com") #通过接口函数打印姓名和年龄 print(kt.get_name()) print(kt.get_age()) #打印出名字长度 print(kt.__get_name_len__()) #程序输出 www.qingsword.com 2 17 #从这个实例可以看出,前后带双下划线的方法或属性,都能直接访问到,而如果我们输入下面这3句,发现并没有报错,不是说私有属性不能直接访问吗,为什么可以直接kt.__name设置私有属性的值呢?这是因为,实际上我们使用实例kt.__name这种语法的时候,是对kt这个类实例,创建了一个新的属性__name,这个属性和Kitty内部的私有属性并不是一个属性,内部的__name属性已经被python解释器自动改名为_Kitty__name了 kt.__name="qingsword.com" print(kt.__name) print(kt._Kitty__name) #从下面的程序输出可以看到,两者保存的数据并不相同 qingsword.com www.qingsword.com #这并不意味着外部就真的无法调用这些私有属性或方法,只是python解释器自动对这些私有数据添加了类名前缀,可以给私有属性添加带但下划线的类名前缀来直接访问他们,但并不推荐这么做 kt._Kitty__name="www.qingsword.com" #可能大家会觉得很奇怪,为什么要添加这些私有的属性或方法,直接提供访问不好吗?实际上,可以通过创建接口函数,对私有数据进行过滤处理,例如     #--------     def set_age(self,age):         """设置年龄"""         if 0<=age<=150:             self.__age=age         else:             print("年龄不科学")

0×4.继承与多态

我们在创建类的时候,默认情况下都是继承了python的基类object,除此之外,我们还能让新建的类继承现有的类,继承后子类将拥有被继承的父类所有的属性和方法,下面用一个实例来演示这一特性:

#!/usr/bin/env python #coding=utf-8 ######## class Parent(object):     """父类,继承了object类,如果一个类是继承基类object,可以省略(object)不写,但写上看起来更加的规范"""     #--------     def print_website(self):         """打印网址"""         print("www.qingsword.com")     #--------     def print_author(self):         """打印作者名称"""         print("QingSword") ######## class Sub_A(Parent):     """继承Parent的子类,将父类写在子类后面的括号中,表示继承其所有的方法和属性,Sub_A重写了父类的print_website方法"""     #--------     def print_website(self):         """打印网址"""         print("qingsword.com") ######## class Sub_B(Parent):     """继承Parent的子类,仅仅是一个空类,但却可以使用父类所有属性或方法(注意,对空类最好添加一个这样的注释,否则在某些编辑器下可能会出现缩进IndentationError错误)""" ######## class Sub_C(object):     """继承object的子类"""     #--------     def print_author(self):         print("qingsword")           #-------- def print_info(x):     """打印作者信息"""     x.print_author() #首先实例化四个类 p=Parent() a=Sub_A() b=Sub_B() c=Sub_C() #访问父类的两个方法 p.print_website() p.print_author() #程序输出 www.qingsword.com QingSword #访问子类A的两个方法,如果一个子类中有与父类同名的属性或方法,那么它将覆盖父类的属性或方法,A类中重写了父类的print_website(),所以会优先被调用,虽然A类并没有print_author()方法,但是它将从父类Parent中继承这个方法,除非重写这个方法,否则就将直接调用父类的方法打印出作者信息 a.print_website() a.print_author() #程序输出 qingsword.com QingSword #B类中什么都没写,但他继承了父类Parent b.print_author() b.print_website() #程序输出 www.qingsword.com QingSword #再来看看这些对象他们的类型都是什么 #Parent类是继承object的,所以它可以是object类型,也可以是Parent类型,但不能是其子类型 print(isinstance(p,Parent)) print(isinstance(p,object)) print(isinstance(p,Sub_A)) #程序输出 TRUE TRUE FALSE #所有的子类型,可以是其父类型或Python基类object,也可以是其自身,所以下面的输出都是True print(isinstance(a,Parent)) print(isinstance(a,Sub_A)) print(isinstance(b,Parent)) print(isinstance(b,Sub_B)) #像print_info()方法传递四个类,四个类可以是不同类型,甚至可以像print_info()传递其他方法名称,这是高级动态语言的一个最强大的地方——多态:print_info()方法接收一个变量,它不管接收的变量是什么类型,只关心这个变量能不能访问print_author()方法,这就是为什么C类虽然是继承了object,但它也有print_author()方法,所以程序不会报错 print_info(p) print_info(a) print_info(b) print_info(c) #程序输出 QingSword QingSword QingSword qingsword