四、 面向对象(一)
“python基础系列”目录:
面向对象和面向过程编程的理解:
面向对象编程和函数式编程(面向过程编程)都是程序设计的方法,不过稍有区别。
面向过程编程:
1. 导入各种外部库
2. 设计各种全局变量
3. 写一个函数完成某个功能
4. 写一个函数完成某个功能
5. 写一个函数完成某个功能
6. 写一个函数完成某个功能
7. 写一个函数完成某个功能
8. ......
9. 写一个main函数作为程序入口
在多函数程序中,许多重要的数据被放置在全局数据区,这样它们可以被所有的函数访问。每个函数都可以具有它们自己的局部数据,将某些功能代码封装到函数中,日后便无需重复编写,仅调用函数即可。从代码的组织形式来看就是根据业务逻辑从上到下垒代码 。
面向对象编程:
1. 导入各种外部库
2. 设计各种全局变量
3. 决定你要的类
4. 给每个类提供完整的一组操作
5. 明确地使用继承来表现不同类之间的共同点
6. 根据需要,决定是否写一个main函数作为程序入口
面向对象编程中,将函数和变量进一步封装成类,类才是程序的基本元素,它将数据和操作紧密地连结在一起,并保护数据不会被外界的函数意外地改变。类和和类的实例(也称对象)是面向对象的核心概念,是和面向过程编程、函数式编程的根本区别。
并不是非要用面向对象编程,要看你的程序怎么设计方便,但是就目前来说,基本上都是在使用面向对象编程。
类的基本用法
面向对象是通过定义class类来定义,这么说面向对象编程就是只使用class类,在class类中有封装,继承的功能,并且还可以构造要传入的参数,方便控制。
# 案例一
import time
# 定义一个类名为studetn
class studetn:
def __init__(self,idx):
# 定义初始化构造,这里使用init,还有别的属性比如reversed,iter之类的
self.idx=idx
# 初始化变量,方便继承
def runx(self):
# 定义运行函数,从上面继承变量
print(self.idx)
# 打印出idx的值,或者做一些别的处理
time.sleep(1)
# 这是类的调用,一定要记得类的使用方法,首先传入参数,类赋值给一个变量a
a=studetn('a')
# 然后调用这个类下面定义的函数
a.runx()
重要名词解释
-
类(Class): 用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。其中的对象被称作类的实例。
-
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
-
实例:也称对象。通过类定义的初始化方法(init()),赋予具体的值,成为一个”有血有肉的实体”。
-
实例化:创建一个类的实例(类的具体对象)。
-
实例变量:在类的声明过程中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。只作用于当前实例。
-
类变量:类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外。
-
数据成员:类变量、实例变量、实例方法、类方法、静态方法和属性等的统称。
-
方法:类中定义的函数。
-
静态方法:不需要实例化就可以由类执行的方法
-
类方法:类方法是将类本身作为对象进行操作的方法。
-
方法重写:如果从父类继承的方法不能满足子类的需求,可以对父类的方法进行改写,这个过程也称override。
-
封装:将内部实现包裹起来,对外透明,提供api接口进行调用的机制
-
继承:即一个派生类(derived class)继承父类(base class)的变量和方法。
-
多态:根据对象类型的不同以不同的方式进行处理。
类与实例
import time
import requests
class cc:
ccc = 'ccc'
# cc就是类名 如果想要继承别的类 就class cc(threading) 意思就是从threading继承
def __init__(self,a,b,c):
self.a=a
self.b=b
self.c=c
# 定义构造的过程就是实例化
def runx(self):
print(self.a*100)
print(self.b*5)
print(self.c*2)
def runy(self):
print(requests.get('http://www.langzi.fun').headers)
e = cc('AAA','CCC','EEE')
# 这两个就是调用类里面的方法
e.runx()
e.runy()
#实例变量指的是实例本身拥有的变量。每个实例的变量在内存中都不一样。
print (e.c)
#类变量,在类里面找到定义的变量。
print (e.ccc)
类中的三种方法和两种属性
实例方法
#实例方法和实例属性的使用
class Hero(object):
# 实例方法的属性定义
def __init__(self,name,hp):
"""
用来做变量初始化或赋值操作,在类实例化的时候会被自动调用,被所有实例方法共用。
"""
self.name = name # 实例属性 (实例方法的属性)
self.hp = hp # 实例属性 (实例方法的属性)
def info(self):
"""
实例方法
在类的实力方法中,通过self 获取改对象所对应的属性,self代表当前实例对象本身
"""
print('英雄{name1}的生命值为{hp1}'.format(name1= self.name,hp1=self.hp))
def move(self,speed):
print('英雄{name1}的生命值为{hp1},其移动速度为{speed1}'.format(name1= self.name,hp1=self.hp,speed1=speed))
# 类的实例化
hero = Hero('安吉拉',100) #实例化一个英雄对象
#获取对象的实例方法
hero.info()
#对实例属性进行修改
hero = Hero('安吉拉',100)
hero.hp = 0
hero.info()
hero = Hero('亚索',80) #再次实例化一个英雄对象
#获取对象的实例方法
hero.move(50)
静态方法
解释:python 中允许定义与️"类对象"无关的方法,称之为静态方法。
详解:在开发中,如果需要在类中,封装一个既不需要访问实例属性或者调用实例方法,也不需要访问类属性或者类方法的时候,可以把这个方法封装成一个静态方法。
静态方法需要装饰器@staticmethod来标识,告诉解释器这是一个静态方法。
import requests
class ff:
@staticmethod
def runx():
#不访问实例属性或类属性
print(requests.get('http://www.badui.com').status_code)
#通过类名.静态方法名来调用这个静态方法, 这个操作不需要实例化。
ff.runx()
# 总结:经常有一些跟类有关系的功能但在运行时又不需要实例参与的情况下需要用到静态方法.
类方法
类方法由类调用,采用@classmethod装饰,至少传入一个cls(代表类本身,类似类实例化中的self)参数。执行类方法时,自动将调用该方法的类赋值给cls。建议只使用类名.类方法的调用方式。(虽然也可以使用实例名.类方法的方式调用)
实际案例
如果要构造一个类,接受一个网站和这个网站的状态码,然后打印出来。就像这样:
# 1.类属性:类对象所拥有的属性,被类对象的所有实例对象所公用,对于公有的类属性,在类外可以通过类对象和实例对象访问
class People():
char = 'eat' #公有属性
__age = 12 #私有属性
_name = 'leon' # 受保护属性
p1 = People() #实例化类
print(p1.char) #获得公有类属性
# print(p1.__age) # 错误 不能在类的外部访问类对象的私有属性
# 2.类方法:类对象所拥有的方法,需要用装饰器@classmethod来标实,对于类方法,第一个参数必须是类对象,一般用cls作为第一个参数。能够通过实例对象和类对象去访问。
class People():
country = 'china'
#类方法用classmethod来修饰
@classmethod
def get_country(cls):
return cls.country
@classmethod
def set_coutry(cls,country):
cls.country = country
p = People()
print(p.get_country()) #可以用实力对象来引用(不建议使用)
print(People.get_country()) #可以通过类对象来引用(建议使用)
p = People()
p.set_coutry('japan')
print(p.country)
总结实战案例
class Person(object):
grade = 6 # 类变量
#实例属性(此方法为构造方法),
def __init__(self,name):
self.name = name #将构造方法中的name参数赋值给self.name
self.age = 20 #定义一个新的变量
#实例方法
def sayHi(self): # 加self区别于普通函数,本质指的是当前实例本身。
print('Hello, your name is?', '{}'.format(self.name))
#实例方法
def sayAge(self,month):
print('My age is {} years old,and {} month' .format(self.age,month))
@staticmethod # 静态方法不能访问实例变量,类变量
def sayName(name):
print("my name is {name}".format(name=name))
@classmethod # 类方法是为类本身定义的方法,它可以访问类属性,但不能访问实例属性
def classMethod(cls):
print('class grade:', cls.grade)
#通过实例化对象来调用类变量
p = Person('leon') # 实例化一个特定对象(也称类的实例化)
print('p.grade:', p.grade) # 实例对象调用类变量(因为类变量在整个类中起作用(除静态方法),所以可以用实例化对象来调用类属性)
#通过实例化对象来修改类变量
p.grade = 9
print(p.grade) # 结果呢为9,实例改变类变量时,其grade变量只会在实例中改变
#重新实例化一个对象,再曲调用类变量,发现类变量并没有被修改,说明通过实例对象来改变类属性,只在当前实例对象中起作用,在其他实例对象中不起作用。
p1 = Person('jack')
print(p1.grade) #在p1这个实例中grade变量没有被改变。
# 实例对象调用不带参的实例方法
p1.sayHi()
# 实例对象调用带参的实例方法
p1.sayAge(9) # 实例对象调用实例方法
# 类对象调用类变量
print(Person.grade)
#类对象调用类方法
Person.classMethod()
#调用静态方法的两种办法
Person.sayName('jack') #通过类对象直接来调用
Person('leon').sayName('jack') #通过实例化后的实例对象来调用