初学Python 5 Python中的类和对象

“类”,可以认为是把对象按照某一属性划分的类。
用class定义类,后面跟上类的名字;类名后面的括号中的内容表示该类的父类。也就是该类继承自的父类,如果没有合适的父类,就用object类,因为所有类最终都会继承这个类。
在类的定义之后要再定义函数类才能有用,暂且不用的时候可以写上pass。
创建了一个类以后,可以把它归属于某个父类,也可以给它创建子类。且支持多对多。父类、子类都不唯一。

class things:
    pass
class apple(frult):
    pass
chen=apple()

有了类以后就可以创建属于某一个或多个类的对象object,也可以称“实例”。
注意在创建对象使用函数的时候是相似的,在类名后面要加上括号。即类名()
对象可以调用它属于的类和该类的父类所提供的函数。用对象加点.加函数名来操作对象。
在类的定义下面再用def定义函数,就定义了该类的特征。也就是该类所拥有的函数,类可以使用它自己以及它的父类所拥有的特征(函数)。任何在父类中定义的函数,在子类中都可以使用。所以子类定义的对象,可以调用父类中定义的函数,称该对象继承了这些函数。

class apple(things):
    def est(self):
        print("delicious')

可以创建多个同属于一个类的对象,称每一个对象都是该类的一个实例。可以分别操作每一个对象。类是抽象的模板,而实例是根据类创建出来的一个个具体的对象。个个实例各自的数据互相独立、互不影响。
可以自由地给一个对象(实例)绑定属性。
在创建实例的时候,可以给他绑定一些属性,用__init__方法
注意init的第一个参数永远是self,表示创建的实例本身。
这里的方法是与实例绑定的函数,和外部定义的函数不同,这些方法可以直接访问实例的数据。在实例上创建方法,可以直接操作实例内部的数据,而无须知道内部的实现细节。
而且Python允许在创建实例以后,再给实例绑定其他,而这些另外给具体实例绑定的变量,其他实例是没有的。所以,同一个类的不同实例,其拥有的变量名称可能是不同的。

>>> class student(object):
    def __init__(self,name,score):
        self.name=name;
        self.score=score

有了init方法以后,在创建实例的时候就不能传入空的参数了,必须要传入与init匹配的参数,self不用传入,解释器会自动执行。
类描述了它能做什么,但是实际上是这个类的对象在做这些事情。

>>> chen=student('chenyuting',23)
>>> chen
<__main__.student object at 0x03056C90>
>>> chen.name
'chenyuting'
>>> chen.score
23

与普通函数的定义相比,在类中定义的函数有一点不同:第一个参数一定是self且在调用时不需要传该参数。其他都相同,包括默认参数、可变参数、关键字参数、命名关键字参数都相同。

数据封装
也是面向对象编程的一个特点,即要访问类中的数据,既可以从外面通过函数来访问,也可以在类的内部定义访问类中的数据的函数,这样就说把数据给“封装”起来了,这些封装数据的函数和类本身是关联起来的,称之为类的方法

#这是从外部访问
>>> def print_score(std):
    print('%s %s' %(std.name,std.score))
>>> print_score(chen)
chenyuting 23
#这是从内部调用
>>> class student(object):
    def __init__(self,name,score):
        self.name=name;
        self.score=score
    def print_score(self):
        print('%s %s' %(self.name,self.score))  
>>> chen=student('chenyuting',23)
>>> chen
<__main__.student object at 0x05C58A70>
>>> chen.print_score
<bound method student.print_score of <__main__.student object at 0x05C58A70>>
>>> chen.print_score()
chenyuting 23

这样就把内部的数据和逻辑封装起来,外部不知道内部的实现细节。
可以在属性的名称前加上__ 这样就变成了私有变量,只能从内部访问。在外部无法访问。

>>> class student(object):
    def __init__(self,name,score):
        self.__name=name;
        self.__score=score
    def print_score(self):
        print('%s %s' %(self.__name,self.__score))  
>>> chen=student('chenyuting',22)
>>> chen.print_score()
chenyuting 22
>>> chen.name
Traceback (most recent call last):
  File "<pyshell#36>", line 1, in <module>
    chen.name
AttributeError: 'student' object has no attribute 'name'

继承和多态
当定义某个类时,可以从现有的类继承,新的类成为该类的子类,该类称为父类、基类、超类。
继承的好处是1.子类自动的拥有父类的全部方法。当然也可以单独为子类增加一些方法。
2.如果有相同名称的方法,则子类的方法会覆盖父类的方法,即子类的方法优先级更高。
多态 从数据类型的角度来说,如果某个实例的数据类型是某个子类,那么的数据类型也可以看作是该子类的父类。但反过来不行。
这样,子类就可以自己重新定义父类不合适的方法,以相同的函数名。而在使用的时候,我们无需担心。
Python的开闭原则:对扩展开放,对修改封闭

多态的好处是,让子类和父类有相同功能相同名称的方法,我们在使用时,只要知道他们的父类的类型,无需确切的知道是哪个子类,因为优先级的关系,会自动帮我们选择子类的方法来执行,即由运行时该对象的确切类型决定。
而任何类,都可以追溯到根类object类。继承关系就像一棵树一样。
Python 的鸭子类型

用type(对象名)可以知道该对象是什么类型的

<class 'int'>
>>> type('123')
<class 'str'>
>>> list=[1,22,3,4]
>>> type(list)
<class 'list'>
#对于函数或者类,或者指向函数或者类的变量,其返回的类型就是class
>>> type(abs)
<class 'builtin_function_or_method'>
>>> f=abs
>>> f(-3)
3
>>> type(f)
<class 'builtin_function_or_method'>

types模块中定义的常量也可以用来判断一个对象的类型

>>> import types
>>> type(abs)==types.FunctionType
False

isinstance() 判断所属类
对于类的继承关系,用isinstance()函数判断,只要该对象属于该类,或者该类是该对象的父类,都返回True。而且能用type()判断的基本类型,也能用isinstance()判断。

>>> isinstance(chen,student)
True
>>> isinstance(123,int)
True
>>> isinstance('123',str)
True

dir()
以list的形式返回一个对象的所有属性和方法

>>> dir(chen)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_student__name', '_student__score', 'print_score']
>>> dir(123)
>>> dir(‘44abca')
>>> 'ans'.upper
<built-in method upper of str object at 0x05C584A0>
>>> 'ans'.upper()
'ANS'

注意,在Python中,左右都带有下划线的方法是有特殊用途的
getattr() setattr() hassttr()可以获取、设置、判断一个对象的状态。

>>> class my(object):
    def __init__(self):
        self.x=8
>>> chen=my()
>>> hasattr(chen,'x')
True
>>> chen.x
8
>>> hasattr(chen,'y')
False
>>> setattr(chen,'y',123)
>>> chen.y
123
>>> getattr(chen,'y')
123

如果试图获取不存在的属性,就会抛出错误。
用法:试图从该文件流fp中读取图像,如果该fp对象没有read()方法,就不能读取,所以用hasattr()来判断。

def readImage(fp):
    if hasattr(fp, 'read'):
        return readData(fp)
    return None

类属性和实例属性
可以给实例单独定义一些属性,称为实例属性。
而像定义方法一样,在定义类的时候加上一些属性,称为类属性。,该属性归类所有,而且该类的所有子类都可以访问到这个属性。所以如果实例和类由相同的属性,要注意。因为实例属性会覆盖类属性,可能你想访问类属性,但是实际会访问到实例属性。把同名的实例属性删了就可以访问同名的类属性了。

对某个实例绑定的属性或方法,对其他实例是无效的,要想给所有实例绑定属性或方法,可以通过给类绑定,这样所有继承自该类的实例都有了该属性或方法。而且,不仅仅是在定义时,Python作为一种动态语言,允许在定义以后,再给他绑定,这都是可以的。
__slots__ 变量。
如果想要限制实例的属性,可以在定义类时加上这个变量,这样就限制了class能添加的属性。

>>> class stu(object):
    __slots__=('name','age')
>>> chen=stu()
>>> chen.age=11
>>> chen.age
11
>>> chen.name='chenyu'
>>> chen.name
'chenyu'
>>> chen.score=111
Traceback (most recent call last):
  File "<pyshell#83>", line 1, in <module>
    chen.score=111
AttributeError: 'stu' object has no attribute 'score'

注意,__slots__ 对属性的限制,仅对当前类的直接实例起作用,对该类的子类时不起作用的,如果要给子类也加上限制,就要在定义子类时另加__slots__,这样子类的限制就是该子类的限制加上其父类的限制。

装饰器
广泛应用在类的定义中,可以用简短的代码,保证对参数必要的检查。

#不用装饰器
class student(object):
    def get_score(self):
        return self.score
    def set_score(self,value):
        if(not isinstance(value,int)):
            raise ValueError('score must be a integer')
        if(value<0 or value>100):
            raise ValueError('score must between 1-100')
        self.score=value        
>>> s=student()
>>> s.set_score (88)
>>> s.get_score()
88

使用@property装饰器 注意使用装饰器的区别

>>> class student(object):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self,value):
        if(not isinstance(value,int)):
            raise ValueError('score must be a integer')
        if(value<0 or value>100):
            raise ValueError('score must between 1-100')
        self._score=value
>>> q=student()
>>> q.score=99  #实际上等于q.set_score(99)
>>> q.score     #相当于q.get_score()
99

多重继承:一个子类可以继承自多个父类
Python允许多重继承,MinIn是一种常见的设计。而Java时单一继承的语言,不能使用MixIn。
MixIn的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系。
在使用多重继承的便利的同时,解决多重继承带来的问题,比如当不同的父类中由相同的方法,就会产生冲突。
多重继承的顺序可以像拓扑排序那样理解,从入度为0的位置开始。帮助理解。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值