一.面向对象的初始
1.类 : 具有相同属性和技能的一类事物
2.对象 : 具体类的表现, 具体的实实在在的一个实例
class Person:
''' 类体:两部分: 变量部分,方法(函数)部分 '''
mind = '有思想' # 变量,一般叫(静态变量,静态字段)
animal = '高级动物'
faith = '有信仰'
def __init__(self):
print(66)
def work(self): # 方法,函数,动态变量
print("人类都会工作")
def shop(self):
print("人类可以消费....")
self.hight = 175 # 方法中也可以封装属性
# 类名的角度
# 类中的静态变量
# 1. Person.__dict__ 查询类中的所有内容,不能进行增删改查
# print(Person.__dict__)
# print(Person.__dict__['faith']) # 获取类中静态字段具体的值
# Person.__dict__['mind'] = '无脑' # 报错
# print(Person.__dict__['mind'])
# 2. 万能的点 . 对类中的单个的变量进行增删改查
# print(Person.mind) # 查
# print(Person.animal) # 查
# Person.money = '运用货币' 增
# Person.mind = '无脑' # 改
# del Person.mind # 删除
# print(Person.__dict__) # 打印类中所有的内容
# 3. 操作类中的方法 (工作中基本不用类名去操作)
# 3. 除了类方法,静态方法,需要类名调用之外,剩下的方法都要对象调用
# Person.work(11)
# 对象的角度
# ret = Person() # 类名 + () 的这个过程: 实例化的过程( 创建一个对象的过程 )
# Person() 实例化对象,实例,对象
# print(ret)
# 1. 只要类名 + () 产生一个对象,自动执行类中__init__方法.
执行步骤
# 1. 类名+() 产生一个实例 ( 对象,对象空间 )
# 2. 自动执行类中的__init__方法,将对象空间传给__init__的self参数
# 3. 给对象封装相应的属性(变量)
# print(ret.__dict__) # 查询对象中的所有内容 结果是 字典{}
# 执行过程
# 1.创建了一个对象空间,实例空间
# 2. 自动执行__init__方法,并将我的对象空间传给self
# 3. 执行具体的__init__代码,给对象空间封装属性
# 操作对象中静态变量
# 1. __dict__ 查询对象中的所有内容
# 2. 万能的点 .
print(ret.name) # 查
ret.high = 189 # 增
del ret.faith # 删除
ret.age = 99 # 改
# print(ret.__dict__) #
对象操作类中的静态变量 : 只能查询
# print(ret.mind)
对象调用类中的方法 ( 工作中 通过对象执行类中的方法,而不是通过类名)
# ret.shop()
# print(ret)
例子
class Person:
mind = '有思想的'
animal = '高级动物'
faith = '有信仰的'
def __init__(self, name, age, hobby):
self.name = name
self.age = age
self.faith = hobby
def work(self):
print('%s是会工作的' % self.name)
def shop(self):
print('%s会消费......' % self.name)
def get(self):
print('%s今年%s岁了' % (self.name, self.age))
ret = Person('alex', 19, '喝酒')
# ret.work()
# ret.shop()
# ret.get()
二.面向对象-名称空间
1.创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性: 静态属性和动态属性
静态属性就是直接在类中定义的变量
动态属性就是定义在类中的方法
其中类的数据属性是共享给所有对象的
>>>id(egg.role)
4341594072 # 内存地址
>>>id(Person.role)
4341594072
而类动态属性是绑定到所有对象的
>>>egg.attack
<bound method Person.attack of <__main__.Person object at 0x101285860>>
>>>Person.attack
<function Person.attack at 0x10127abf8>
创建一个对象/实例就会创建一个对象/实例的名称空间, 存放对象/实例的名字. 称为对象/实例的属性
在obj.name 会先从obj 自己的名称空间找 name .找不到则去类中找,再找不到就去父类中扎找…最好找不到就会抛出异常
- 查询顺序:
- 对象.属性: 先从对象空间找.如果找不到.再从类空间找.再找不到.再从父类中找..
- 类名.属性: 先从本类空间中找.如果找不到,在从父类中找..
- 对象与对象之间是相互独立的
计算一个类 实例化多少对象.
class Count:
count = 0
def __init__(self):
Count.count = self.count + 1
obj1 = Count()
obj2 = Count()
print(Count.count)
count = 0
def func():
print(count)
func()
class Count:
count = 0
def __init__(self):
pass
通过类名可以更改我的类中的静态变量值
Count.count = 6
print(Count.__dict__)
但是通过对象 不能改变只能引用类中的静态变量
obj1 = Count()
print(obj1.count)
obj1.count = 6
三.组合: 给一个类的对象封装一个属性,这个属性是另一个类的对象
class GameRole:
def __init__(self, name, ad, hp):
self.name = name
self.ad = ad
self.hp = hp
def attack(self,p):
p.hp = p.hp - self.ad
print('%s 攻击 %s,%s 掉了%s血,还剩%s血' %(self.name,p.name,p.name,self.ad,p.hp))
def armament_weapon(self,wea):
self.wea = wea
class Weapon:
def __init__(self,name,ad):
self.name = name
self.ad = ad
def fight(self,p1,p2):
p2.hp = p2.hp - self.ad
print('%s 用%s打了%s,%s 掉了%s血,还剩%s血'\
% (p1.name,self.name,p2.name,p2.name,self.ad,p2.hp))
p1 = GameRole('大阳哥',20,500)
p2 = GameRole('印度阿宁',50,200)
axe = Weapon('三板斧',60)
broadsword = Weapon('屠龙宝刀',100)
# print(axe)
p1.armament_weapon(axe) # 给大阳哥 装备了三板斧这个对象.
# print(p1.wea)
# print(p1.wea.name)
# print(p1.wea.ad)
p1.wea.fight(p1,p2)
四.面向对象第一大特性—继承
子类以及子类实例化的对象, 可以访问父类的任何方法和变量
类名可以访问父类的所有内容 (print(Animal.breath))
子类实例化的对象也可以访问父类所有内容 print(p1.breath) print(p1) p1.eat()
只执行父类的方法: 子类中不要定义与父类同名的方法
只执行子类的方法,在子类中创建
既要执行子类的方法,又要执行父类中的方法?
两种办法:
Animal.__init__(self, name, sex, age) super().__init__(name,sex,age)
class Animal:
breath = '呼吸' # 静态字段
def __init__(self,name,sex,age)
self.name = name
self.sex = sex
self.age = age
def eat(self):
print('吃东西...')
class Cat(Animal): # 括号里面的: 父类,基类,超类 括号外面的: 子类,派生类
pass
class Dog(Animal):
pass
p1 = Cat('alex','women',100) # 实例化子类对象
print(p1.__dict__)
class Animal:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def eat(self, a):
print('%s吃%s' % (self.name, a))
def drink(self):
print('%s喝东西' % self.name)
class Cat(Animal):
def __init__(self, name, sex, age, wing):
Animal.__init__(self, name, sex, age)
# super(Cat, self).__init__(name, sex, age)
self.wing = wing
def miaow(self):
print('喵喵叫')
def eat(self, a):
super(Cat, self).eat(a)
print(666)
c1 = Cat('tom', '公', 3, '好看')
# print(c1.__dict__)
c1.eat('金蝉')
五.继承的进阶
1.继承: 单继承, 多继承
2.类的角度: A–>经典类,B–>新式类
1.新式类: 凡是继承object类都是新式类( 在Python3版本中,所有类都是新式类,因为Python3版本中的类都默认继承object)
2.经典类: 不继承object类的都是经典类(Python2中既有新式类又有经典类,中所有的类都不继承object,所以所有的类默认是经典类)
3.单继承: 新式类,经典类查询顺序一样
class A:
def func(self):
print('A')
class B(A):
def func(self):
print('B')
class C(B):
def func(self):
print('C')
c1 = C()
c1.func()
b1 = B()
b1.func()
4.多继承:
1.新式类: 遵循广度优先
2.多继承的新式类 广度优先: 一条路都到倒数第二级,进行判断,如果其他路能走到终点,则返回走另外一条路,如果不能,则走到终点
class A:
def func(self):
print('IN A')
class B(A):
pass
# def func(self):
# print('IN B')
class C(A):
pass
# def func(self):
# print('IN C')
class D(B):
pass
# def func(self):
# print('IN D')
class E(C):
pass
# def func(self):
# print('IN E')
class F(D, E):
pass
# def func(self):
# print('IN F')
f1 = F()
f1.func()
print(F.mro()) # 查询类的继承顺序
3.经典类: 遵循深度优先: 一条路走到底
六.面向对象之封装和多态
一. 接口类,抽象类: 制定一个规范(Python中没有接口的概念)
# 制定规则,抽象类,接口类
from abc import ABCMeta, abstractmethod
class Payment(metaclass=ABCMeta): # 抽象类(接口类)
@abstractmethod # 装饰器
def pay(self): pass # 制定规范
class Alipay(Payment):
def __init__(self, money):
self.money = money
def pay(self):
print('使用了支付宝支付了%s' % self.money)
class Jdpay(Payment):
def __init__(self, money):
self.money = money
def pay(self):
print('使用了京东支付了%s' % self.money)
def pay(obj):
obj.pay()
a1 = Alipay(1000)
p1 = Jdpay(1222)
pay(a1) # 归一化设计
pay(p1)
二. 多态
1.多态: Python中没有多态,只有鸭子类型(Python是弱类型语言,不管是什么类型,传入函数,封装到对象中都可以)
以下这些类互称为鸭子
class Str:
def index(self):
pass
class List:
def index(self):
pass
class Tuple:
def index(self):
pass
三.封装
1.广义的封装: 实例化一个对象, 给对象空间封装一些属性
2.狭义的封装: 私有制
3.私有成员: 私有静态字段,私有方法,私有对象属性
A.私有静态字段
class A:
__money = 1100 # 前面加 __就是私有静态字段
class B(A):
name = 'alex'
__age = 99 # 前面加 __就是私有静态字段
def func(self):
print(self.__age) # 对于私有静态字段,类的内部是可以访问的
print(B.__age)
# print(self.__money)
print('func...')
a1 = B()
print(a1.name)
print(a1.name)
print(a1.__age) # 实例化对象不能访问私有静态字段
print(B.__age) # 类名也不能访问私有静态字段
#对与私有静态字段,类的外部是不能访问的
a1.func()
#对于私有静态字段,只能在类的内部访问,类的外部,派生类均不能访问
#其实是可以访问的是Python中的一个bug(工作中千万不要用)
print(B._B__age)
print(B.__dict__)
B.私有方法
#私有方法
class B:
__money = 1000 #前面加 __就是私有静态字段
def __f1(self): #前面加 __就是私有方法
print('B')
class A(B):
name = 'alex'
def __func(self):
print('func...')
def func1(self):
self.__func() # 类的内部可以访问
self.__f1()
a1 = A()
# a1.__func() # 类的外部不能访问
a1.func1() # 类的内部可以访问
a1.func1() # 类的派生类不可以访问
七.面向对象之反射(重点)
1.反射: 用字符串数据类型的变量名来访问这个变量的值
2.反射的方法: getattr hasattr setattr delattr
- 命名空间.xxx = getattr(命名空间, ‘xxx’)
1.反射类 –> 静态属性 类方法 静态方法
s Student:
role = 'student'
@classmethod
def check_course(cls):
print('查看课程')
@staticmethod
def login():
print('登录')
# 反射查看属性
print(Student.role)
print(hasattr(Student, 'role')) # 结果是True
print(getattr(Student, 'role'))
# 反射调用方法
getattr(Student, 'check_course')() # 类方法
getattr(Student, 'login')() # 静态方法
num = input('>>>')
if hasattr(Student, num):
getattr(Student, num)()
2.对象的反射 –> 方法 对象属性
class A:
def __init__(self, name):
self.name = name
def func(self):
print('in func')
a = A('alex')
print(a.name)
# 反射对象属性
print(hasattr(a, 'name'))
print(getattr(a, 'name'))
# 反射对象方法
getattr(a, 'func')()
3.模块的反射
mport os # 别人写好的python代码的结合
# os.rename('__init__.py', 'init')
# getattr(os, 'rename')('nit', '__init__.py') # == os.name
rename = os.rename
rename1 = getattr(os, 'rename')
# rename1('__init__.py', 'init') # os.rename(__init__.py', 'init')
rename('init', '__init__.py') # os.rename('init', '__init__.py')
1.反射自己模块中的内容
# 反射自己模块中的内容, 找到自己当前文件所在的命名空间
def wahaha():
print('哈哈哈')
def qqing():
print("123")
import sys
# print(sys.modules)
# import 相当于导入了一个模块
# 模块哪个导入了, 哪个没导入, 在自己的python解释器里面应该记录下来
# import sys 是一个模块, 这个模块里的所有的方法都是和python解释器相关的
# sys.modules 这个方法, 表示所有在当前这个python程序中导入的模块
# '__main__':<module '__main__' from 'D:/sylar/python_workspace/day20/4.反射.py'>
print(sys.modules['__main__'])
my_file = sys.modules['__main__']
my_file.wahaha()
my_file.qqing()
getattr(my_file, 'wahaha')()
- 反射
- hasattr getattr
- 类名.名字
- getattr(类名, ‘名字’)
- 对象名.名字
- getattr(对象, ‘名字’)
- 模块名
- getattr(模块, ‘名字’)
- 自己文件.名字
- import sys
- getattr(sys.modules[‘_ main _ _’], ‘名字’)
选课系统的代码
class Manager:
OPERATE_DIC = [
('创建学生账号', 'create_student'),
('创建课程', 'create_course'),
('查看学生信息', 'check_student_info')
]
def __init__(self, name):
self.name = name
def create_student(self):
print('创建学生账号')
def create_course(self):
print('创建课程')
def check_student_info(self):
print('查看学生信息')
class Student:
OPERATE_DIC = [
('查看课程', 'check_course'),
('选择课程', 'choose_course'),
('查看已经选择的课程', 'choosed_course')
]
def __init__(self, name):
self.name = name
def check_course(self):
print('查看课程')
def choose_course(self):
print('选择课程')
def choosed_course(self):
print('查看已经选择的课程')
def login():
username = input('user: ')
password = input('pwd: ')
with open('userinfo') as f1:
for line in f1:
user, pwd, ident = line.strip().split('|')
if user == username and pwd == password:
print('登录成功...')
return username, ident
import sys
def main():
usr, id = login()
file = sys.modules['__main__']
cls = getattr(file, id)
obj = cls(usr)
operate_dic = cls.OPERATE_DIC
while True:
for num, i in enumerate(operate_dic, 1):
print(num, i[0])
choice = int(input('请选择:'))
print(len(operate_dic))
if choice < len(operate_dic):
choice_item = operate_dic[choice - 1]
getattr(obj, choice_item[1])()
else:
print('输入有误,重新输入:')
main()
八.面向对象的进阶
析构方法
- 释放一个空间之前执行
- 某对象借用了操作系统的资源, 还要通过析构方法归还回去: 比如–> 文件资源, 网络资源
1.垃圾回收机制
class A:
def __del__(self):
# 析构方法 del A的对象, 会自动触发这个方法
print('执行我来了')
a = A()
del a # 对象的删除, del
print(a)
class File:
def __init__(self, file_path):
self.f = open(file_path)
self.name = 'alex'
def read(self):
self.f.read(1024)
def __del__(self): # 是去归还/释放一些在创建对象的时候借用的一些资源
# del 对象的时候 是程序员触发
# python 解释器的垃圾回收机制, 回收这个对象所占的内存的时候, python自动触发的
self.close()
f = File('文件名')
f.read()
# 不管是主动还是被动, 这个f对象总会被清理掉, 被清理掉就会触发__del__方法, 触发这个方法就会归还操作系统的文件资源
# python解释器在内部就能搞定的事
# 申请一块空间, 是操作系统分配给你的
# 在这一块空间中, 是由python解释器来管理的
# example :
f = open('文件') # python--> 操作系统 --> 硬盘里的文件 --> 文件操作符
f.close() # f就是文件操作符
# def f
- item系列 是和对象使用[] 访问值有联系
- 在内置模块中,有一些特殊的方法, 要求对象必须实现_ _ getitem _ _/ _ _ setitem _ _ 才能使用
class A:
def __getitem__(self, item):
return getattr(self, item)
def __setitem__(self, key, value):
setattr(self, key, value*2)
def __delitem__(self, key):
delattr(self, key)
a = A()
a.k1 = 'k1'
print(a.k1)
a['k1'] = 'v1' # 默认调用 __setitem 方法
print(a['k1']) # 默认调用 __getitem
del a['k1'] # 默认调用__delitem
print(a['k1'])
class B:
def __init__(self, lst):
self.lst = lst
def __getitem__(self, item):
return self.lst[item]
def __setitem__(self, key, value):
self.lst[key] = value
def __delitem__(self, key):
self.lst.pop(key)
b = B(['111', '22', 'dd', 'rr'])
print(b.lst[0])
print(b[0])
b[2] = 'alex'
print(b[2])
print(b.lst)
del b[2]
print(b.lst)
hash方法
- 底层数据结构是基于hash值寻址的优化
- hash 是一个算法
- 能够把某一个要存在内里的值通过一系列的计算
- ‘adf’ – > 851621 类似于这样
- 对同一个值在多次执行python代码的时候值是不同的
- 但是同一个值, 在同一次执行python代码的时候hash值 永远不变
- 字典的寻址 – hash 算法 通过key的hash值去找value,所以速度比较快
- d = {‘key’ : ‘value’}
- hash 是一个内置函数
- hash(obj) # obj内部必须是实现了_ _ hash _ _ 方法
- set集合 hash不是万能的, 两个不一样的字符串, hash值可能相等–> 如果hash值相等,首先它就会判断值是否相等 == ,相同则去重, 不同则存在内存中
- set集合的去重原理–> 通过hash算法去重的, hash的结果找到一块内存地址,只要这个地址上没有数据,就说明之前没有重复的数据, 如果这块地址上有一个数据存在了,才判断这个值和我要存的值是否一样, 如果一样,覆盖去重, 如果不一样,二次寻址给这个值换个地方存
eq方法
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if self.name == other.name and self.age == other.age:
return True
a = A('LAEX', 10)
a1 = A('LAEX', 10)
a2 = A('LAEX', 10)
a3 = A('LAEX', 10)
print(a, a1,)
print(a == a1 == a2) # 返回True 完全和__eq__方法一样
- 一道经典面试题
# 一个类
# 对象的属性: 姓名 性别 年龄 部门
# 员工管理系统
# 内部转岗 python--go开发
# alex male 44 python
# alex male 55 go
# 1000个员工
# 如果几个员工对象的姓名和性别相同,这是一个人
# 请对这1000个员工做去重
class Employee:
def __init__(self, name, sex, age, partment):
self.name = name
self.sex = sex
self.age = age
self.partment = partment
def __hash__(self): # 第二步 ,重写父类boject的__hash__方法, 返回hash的值,还是不行
return hash('%s%s' % (self.name, self.sex))
def __eq__(self, other): # 第三步, 重写__eq__方法 ,判断值是否相等,返回True
if self.name == other.name and self.sex == other.sex:
return True
employ_lst = []
for i in range(100):
employ_lst.append(Employee('alex', 'male', i, 'python'))
for i in range(100):
employ_lst.append(Employee('wusir', 'male', i, 'go'))
employ_set = set(employ_lst) # 第一步,先用set集合去重,结果不行
# print(employ_lst)
for person in employ_set:
print(person.__dict__)