日知录(五):python面对对象编程
OOP
理解OOP的想法
终于到这个part了,如何面对对象编程呢?
来一个高大上的定义:面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
之前学的是C语言,是一种面向过程的程序设计思想。
1.在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。
2.类(Class)和实例(Instance)的概念
Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student,比如,Bart Simpson和Lisa Simpson是两个具体的Student。
3.面向对象的设计思想是抽象出Class,根据Class创建Instance。
4.我大白话讲讲:简单点理解,动物分类:界门纲目科属种,比如狼这一实例属于犬科,犬科的基本特点,在_init_内定义(数据封装)。狼在继承犬科(继承)这一基本特点后,还有一些自己的特点,或者可以重新定义一些基本特点(多态性)。同时,犬科与猫科之间,必定是由一些特点是根本性的,不能改变的。(即 该类的私有属性)
接下来看看我们对象的特性
特点一:数据封装
# -*- coding: UTF-8 -*-
#创建一个新的抽象类:用class语句,Student为类的名称
class Student(object):
#__init__()是一种特殊的方法,被称为类的构造函数或初始化方法
def __init__(self,name,score):
self.name=name
self.score=score
#slef代表类的实例,self在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
def print_score(self):
print('%s:%s' % (self.name,self.score))
#创建类的实例对象bart,并通过__init__方法接收参数
bart = Student('Bart Simpson', 5)
#访问对象的属性.print_score()
bart.print_score()
该例中定义了print_score()方法,即在Student类的内部定义访问数据的函数print_score(),这样,就把“数据”给封装起来了。这些封装数据的函数是和Student类本身是关联起来的,我们称之为类的方法。
定义方法时进行数据封装
1.定义一些特殊方法
一般是系统定义名字,类似__init()__之类的
- __foo __(): 定义的是特殊方法,一般是系统定义名字 ,类似 __ init __() 之类的。
- _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
2.定义类的私有属性
__private_attrs: 两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs
3.定义类的方法
def 关键字:在类的内部,使用 def 关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数
4.定义类的私有方法
__private_method:两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用 self.__private_methods
试图从外部访问私有变量时的报错
# -*- coding: UTF-8 -*-
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print(self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print(counter.publicCount)
print(counter.__secretCount )
# 报错,实例不能访问私有变量
AttributeError: 'JustCounter' object has no attribute '__secretCount'
Python不允许实例化的类访问私有数据,但你可以使用 object._className__attrName( 对象名._类名__私有属性名 )访问属性
# -*- coding: UTF-8 -*-
class Runoob:
__site = "www.runoob.com"
runoob = Runoob()
print (runoob._Runoob__site)
结果
www.runoob.com
特点二:继承
当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
1.继承1个类
class 派生类名(基类名)
···
2.继承多个类
class A: # 定义类 A
.....
class B: # 定义类 B
.....
class C(A, B): # 继承类 A 和 B
.....
3.方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Eating meat...')
class Cat(Animal):
def run(self):
print('Cat is running...')
dog = Dog()
dog.run()
cat = Cat()
cat.run()
运行结果
Dog is running...
Cat is running...
当子类和父类都存在相同的run()方法时,调用时子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态
特点三:多态性
多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可,牵一发而动全身的感觉,就是从父类更改就可以。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态。
获取对象信息
在引用对象时,了解对象的类型和方法
1. type()
2. isinstance()
要判断class的类型,可以使用isinstance()函数
3. dir()
要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list。
配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态
类属性与实例属性
给实例绑定属性的方法是通过实例变量,或者通过self变量
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
以下摘自廖雪峰老师的教程实例。
当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。来测试一下:
>>>class Student(object):
name = 'Student'
>>>s = Student() # 创建实例s
>>>rint(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
在编写程序的时候,不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
本文地址:https://blog.csdn.net/weixin_43883903/article/details/107175514