Python学习(六)—— 面向对象编程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q1449516487/article/details/86594798

一、类和实例

1.类的定义

在Python中,定义类是通过class关键字:

class 类名(继承类):    //所有类最终都会继承object类
    pass

2.类的变量

定义类的变量有两种方法,静态定义和动态定义:

(1)静态定义:所谓静态定义,是指在创建类的时候定义

class Student(object):
    def __init__(self, name, score):    //定义初始化函数,self表示类本身(必须加),后面的变量可以任意定义
        self.name = name
        self.score = score

(2)动态定义:所谓动态定义,是指在实例化类之后,将变量绑定给实例

>>> bart = Student()
>>> bart.name = 'Bart Simpson'
>>> bart.name
'Bart Simpson'

3.类的方法

class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def print_score(self):        //定义类的方法,除了第一个参数是self外,其他和普通函数一样
        print('%s: %s' % (self.name, self.score))

4.类的实例化

将类实例化之后,可以调用类的变量和方法:

>>> 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))
...
>>> bart = Student('Bart Simpson', 59)        //实例化类,调用类的__init__方法,self不需要传入
>>> bart.name                                 //调用类的变量
'Bart Simpson'
>>> bart.print_score()                        //调用类的方法
Bart Simpson:59

二、访问限制

参考类参数的动态定义,我们可以从外部改变一个实例的参数。如果要让内部不被外部访问,可以把属性的名称前加上两个下划__,让参数变成私有变量(private)。重新定义Student类:

>>> 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))
...
>>>
>>>
>>> bart = Student('Bart Simpson', 59)
>>> bart.__name                                //外部不能直接访问类的__name变量
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'
>>>
>>>
>>> bart.__name = 'Bob'                        //给__name设置参数
>>> bart.__name                                //表面上定义成功,实际上是给实例定义了另一个变量
'Bob'
>>> bart.print_score()                         //可见结果并不成功
Bart Simpson:59

实际上,外部想要访问类内部的私有变量是有方法的(只是不推荐这么做):

>>> bart._Student__name            //Python解释器对外把__name变量改成了_Student__name,但是不同的解释器定义不同,所有不推荐这么做
'Bart Simpson'

三、继承和多态

1.继承:当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。实例如下:

>>> class Animal(object):                    //定义一个Animal作为基类
...     def run(self):                       //定义一个run()方法
...         print('Animal is running...')
...
>>> class Dog(Animal):                       //定义一个子类Dog,继承Animal基类
...     pass
...
>>> class Cat(Animal):                       //定义一个子类Cat,继承Animal基类
...     pass
...
>>> dog = Dog()        
>>> dog.run()                                //dog实例调用了基类的run()方法
Animal is running...
>>> cat = Cat()
>>> cat.run()                                //Cat实例调用了基类的run()方法
Animal is running...

子类Cat和Dog继承了基类Animal的run()方法,理论上子类将继承基类的所有方法和参数。

如果子类要对基类的方法进行改写,也可以在子类中重新定义该方法:

>>> class Dog(Animal):
...     def run(self):                    //重新定义run()方法
...         print('Dog is running...')
...     def eat(self):                    //也可以自定义其他方法
...         print('Eating meat...')
...
>>> dog = Dog()
>>> dog.run()                             //dog实例调用重新定义的run()方法
Dog is running...
>>> dog.eat()
Eating meat...

2.多态:在讲解什么是多态前,可以先通过isinstance(实例,类型)判断子类和基类的关系

>>> animal = Animal()
>>> dog = Dog()
>>> isinstance(animal, Animal)             //animal的数据类型是Animal
True
>>> isinstance(dog, Dog)                   //dog的数据类型是Dog
True
>>> isinstance(dog, Animal)                //dog的数据类型可以是Animal
True
>>> isinstance(animal, Dog)                //而animal的数据类型却不可以是Dog
False

从上面的例子可以看出,子类的数据类型可以用父类的数据类型来表示,而父类的数据类型却不可以用子类的数据类型来表示。利用上面的特性,我们就可以获得多态的便利性:

>>> def run_twice(animal):             //定义一个函数
...     animal.run()
...     animal.run()
...
>>> run_twice(Animal())                //传入Animal类的实例,则调用Animal类的run()方法
Animal is running...
Animal is running...
>>> run_twice(Dog())                   //而传入Dog类的实例,则调用Dog类的run()方法
Dog is running...
Dog is running...
>>> run_twice(Cat())                   //以此类推,调用不同的子类,不需要对run_twice()方法做任何修改。实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
Cat is running...
Cat is running...

实际上,Python这种动态语言,和静态语言(Java等)相比,还有一个更大的好处就是:

语言 好处
静态语言(Java等) 如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。
动态语言(Python等)

动态语言则不一定需要传入Animal类型,只需要保证传入的对象有一个run()方法,这就是所谓的“鸭子类型”。

四、获取对象信息

问:当我们获得一个对象的引用时,如何知道这个对象是什么类型,有哪些方法呢?

答:可以使用type()isinstance()dir()。三个函数的用法如下所示:

函数 用法
type()

判断基本类型:

type(123) -> <class 'int'>

type('str') -> <class 'str'>

type(None) -> <type(None) 'NoneType'>

判断函数或者类:

type(abs) -> <class 'builtin_function_or_method'>

type(a) -> <class '__main__.Animal'>

if语句中判断两个变量的type类型:

type(123) == type(456)  -> True

type(123) == int  -> True

type('abc') == type('123')  -> True

type('abc') == str -> True

type('abc') == type(123)  -> False

if语句中判断变量是否是函数:(使用types模块中定义的常量)

type(fn) == types.FunctionType  -> True

type(abs) == types.BuiltinFunctionType -> True

type(lambda x: x) == types.LambdaType -> True

type((x for x in range(10))) == types.GeneratorType -> True

isinstance()

首先有以下继承关系:object -> Animal -> Dog -> Husky

它们的实例分别是:                     animal      dog     husky

判断它们的类型:

isinstance(animal, Animal) -> True

isinstance(dog, Animal) -> True

isinstance(husky, Animal) -> True

isinstance(husky, Dog) -> True

判断基本类型:

isinstance('a', str) -> True

isinstance(123, int) -> True

isinstance(b'a', bytes) -> True

判断变量是否某些类型中的一种:

isinstance([1, 2, 3], (list, tuple)) -> True

isinstance([1, 2, 3], (list, tuple)) -> True

dir()

dir()函数返回一个包含字符串的list,比如获得一个str对象的所有属性和方法:

>>> dir('ABC')

['__add__', '__class__', ..., '__subclasshook__', 'capitalize', 'casefold', ..., 'zfill']

仅仅把属性和方法列出来是不不够的,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:

---------------------------------------定义一个类并实例化它的对象---------------------------------

>>> class MyObject(object):

...          def __init__(self):

...                self.x = 9

...          def power(self):

...                return self.x * self.x

...

>>> obj = MyObject()

---------------------------------------判断该对象是否包含某属性或方法---------------------------

hasattr(obj, 'x') -> True

hasattr(obj, 'y') -> False

hasattr(obj,'power') -> True

---------------------------------------获取该对象的某属性或方法------------------------------------

getattr(obj, 'x') -> 9

getattr(obj, 'z', 404) -> 404 //获取属性'z',如果不存在,返回默认值404

fn = getattr(obj, 'power') //获取obj的power方法

---------------------------------------设置该对象的某属性------------------------------------

setattr(obj, 'y', 19)

五、实例属性和类属性

实例属性和类属性的定义如下:

属性 定义
类属性 所谓类属性,是指我们在定义类的时候,在类内部定义好的属性
实例属性 而实例属性是指,将一个类实例化之后,在运行状态下给实例定义的属性

例子如下:

>>> class Student(object):
...     def __init__(self, name):
...         self.name = name                    //name在类内定义,表示类属性
...
>>> s = Student('Bob')                          //将Student类实例化
>>> s.name
'Bob'
>>> s.score = 97                                //给s实例定义一个score属性,score表示实例属性

在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。

猜你喜欢

转载自blog.csdn.net/q1449516487/article/details/86594798