类及其类属性
1.属性就是属于另一个对象的数据或者函数元素,可以通过我们熟悉的句点属性标示法来访问。
2.类属性仅与其被定义的类相绑定,由于实例对象在日常的面向对象编程中用得最多,实例数据属性是你将会一直用到的主要数据属性。
类数据属性仅当需要更加“静态”数据类型时才变得有用,他和任何实例都无关。
类的数据属性
这种属性是一种静态变量,表示这些数据是与他们所属的类对象绑定的,不依赖于任何类实例。
>>>
>>> class my(object):
... foo=100 #类属性
...
>>> print my.foo
100
>>> my.foo=my.foo+1
>>> my.foo
101
>>>
以上代码没有出现任何实例的引用
方法
方法其实就是类中定义的函数,他是属于类属性的,并不属于实例属性。虽然他是类属性,但是并不能直接通过类来调用。
>>> class my(object):
... def my_method(self):
... pass
...
>>> c=my()
>>> c.my_method() #通过实例调用
>>> my.my_method() #通过类直接调用这个方法
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method my_method() must be called with my instance as first a
rgument (got nothing instead)
>>>
为什么会出错,明明方法也是类属性,接下来解释这个问题
绑定(绑定以及非绑定方法)为了与oop惯例保持一致,python严格要求,没有实例,方法是不能被调用的,这种限制即Python所描述的绑定概念,方法必须与实例绑定才能被直接被调用。 非绑定方法可能可以被调用,但实例对象一定要明确给出,才能确保调用成功。
dir
要知道一个类有哪些属性,有两种方法,最简单的是使用dir()内建函数,另为一个就是通过访问类的字典属性__dict__
,这是所有类都具备的特殊属性之一。
>>> class myclass(object):
... myversion=1.0
... def show(self):
... print myclass.myversion
...
>>> dir(myclass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut
e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e
x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_
_weakref__', 'myversion', 'show']
>>> myclass.__dict__
dict_proxy({'__module__': '__main__', 'show': <function show at 0x0000000002D51E
B8>, '__dict__': <attribute '__dict__' of 'myclass' objects>, 'myversion': 1.0,
'__weakref__': <attribute '__weakref__' of 'myclass' objects>, '__doc__': None})
>>>
从上面的代码可以看出,dir()返回的仅是对象的属性的一个名字列表,可以打印类属性,还可以打印所有的实例属性,而__dict__
返回的是一个字典,他的键是属性名,键值是相应的属性对象的数据值。
特殊的类属性
C.__name__ 类C的名字(字符串)
C.__doc__ 类C的文档字符串
C.__bases__ 类C的所有父类构成的元组
C.__dict__ 类C的属性
C.__module__ 类C定义所在的模块
C.__class__ 实例C对应的类(仅新式类中)
实例
如果说类是一种数据结构定义的类型,那么实例则声明了一个这种类型的变量。
__init__()
“构造器”方法
当类被调用的时候,实例化的第一步就是创建实例对象,一旦对象创建了,Python检查是否实现了__init__()
方法,默认情况下,如果没有定义(或者覆盖)特殊方法__init__()
,对实例不会施加任何特别操作,任何所需要的特定操作,都需要程序员实现__init__()
,覆盖它的默认行为。
如果__init__()
已经被实现 ,那么它将被调用,实例对象作为第一个参数(self)被传递进去,调用类的时候,传进去的任何参数都交给了__init__()
。
__new__()
“构造器”方法
与__init__()
方法相比,__new__()
方法更像一个真正的构造器,python可以对内建类型进行派生,因此,需要一种途径来实例化不可变对象,比如派生字符串,数字等
__new__()
相比与__init__()
方法,__new__()
必须返回一个合法的实例,这样解释器在调用__init__()
时,就可以把这个实例作为self传给他。简单的说就是new调用了init
__call__
有了这个特殊方法,就可以像函数一样调用实例了
class Test(object):
def __init__(self,name):
self.name=name
def __call__(self,age):
self.age=age
return "%s is %s"%(self.name,self.age)
t=Test('cmustard')
print t(23) #调用实例
"cmustard is 23"
实例属性
实例仅拥有数据属性(方法严格来说是类属性),当一个实例被释放后,他的属性同时也被清除了。
构造器是最早设置实例属性的地方,一旦__init__()
执行完毕,返回实例对象,即完成了实例化过程
查看实例属性
>>> class my(object):
... pass
...
>>> c=my()
>>> c.foo='cmustard'
>>> c.bar=12312
>>> dir(c) #所有属性,包括类属性和实例属性
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribut
e__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_e
x__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_
_weakref__', 'bar', 'foo']
>>> c.__dict__ #返回实例对象构成的字典
{'foo': 'cmustard', 'bar': 12312}
>>>
实例属性和类属性比较
类属性仅是与类相关的数据值,和实例属性不同,类属性和实例属性无关。类和实例都是名字空间,类是类属性的名字空间,实例则是实例属性的。我们可以采用类来访问类属性,如果实例没有同名的属性的话,你也可以用实例来访问。
>>> class my(object):
... myversion=1
... def __init__(self,name):
... self.name=name
...
>>> class my(object):
... myversion=1
... def __init__(self,name):
... self.name=name
... def show(self,age):
... print "name is %s age is %s"%(self.name,age)
...
>>> c=my('cmustard')
>>> c.name #访问实例属性
'cmustard'
>>> c.myversion #访问myversion,实例属性中没有,于是访问的是类属性中的变量
1
>>> c2=my("abner")
>>> c2.show(22) #访问方法
name is abner age is 22
>>> c.show(18)
name is cmustard age is 18
>>> c2.myversion #访问myversion,实例属性中没有,于是访问的是类属性中的变量
1
>>> my.myversion #通过类直接访问类属性
1
>>> c.myversion=100 #在实例c中修改myversion,相当与在实例c中动态添加了一个新的属性
>>> c.myversion
100
>>> c2.myversion #在实例c2中myversion的值依然没有改变
1
>>> my.myversion=150 #通过类直接修改myversion的值
>>> c.myversion #实例c中的值没有发生改变,因为实例c中已经有一个名叫myversion的变量了
100
>>> c2.myversion #实例c2中值随着类的改变而改变,因为实例c2中没有myversion这个变量,只能访问类属性中的变量
150
>>> my.myversion
150
>>>
绑定和方法调用
方法只有在所属的类拥有实例的时候才能被调用,当存在一个实例的时候,方法才被认为是绑定到了那个实例,没有实例时方法就是未绑定的
self是什么:self变量用于在类实例方法中引用方法所绑定的实例,因为在方法的实例在任何方法调用中总是作为一个参数传递的,self被选中用来代替实例。
调用绑定方法
就是用实例调用这个方法
调用非绑定方法
调用非绑定方法并不经常用到,主要应用场景:你在派生一个子类 ,而且你要覆盖父类的方法,这时你需要调用哪个父类中想要覆盖的构造方法。
class Foo(object):
def __init__(self,name,sex,age):
self.name=name
self.sex=sex
self.age=age
def show(self):
print "name is %s,sex is %s"%(self.name,self.sex)
class Bar(Foo):
def __init__(self,name,sex,age,id,salary):
super(Bar,self).__init__(name,sex,age) #这就是在调用父类非绑定方法
#或者Foo.__init__(self,name,sex,age) 现在不用了
self.id=id
self.salary=salary
def info(self):
print "name is %s salary is %s"%(self.name,self.salary)
>>> f=Bar('cmustard','F',22,123123,1000)
>>> f.show()
name is cmustard,sex is F
>>> f.info()
name is cmustard salary is 1000
>>>
静态方法和类方法
静态方法中默认是不能访问类变量和实例变量。
类方法不能访问实例变量
class TestS(object):
@staticmethod
def foo():
print "calling static method foo()"
class TestC(object):
@classmethod
def foo(cls):
print "calling class method foo()"
print "foo() is part of class",cls.__name__
>>> s=TestS()
>>> s.foo()
calling static method foo()
>>> TestS.foo() #直接调用静态方法
calling static method foo()
>>>
>>>
>>> c=TestC()
>>> TestC().foo()
calling class method foo()
foo() is part of class TestC
>>> c.foo()
calling class method foo()
foo() is part of class TestC
>>>
property属性
@property装饰器是把方法转变成属性访问,简单来说就是实例访问这个方法的时候,不需要加括号
#coding:utf-8
class TestP(object):
def __init__(self,name):
self.name=name
self.num=0
@property
def total(self):
return "is %s"%self.num
@total.setter #设置属性的值
def total(self,num):
self.num=num
@total.deleter #删除这个属性
def total(self):
del self.num
p=TestP('cmustard')
print p.total #is 0
#怎么给他赋值呢 需要setter装饰器
p.total=10
print p.total #is 10
#怎么删除这个属性
del p.total
print p.total #'TestP' object has no attribute 'num'
这个有什么作用呢,我们还是可以直接改变num的值呀。。
p.num=100
print p.num #100
这时我们需要引用私有变量
class TestP(object):
def __init__(self,name):
self.name=name
self.__num=0 #设置了一个私有变量
@property
def total(self):
return "is %s"%self.__num
@total.setter #设置属性的值
def total(self,num):
self.__num=num
@total.deleter #删除这个属性
def total(self):
del self.__num
p=TestP('cmustard')
p.total=100
print p.total #is 100
#倘若直接修改呢
p.__num=130
print p.__num #130
print p.__dict__ #{'_TestP__num': 100, 'num': 120, 'name': 'cmustard', '__num': 130},这里只是在实例属性中添加了一个新的变量
print p.total #is 100 还是没有改变
#特殊情况
p._TestP__num=110
print p.total #is 110 这就改变了,不过我们一般不会这么用的