【python基础】4.1 面向对象(待修改)
一、名词介绍
1.1 面向对象与面向过程
解决问题的两种思路
面向对象 |
面向过程 |
|
概念 |
将构成问题的事物,分解成若干个对象,把数据以及对数据的操作放在一起,作为一个相互依存的整体 比如moba游戏里每个英雄(类)有不同的技能(方法)和外形(属性),你创建了一个账号,你玩的每个英雄又是独一无二的(实例化),他们都有自己的属性和方法。 是一种代码封装的方法,将相关数据和实现函数封装到一起 |
直接将步骤分析出来,然后用函数把步骤一步一步实现,然后再依次调用 |
举例 |
把大象放冰箱 大象类: 鼻子长(属性) 能被放进冰箱(方法3) 冰箱类: 有门(属性) 门能被打开(方法1) 门能被关上(方法2) 主函数: 创建一只叫小明的大象(类的实例化) 创建一个叫小红的冰箱(类的实例化) 小红执行方法1 小明执行方法3 小红执行方法2 |
把大象装冰箱的步骤:
这里的每个步骤依次用函数实现,然后再依次调用 |
1.2 对象,类,实例
名词 |
对象 |
类 |
实例 |
概念 |
一切皆对象 |
抽象的模板,类似工厂生产前的模具,一类事物的统称 |
根据模板(模具)创建出来的具体对象,一类事物中的具体一个 |
具体 |
类,实例,方法,函数...都是对象 对象=属性+方法 静态属性(特性,形容词) 动态方法(能干啥,动作) |
|
杨幂是人类的一个实例,我家养的猫是动物类的一个实例 修改/增加一个对象的属性,这个类其他对象的属性值不变 |
应用 |
a = [1,2,3] print(type(a)) <class ‘list’> 列表类的实例对象 |
class 类名:(类名首字母大写) 属性1 属性2 def 方法1(self): 函数内容 属性3 def 方法2(self): 函数内容 |
实例 = 类名() |
1.3 函数,方法,参数,属性
名词 |
函数 |
方法 |
参数 |
属性 |
概念 |
|
|
1.形式参数:在定义函数时,函数名后面括号中的变量名称叫做“形式参数”,或者称为“形参” 2.实际参数:在调用函数时,函数名后面括号中的变量名称叫做“实际参数”,或者称为“实参” |
|
举例 |
dir(实例名): 查看实例的所有属性和方法 |
行为能力 狗会叫,还会咬人,还会吃东西 |
人类这个类来说 人有两个眼睛,一个鼻子,一张嘴 |
|
应用(定义) |
def 函数名(): 函数内容 |
class 类名:(类名首字母大写) 属性1 属性2 def 方法1(self): 函数内容 属性3 def 方法2(self): 函数内容 |
class 类名:(类名首字母大写) 属性1 属性2 def 方法1(self): 函数内容 属性3 def 方法2(self): 函数内容 |
|
应用(调用) |
函数名() |
方法的调用: 实例名.方法名() |
属性的调用: 实例名.属性名 |
1.4 类方法,静态方法
1.5 私有属性,私有方法,魔术方法,单下划线的方法
私有属性(__属性名) |
私有方法(__方法名) |
魔术方法(__方法名__) |
_方法名 |
|
定义 |
写在类里:不能通过对象直接访问, 不能从外部调用 不能被子类继承 可以在本类内部访问;但是要构造另一个函数来调用 |
前后都有双下划线__,如__init__ 是object自带的,指的是python内置的方法或属性 |
尽量不要乱调用 |
|
写法 |
__属性(双下划线) |
__方法(双下划线) |
_str(单下划线) |
|
意义 |
用来处理类的内部事情,不通过对象处理,起到安全作用。 |
1.6 封装、继承与多态
封装 |
继承 |
多态 |
组合 |
|
创建对象之前,通过类把相关属性和方法打包到一起,然后通过类生成相应的对象 |
|
不同的类中有同名的方法,调用方法时,根据对象的不同,实现的操作也不同, |
||
举例 |
class A: x = 520 def hello(self): print('你好') class B(A): pass b = B() b.x b.hello() |
同名的方法‘叫’,调用鸡的‘叫的方法’为鸡叫,调用鸭‘叫’的方法为鸭叫 |
|
|
覆盖:class B(A): x = 888 def hello(self): print('你好,我是b') b = B() b.x isinstance(b,B) # 判断对象是否属于某个类 isinstance(b,A) (结果都是True) issubclass(A,B) # 判断一个类是否是另一个类的子类 issubclass(B,A) # 前者false后者true |
||||
多重继承: |
二、创建类的一个例子
class Rectangle:#类名首字母大写def __init__(self,length,width): # 初始化方法self.length = length # 生成属性赋予实例,将用户传的length转为实例自身的属性self.width = width # 将用户传的width转为实例自身的属性,# 此时类里面所有的方法都可以直接用,不需要额外的传参def perimeter(self):return (self.length+self.width)*2 def area(self):return self.length * self.width # 实例化rec = Rectangle(5,4)print(rec.__dict__) # 可以看实例自身的属性print(rec.perimeter()) # 不需要传参了print(rec.area())
三、初始化方法__init__与self的含义
在实例产生时,赋予实例属性值
用户在实例化一个长方形时,需要传长和宽两个值,之后初始化方法将其转为长方形实例的属性
初始化方法里的length转换为self.length之后,类当中的所有含有self参数的方法都可以使用这个属性
生成属性赋予实例,将用户传的length转为实例自身的属性
将用户传的width转为实例自身的属性,
此时类里面所有的方法都可以直接用,不需要额外的传参
# 生成实例时,将实例的属性赋予实例,实例刚生成时,没有属性,由初始化方法赋予,
# self指实例本身,即类里面的其他所有方法都可以共用属性,不需要传参了,当作实例自身的属性,而不是用户传递的属性
# 写了self可以认为是同一帮派的人,大家都认可,是一家的,带self的所有人都可以用,把length变成self.length .把传进来的参数看成自己的参数,
# 只要后面别的函数里写了self,self.width,self.length都可以直接用
3.1 self的含义
名称 |
self |
参数 |
|
概念 |
|
实例化对象时不带括号也不会传参数 |
c是类c的实例对象,就具有类c所具有的属性和用法,定义def中这个self代表c这个实例对象, |
class C:def hello():print('你好')
c = C()
c.hello()
报错:hello() 没有参数但是给了一个参数
实例对象和类的方法进行绑定
class C1:def hello1(self):print(self)
c1 = C1()
c1.hello1() # 后两行结果一样
print(c1)
C1.hello1(c1)
<__main__.C1 object at 0x000001D856F76170>
<__main__.C1 object at 0x000001D856F76170>
方法是大家的,属性是自己的
#接上
d = C()
d.x = 250
print(d.x) #250
print(c.x) # 报错
c.x = 520
print(c.x) # 520
print(d.x) #250
class C:def set x(self,v):self.x = v
c = C()
c.__dict__
c.set_x(250)
c.__dict__ # {'x':250}
c.x # 250
class C:x = 100def set_x(self,v):x = v
c = C()
c.set_x(250)
print(c.x) # 100
print(C.x) # 100
C.x = 250
print(c.x) # 250
c.__dict__ # {}
3.2 类的实例化
类是抽象的概念,不能被直接调用,要调用具体的实例,也就是实例化
实例名 = 类(属性) 实例化一个类,属性,除了self以外的
rec = Rectangle(6,4)
# 实例化一个长方形,长为6宽为4
实例化之后,就可以调用类里面的所有方法和属性
print(rec.permiter())
print(rec.area())
# 实例化,生成一个具体的
# 可以看实例自身的属性
# 不需要传参了
3.3 实例的方法
实例方法,定义的方式与函数类似
调用时,实例.方法名()进行调用
注意不要写成类.方法
具体的实例才能调用方法,字符串和列表同理
例子
def perimeter(self):
return (self.length+self.width)*2
def area(self):
return self.length * self.width
方法里的self表示实例本身,所以可以直接使用实例的属性,比如长方形实例的长和宽,调用时,用户不需要传长和宽就可以计算出周长和面积
3.4 私有属性和私有方法
私有属性与私有方法不能从外部被调用,也不能被子类继承
在属性的前面加上__,就是私有属性
在方法前面加上__,就是私有方法
举例
class Test:__pri = '这是一个私有属性'pub = '这是一个普通属性'def __fun_pri(self): # 外部访问不了,只能内部调用print('这是一个私有方法')def fun_pub(self):print('这是一个实例方法')# self.fun_pub() # 不能自己调用自己,会递归卡死def fun_pub2(self):print('这是一个用来调用‘别的方法和属性’的方法')print(self.__pri) # 调用私有属性self.__fun_pri() # 调用私有方法,私有方法不能直接调用,必须构造另一个函数来调用私有方法self.fun_pub() # 调用实例方法print(self.pub) # 调用属性cls = Test() # 实例化# print(cls.__pri) # 私有属性不能被直接调用
print(cls.pub) # 普通属性能被调用
# cls.__fun_pri() # 私有方法不能被直接调用
cls.fun_pub() # 普通方法能被调用
cls.fun_pub2()
运行结果(抛掉注释掉的报错的部分)
这是一个普通属性 ———— print(cls.pub) # 普通属性能被调用
这是一个实例方法 ———— cls.fun_pub() # 普通方法能被调用
这是一个用来调用‘别的方法和属性’的方法 —————— cls.fun_pub2()
这是一个私有属性
这是一个私有方法
这是一个实例方法
这是一个普通属性
属性的隐藏??
四、装饰器
1.1 @property:把方法变成属性
装饰器 声明下面的方法是属性
举例:
b本是一个方法,加括号才能得到方法的返回值。不加括号返回b的类型,以及位于内存的哪个位置信息等
①不加括号
class Class2:def __init__(self):self.a = 100def b(self):return self.a
cls2 = Class2()
print(cls2.b)
<property object at 0x000002A073A05A30>
②加括号
class Class2:def __init__(self):self.a = 100def b(self):return self.a
cls2 = Class2()
print(cls2.b())
100
③ 用@property把方法b变成属性b:属性加括号会报错
class Class2:def __init__(self):self.a = 100@propertydef b(self):return self.a
cls2 = Class2()
print(cls2.b) # int类型,把这个方法变成属性了,属性加括号会报错
100
④有@property,不实例化,打印的还是b的类型,以及位于内存的哪个位置信息等
class Class2:def __init__(self):self.a = 100@propertydef b(self):return self.a
cls2 = Class2()
print(cls2.b) # int类型,把这个方法变成属性了
<property object at 0x000002A073A05A30>
六、继承
先写一个长方形的类
class Rectangle:def __init__(self, length, width): # 初始化方法self.length = length # 将用户传的length转为实例自身的属性self.width = width # 将用户传的width转为实例自身的属性def perimeter(self): # 实例方法return (self.length + self.width) * 2def area(self):return self.length * self.width
3.1 完全继承
写一个正方形继承长方形的类
class Square(Rectangle):pass
squ = Square(6,6)
print(squ.perimeter())
print(squ.area())
3.2 重写父类的某个方法
方法重名需要重写, 由于init方法和父类重名,init新方法把旧的覆盖了
class Square(Rectangle):def __init__(self,side):self.length = sideself.width = side# 不写self.side = side,否则后面的方法都要重写,继承了个寂寞
squ = Square(6)
print(squ.perimeter())
print(squ.area())
3.3 改写父类的某个方法
保留父类原来的代码,增加子类的代码
class Square(Rectangle):def __init__(self,side):self.length = sideself.width = side@ classmethoddef feature(cls):super().features() # 继承父类features方法的代码print('长和宽也相等')
squ = Square(6)
Square.features()
3.4 object
所有类都是object的子类
一个类无论是否声明继承object,实际都继承
继承了object之后,就可以使用object的属性
class Class1(object): # 写不写object都一样'''类的注释'''
# Class1. 即使什么都不写也有方法和属性
cls1 = Class1()
print(Class1.__name__) # 返回类的名称
print(Class1.__base__) # 返回父类的名称
print(Class1.__bases__) # 返回所有父类的名称:元组形式返回
# Square -> Rectangle -> object,祖辈也能用
print(Class1.__doc__) # 返回类的注释
print(cls1.__dict__) # 返回实例的属性
3.5 多继承
一个类可以有多个父类
调用父类中的同名方法时,按照继承顺序进行调用
class Dad1:def method(self):print('这是父类1')class Dad2:def method(self):print('这是父类2')class Son(Dad2, Dad1): # 调用父类中的同名方法时,按照继承顺序进行调用pass
son = Son()
son.method()
七、魔术方法(魔法方法): __方法名__
写法 |
含义 |
举例 |
__init__ |
||
__name__ |
返回类的名称 |
print(Class1.__name__) |
__base__ |
返回父类的名称 |
print(Class1.__base__) |
__bases__ |
返回所有父类的名称:元组形式 |
print(Class1.__bases__) |
__doc__ |
返回类的注释 |
print(Class1.__doc__) |
__dict__ |
返回实例的属性 |
print(cls1.__dict__) 返回字典 |
八、多态
举例:
class Hen:def say(self):print('咯咯咯')class Duck:def say(self):print('嘎嘎嘎')
hen = Hen()
duck = Duck()
duck.say()def animal_say(animal):animal.say()animal_say(duck) # 传函数实例
# 即duck.say():前面duck已经实例化过了
九、反射
在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需要调用对象中的某个变量,但是由于种种原因我们无法确定这个方法或变量是否存在,
这时我们需要用一个特殊的方法或机制要访问和操作这个未知的方法或变量,这种机制称为反射
python的反射主要是指三个函数:
hasattr
getattr
setattr
# 反射
# 一、hasattr(对象,属性或方法名)
# 在对象里找有没有属性或方法名,返回值是布尔型
print(hasattr(str,'replace')) # 查找在str类里面有没有叫replace的方法或属性,返回值是布尔型# 二、getattr(对象,属性或方法名)
# 在对象里找有没有属性或方法名,如果能找到,返回找到的属性或方法,如果找不到报错
print(getattr((str, 'replace')))
# 如果找不到,也可以返回指定的值
print(getattr(str,'replace999','这个真没有'))# 三、setattr(对象,属性)
# 在对象里修改属性值,
# 如果找不到输入的属性,新建属性并赋值
class Class1:a = 1def __init__(self):self.b = 2
setattr(Class1,'a',100) # 修改类属性
print(Class1.a)
cls1 = Class1()
setattr(cls1,'b',180) # 修改实例属性
print(cls1.b)
setattr(cls1,'c',180) # 没有属性,则新增
print(cls1.c)
十、构造函数(__init__())与单例模式
# 单例模式,不需要自己写,所有的类都继承自object的类
# 一般来说,一个类可以生成任意个实例,单例模式只生成一个实例
# 构造方法是一种特殊的方法,它是一个与类同名的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的初始化。当类实例化一个对象时会自动调用构造方法。构造方法和其他方法一样也可以重载。
三种方法
# 单例模式
class Single:def __init__(self):passdef __new__(cls, *args, **kwargs): # 构造方法,生成实例对象if not hasattr(cls,'obj'): # 判断类当中有没有实例,如果没有则新建cls.obj = object.__new__(cls) # 新建一个类的实例,obj是实例名字return cls.obj
s1 = Single()
s2 = Single()
print(s1 == s2)class Restaurant:def yuxiangrousi(self):return '鱼香肉丝'def gongbaojiding(self):return '宫保鸡丁'def qingjiaotudousi(self):return '青椒土豆丝'def fanqiechaodan(self):return '番茄炒蛋'def kaishuibaicai(self):return '开水白菜'customer = Restaurant()
while True:menu = input('请点菜:')if hasattr(Restaurant,menu):print('好的,请厨师开始做菜')breakelse:print('没有这道菜')
handle_loguru
from configparser import ConfigParser # 读取ini配置的模块
from loguru import logger # 日志模块
from handle_path import config_path # 读取项目自定义路径
from time import strftime, sleep # 时间模块class MyLog:__instance = None # 单例实现__call_flag = True # 控制init调用,如果调用过就不再调用def __new__(cls, *args, **kwargs):if not cls.__instance:cls.__instance = super().__new__(cls)return cls.__instancedef get_log(self):if self.__call_flag: # 看是否调用过__curdate = strftime('%Y%m%d %hh:%mm:%dd')cfg = ConfigParser()cfg.read(f'{config_path}\loguru.ini') # 读取配置文件logger.remove(handler_id = None) # 关闭console输出logger.add(f'log_{__curdate}.log', # 日志存放位置retention = cfg.get('log','retention'), # 清理rotation = cfg.get('log','rotation'), # 循环 达到指定大小后建立format = cfg.get('log','format'), # 日志输出格式compression = cfg.get('log','compression'), # 日志压缩格式level = cfg.get('log','level'), # 日志级别encoding = 'utf - 8')self.__call_flag = False # 如果调用过就置为Falsereturn loggerif __name__ == '__main__':log1 = MyLog().get_log() # 第一个实例log1.error('李四')sleep(5)log2 = MyLog().get_log() # 第二个实例,因为做了单例模式,所以其实是同一个实例log2.error('张三')
问题
class Class2: # 静态类?不需要实例化就能调用?print('你好')
# cls = Class2()
# 第七次课思考题
# 写一个猜数字游戏,需求如下
# 随机生成一个0-100之间的数字,让用户猜,如果用户猜对了,提示:回答正确,游戏结束
# 如果猜错了给出对应的提示(您输入的值过大,您输入的值过小),最多允许猜7次
from random import randint
answer = randint(0,100)
for i in range(7):input1 = int(input('请输入一个数字:'))if not input1.isdigit():print('您输入的不是数字,请重新输入')else:input1 = int(input1)if input1 == answer:print('回答正确')breakelif input1 > answer:print('数字过大')elif input1 < answer:print('数字过小')# 写一个三角形的类
class Triangle:def __init__(self,a,b,c):self.a = aself.b = bself.c = cdef perimeter(self):if self.a + self.b <= self.c or self.a + self.c <= self.b or self.b + self.c <= self.a:return '无法构成三角形,忽略周长'else:return self.a + self.b + self.cdef area(self):if self.a + self.b <= self.c or self.a + self.c <= self.b or self.b + self.c <= self.a:return '无法构成三角形,忽略周长'else:p = (self.a + self.b + self.c) / 2return(p * (p - self.a) * (p - self.b) *(p - self.c)) ** 0.5tr = Triangle(3,4,5)
print(tr.perimeter())
print(tr.area())
爬取全书网原文
import re # 正则表达式模块
import requests # 爬虫模块
import os
url = 'http://www.quannovel.com/read/620' # 网址
req = requests.get(url) # 获取网页内容,get和post# 获取书名
book_name = re.findall('<h2>(.*?)<i',req.text)[0] # 获取内容为列表,取【0】获得文字# 获取章节名
title_list = re.findall('class = "name">(.*?)</a>',req.text)# 获取网页的数字部分,之后用url+数字+.html拼接为每个章节的正文的网址
url_list = re.findall('<a href = "(.*?).html"',req.text)# 将章节名与网址放入字典中
dict1 = {}
for i in range(len(title_list)):dict1[title_list[i]] = f'{url}{url_list[i]}.html'
# 写入多个文件
# if not os.path.exists(f'D:/{book_name}'):
# os.mkdir(f'D:/{book_name}')
#
count = 1
with open(f'./{book_name}.txt','w+') as file1: # 在当前目录生成文件,把相关内容写入for k,v in dict1.items():if count > 5:breakelse:req = requests.get(v) # 获取正文网页的内容# ==$0 光标放上去才有text = re.findall('class = "page-content ">(.*?)<div class',req.text,re.S)[0]text = text.replace('<p>','').replace('</p>','')# with open(f'D:/{book_name}/{k}.txt','w') as file1:# file1.write(text)file1.write(k)file1.write(text)file1.write('---------------------------------------------\n')print(f'第{count}章爬取完毕')count += 1
第十次思考题
# 第十次课思考题class Restaurant():passclass Yuxiangrousi(Restaurant):def menu(self):print('鱼香肉丝')class Gongbaojiding(Restaurant):def menu(self):print('宫保鸡丁')class Qingjiaotudousi(Restaurant):def menu(self):print('青椒土豆丝')customer1 = Yuxiangrousi()
customer2 = Gongbaojiding()
customer3 = Qingjiaotudousi()def waiter(obj):obj.menu()
waiter(customer1)
# 或
customer1.menu()
customer2.menu()
customer3.menu()
【python基础】4.1 面向对象(待修改)相关推荐
- Python基础day09【面向对象(封装、继承、多态)、重写、私有权限】
视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员] Python基础day09[面向对象(封装.继承.多态).重写.私有权限] Python基础day ...
- python基础四_01_面向对象
python基础四_01_面向对象编程 导读: 本文主要从what?why?how?三个方向理解面向对象编程的思想:仅供自己梳理. 一.什么是面向对象编程? 面向对象编程与面向过程编程是两种常见的编程 ...
- python基础程序设计与面向对象程序设计_python基础——面向对象的程序设计
python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- Python基础day08【面向对象(类、对象、属性)、魔方方法(init、str、del、repr)】
视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员] 目录 0.复习 1.类外部添加和获取对象属性 2.类内部操作属性 3.魔法方法 3.1.__i ...
- Python基础入门_5面向对象基础
Python 基础入门前四篇: Python 基础入门–简介和环境配置 Python基础入门_2基础语法和变量类型 Python基础入门_3条件语句和迭代循环 Python基础入门_4函数 第五篇主要 ...
- Python基础学习(13)—面向对象2(特殊方法,分装及装饰器)
面向对象(2) 1.1 特殊方法(魔术方法) 1 特殊方法例如__init__的都是以__开头__结尾的方法, 特殊方法会在特定的时候自动调用,init会在对象创建以后立即执行并且init会对新创建的 ...
- python基础之数据类型-面向对象
人生苦短,Python當歌! 此篇博客是本人学习python过程中,总结的基础知识点,希望可以帮到有需要的朋友,如有不足或错误之处,希望评论指出,感谢大家!! 第一章 计算机基础 1.1 硬件 计 ...
- Python全栈开发-Python基础教程-07 面向对象初级
面向对象初级 一. 面向对象 面向对象编程(Object-oriented Programming,简称 OOP),是一种封装代码的方法.其实,在前面章节的学习中,我们已经接触了封装,比如说,将乱七八 ...
- Python基础学习,面向对象的基本概念
Python使用类(class)和对象(object),进行面向对象(object-oriented programming,简称OOP)的编程. 面向对象的最主要目的是提高程序的重复使用性.我们这么 ...
- Python基础复习09_面向对象特性
面向对象特性 1. 继承 Outline ·继承概念 ·单继承/多继承 ·子类重写/调用父类的同名属性和方法 ·多层继承 ·super() ·私有属性和私有方法 1.1 继承的概念 继承指的是多个类之 ...
最新文章
- mysql 二进制日志 解析c++_mysql二进制日志文件恢复数据库
- 【Ubuntu】ubuntu webqq桌面版pywebqq
- python打开json文件变为字典_Python json读写方式和字典相互转化
- Python20行代码实现视频字符化
- UI5控件类似Java反射机制的一个小技巧
- java jpa_Java JPA 语法知识
- vuedraggable嵌套块拖拽_Vue 基于 vuedraggable 实现选中、拖拽、排序效果
- JMH性能测试,试试你代码的性能如何
- js选中文字兼容性解决
- JavaScript日期格式化
- 逻辑斯蒂回归模型为什么用sigmoid函数
- 遗传算法python
- 详介 MQTT 服务器的搭建与客户端连接
- vs2013 MFC入门
- python单样本t检验_SPSS单一样本的T检验
- python文本字词分割及词库云
- SEO个人整理全套学习资料
- 必看:C语言高效学习方法(附经典试题详解)
- EF Power Tool 参数错误 HRESULT:0x80070057 (E_INVALIDARG)) 解决办法
- JAVA中String、StringBuffer和StringBuider类