[Python]-8-对象与类(中)
Posted 海
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Python]-8-对象与类(中)相关的知识,希望对你有一定的参考价值。
引言
这篇文章介绍Python如何将函数与数据整合成类,并通过一个对象名称来访问它们。
文章目录
0×5.获取对象信息
0×6.实例属性与类属性
0×7.属性和方法的动态绑定
0×8.如何将类方法封装成属性
0×5.获取对象信息
除了使用isinstance来匹配对象类型外,还能使用type来获取这些对象的类型,请看下面的实例:
#!/usr/bin/env python
#coding=utf-8
#types模块中定义的常量可用于判断函数类型
import types
#输出对象的类型
print(type("www.qingsword.com"))
#判断对象是否为字符串类型
print(type("qingsword.com")==str)
#程序输出
<class \'str\'>
TRUE
#如果对象是一个函数,就需要借助types模块中定义的常量来判断了
#--------
def fx():
return 0
#判断fx是否为函数类型
print(type(fx)==types.FunctionType)
#判断是否为lambda类型
print(type(lambda :0)==types.LambdaType)
#判断len是否为内置的函数类型
print(type(len)==types.BuiltinFunctionType)
#判断表达式是否为列表生成器类型
print(type((x for x in range(10)))==types.GeneratorType)
#程序输出都为True
#isinstance同样能够完成这些操作,例如将判断fx函数的语句改成下面这样,返回值同样是True
print(isinstance(fx,types.FunctionType))
除了上面的两种对象类型判断外,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态,请看下面的实例:
#!/usr/bin/env python
#coding=utf-8
class Ob_A(object):
#---------
def __init__(self,x=0):
if type(x)==int:
self.a=x
else:
raise TypeError("传入参数类型(%s)错误,正确的参数类型int"%type(x))
#---------
def sq(self):
return self.a*self.a
oba=Ob_A(12)
#判断oba对象中是否有属性(或方法)a,返回True
print(hasattr(oba,"a"))
#获取属性(或方法)a,本例中a是一个属性值12,所以被print直接打印了出来
print(getattr(oba,"a"))
#是否有属性(或方法)b,返回False
print(hasattr(oba,"b"))
#给对象设置一个属性b,值为13
setattr(oba,"b",13)
#因为已经给对象添加了属性b,再次判断,返回True,并且打印出b的值13
print(hasattr(oba,"b"))
print(getattr(oba,"b"))
#判断oba对象中是否存在sq属性(或方法)
print(hasattr(oba,"sq"))
#使用sq对象指向oba对象的sq方法
sq=getattr(oba,"sq")
#从type可以看到sq是一个方法类型
print(type(sq))
#执行sq方法,返回144
print(sq())
#程序输出
TRUE
12
FALSE
TRUE
13
TRUE
<class \'method\'>
144
这三个函数可用于探测对象中的信息,只有在不知道对象信息的时候,才会使用这三个函数,如果已经明确知道了一个对象中包含了哪些属性和方法,请直接调用他们。
0×6.实例属性与类属性
python是动态语言,在实例化后,还能给实例添加新的属性,但最好不要与类中的属性同名,请看下面的实例:
#!/usr/bin/env python
#coding=utf-8
#Ob_A类中定义了一个类属性x,并且配置了其值为2
class Ob_A(object):
x=2
#实例化Ob_A类
oba=Ob_A()
#给oba实例创建一个新属性x,因为和Ob_A类中的属性同名,所以会覆盖原有属性值
oba.x=1
#打印出1
print(oba.x)
#类中的属性保持不变,打印出2
print(Ob_A.x)
#此时如果手动删除oba实例的x对象,再次打印oba实例的x对象,就会打印出原类中绑定的属性x值,打印出2
del oba.x
print(oba.x)
#程序输出
1
2
2
类在实例化后,如果需要给实例新增属性,建议属性名不要使用与原类中已经存在的属性同名,因为相同名称的实例属性将屏蔽掉类属性。
0×7.属性和方法的动态绑定
Python属于高级动态语言,与静态语言不同,当我们实例化一个类对象后,可以动态的给这个类实例绑定属性或方法,请看下面的实例:
#!/usr/bin/env python
#coding=utf-8
from types import MethodType
#定义一个类,仅包含一个age属性
class Ob_A(object):
def __init__(self,age=0):
self.age=age
#实例化Ob_A类
a=Ob_A(23)
#给Ob_A类的实例a新增一个name属性
a.name="qingsword"
#定义一个外部方法,稍后将它绑定到a实例
def get_sex(self):
return "male"
#使用types模块中的MethodType方法,将get_sex这个外部方法绑定到a实例的getsex变量上
a.getsex=MethodType(get_sex,a)
#执行a实例的getsex()就相当于执行了get_sex()
print(a.getsex())
#程序输出
male
#getsex名称仅限于a实例调用,如果此时再实例化一个Ob_A类,除非再次使用MethodType绑定一个新的get_sex方法,否则这个新的类实例是不能使用get_sex这个外部方法的
从上面这个实例可以看出,Python不会限制一个对象实例绑定多少外部属性和方法,但如果要限制他们,可以在类中使用__slots__属性,请看下面的实例:
#!/usr/bin/env python
#coding=utf-8
from types import MethodType
########
class Ob_A(object):
def __init__(self,age=0):
self.age=age
#定义了 __slots__属性后,Ob_A自身和所有实例,都只能使用这个元组中所包含的元素作为属性或方法名称
__slots__=("name","age","get_sex")
########
#但__slots__属性对继承它的子类无效,除非这个子类中也包含一个__slots__属性,那么这个子类可以定义的属性或方法名就是自己的__slots__元组中包含的元素加上父类__slots__元组中包含的元素的集合
class Ob_B(Ob_A):
x=0
########
def get_sex(self):
return "male"
a=Ob_A(23)
a.name="qingsword"
a.get_sex=MethodType(get_sex,a)
print(a.get_sex())
#Ob_B类虽然继承Ob_A,但它没有包含__slots__属性,所以实例b可以添加任何属性或方法名,本例添加了一个web属性,指向了本站网址这段字符串地址
b=Ob_B()
b.web="www.qingsword.com"
print(b.web)
0×8.如何将类方法封装成属性
这一部分将使用python内置的@property装饰器,将类中的方法转换成属性,在外部看来,这个方法就像一个普通属性那样使用,请看下面的实例:
#!/usr/bin/env python
#coding=utf-8
from datetime import datetime
########
class Ob_A(object):
def __init__(self,birth=2016):
"""初始化配置出身年份"""
self.__birth=birth
#使用@property装饰器将birth方法转换成属性
@property
def birth(self):
"""获取出身年份"""
return self.__birth
#使用@方法名.setter将这个方法设置成可写属性(一个方法名称必须先使用过property装饰器,才能使用setter)
@birth.setter
def birth(self,birth):
"""设置出身年份"""
self.__birth=birth
#仅有一个@property没有setter的方法,相当于一个只读属性
@property
def age(self):
"""返回年龄"""
y=datetime.now()
return y.year-self.__birth
x=Ob_A(2008)
print(x.birth)
#可以像设置属性值那样复制(如果是方法语法应该是x.birth(2000))
x.birth=2000
print(x.birth)
print(x.age)
#程序输出
2008
2000
16
虽然上面的实例中,并没有对年龄做进一步的检测(比如年龄范围,输入类型等),但也不难看出,将函数封装成属性的样式可以让调用者写出更直观代码(比如x.birth=2000,而不是x.birth(2000)),而对封装者而言,可以在函数中去做各种条件判断来保证逻辑的合理。
以上是关于[Python]-8-对象与类(中)的主要内容,如果未能解决你的问题,请参考以下文章
python 面向对象专题:元类type反射函数与类的区别特殊的双下方法