类及其类属性
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 这就改变了,不过我们一般不会这么用的
来源:https://www.cnblogs.com/cmustard/p/6769933.html