Python:class类

感情迁移 提交于 2020-02-21 07:57:42

类及其类属性

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  这就改变了,不过我们一般不会这么用的
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!