Python3 面向对象编程OOP

生来就可爱ヽ(ⅴ<●) 提交于 2020-03-27 14:52:24

OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

特性:封装,继承,多态


 

 

1.类

  在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。

1)创建类:(实例模板)

  名词--属性

  动词--方法

Eg:

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)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()

  注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。

  2)实例可以自由绑定属性/方法(类也可以)

#为实例绑定属性/方法,只对当前实例有效>>> bart.name = 'Bart Simpson'
>>> bart.name
'Bart Simpson'---------------------------------->>> def set_age(self, age): # 定义一个函数作为实例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25#为了作用于所有实例可为类绑定
>>> def set_score(self, score):
...     self.score = score
...
>>> Student.set_score = set_scor
>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99#实例绑定可覆盖类同名属性
class Student(object):
    name = 'Student'

#当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。来测试一下:

>>> class Student(object):
...     name = 'Student'
...
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student

怎么限制呢?----类内__slot__变量

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
然后,我们试试:

>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

    子类实例允许定义的属性=自身的__slots__+父类的__slots__。)

  3)数据封装

  在类内自定义xxxset和xxxget方法,内部细节透明化

class Student(object):
    ...

    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'

 

2.访问限制

私有变量/方法 (内部属性不被外部访问) :__双下划线开头

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
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'

外部想获取/修改----类内设置set和get

注意:

1.变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name____score__这样的变量名。

2.一个下划线开头的实例变量名,比如_name约定俗成的规定意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”

3.事实上,__开头的变量也是可以在类外访问的,因为私有化实际上是python解释器对变量改名。访问方式_类名__私有变量(eg: _Student__name),强烈建议不要访问。

 

3.继承

从父类/基类/超类继承现有框架(变量,方法),发展新特性(自己的变量,方法)

子类获得了父类的全部功能,python允许多重继承

Eg:

#比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:

class Animal(object):
    def run(self):
        print('Animal is running...')
#当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:

class Dog(Animal):
    pass

class Cat(Animal):
    pass

 

类型判断 isinstance和type

  isinstance:子类=父类,父类!=子类

a = list() # a是list类型
b = Animal() # b是Animal类型
c = Dog() # c是Dog类型
>>> isinstance(a, list)
True
>>> isinstance(b, Animal)
True
>>> isinstance(c, Dog)
True
>>> isinstance(c, Animal)
True
#父类!=子类
>>> b = Animal()
>>> isinstance(b, Dog)
False#----------------------其他判断
>>> isinstance(d, Dog) and isinstance(d, Animal)
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

  type():返回对应的Class类型

#基本类型
>>> 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'>

返回class类型

>>> type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False#判断是否是函数
>>> import types
>>> def fn():
...     pass
...
>>> 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

 

4.多态

子类使用同名方法覆盖父类方法

class Dog(Animal):

    def run(self):
        print('Dog is running...')

class Cat(Animal):

    def run(self):
        print('Cat is running...')-------------------------------------
Dog is running...
Cat is running...

应用:接收父类参数,可接受传入子类

def run_twice(animal):
    animal.run()
    animal.run()
----------------------
>>> run_twice(Animal())
Animal is running...
Animal is running...
------------------------
>>> run_twice(Dog())
Dog is running...
Dog is running...

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!