面向对象

第四章 面向对象

1.面向对象初识

1.1 面向对象过程vs函数式编程vs面向对象编程
s1 = 'fkjgkrsge'
count = 1
for i in s1:
	count += 1 
l1 = [1,2,3,4,5]

def my_len(a):
	count = 1
		for i in a:
	count += 1 
提高了代码的可读性,减少了代码的重复性....
上面统称为面向过程式编程.
面向过程式编程:
好处:出色的完成你之前布置的所有的需求.
坏处:但凡更改或者增加一条需求,可能整个项目都随之改变.
1.2面向对象的结构
1. 类是相似功能的集合体.
2. 类 你要站在上帝的角度去考虑问题.
类: 具有相似功能和特性的一类事物.
对象:类的具体体现.
一定要有宏观的概念,区分类与对象.
类的第二个优点: 你要站在 的角度去考虑,类一个公共模板,对象是从这个公共的模板产出的.
结构上分析:
Human 类名要具有描述性,类名首字母大写,类名不宜用_
1.3从类名的角度使用类
class Student:
    """
    此类是构建学生类
    """
    daily = '学习'
    examination = '考试'
    def work(self):
        print('每天要上课')

    def homework(self):
        print('家庭作业')

1562294549262

类名的角度调用类中的属性,

1.查看类中的所有的内容.类名.__dict__只用于获取类中的全部.

print(Student.__dict__)
print(Student.__dict__['daily'])

2.万能的 . 点

class Student:
	daily = '学习'
	examination = '考试'
	def work(self):
		print('每天上课')
	def homework(self):
		print('家庭作业')
print(Student.daily)#查
Student.cloth = '校服'#增
Student.examination = '不考试'#改
del Student.daily #删
print(Student.__dict__)

一般类中的属性都是通过类名. 的方式 去操控的.

类名的角度调用类中的方法.(一般类中的方法(除去类方法,静态方法外)不通过类名调用)

Student.work(5565) # 工作中不用类名调用

1562299522885

1.4从对象的角度分析类
class Student:
    """
    此类是构建学生类
    """

    daily = '学习'
    examination = '考试'

    def __init__(self,n,a,h):
        self.name = n
        self.age = a
        self.hobby = h

    def work(self,c):
        self.color = c
        print(f'{self.name}每天要上课')

    def homework(self):
        # 利用self 对象空间,为所欲为
        print('家庭作业')

obj = Student()  # 类名() 过程就叫做实例化过程,实例化一个对象
print(obj)  # 对象,实例
obj1 = Student()
print(obj1)
obj = Student()
print(obj)

对象可以操作对象空间的属性 万能的点

obj = Student('xiaohong',12,'运动')
obj.age = '29'  # 增
del obj.name  # 删
obj.sex = '女'# 改
print(obj.age)  # 查
daming = Student('大明',21,'工作')
Tom = Student('汤姆',12,'学习')
对象查看全部属性
print(obj.__dict__)
{'age': '29', 'hobby': '运动', 'sex': '女'}

对象查看类中的属性

print(daming.daily)
daming.daily = '活动'不会修改,只会在对象空间的属性中增加这样一个属性

对象调用类中的方法

liye = Student('小黑',21,'音乐')
liye.work('红色')
print(liye.__dict__)
1.5实例化对象
obj = Student()  # 类名() 过程就叫做实例化过程,实例化一个对象
print(obj)  # 对象,实例
实例化一个对象时发生了三件事:
1. 在内存中创建一个对象空间.
2. 自动执行__init__方法,并且将对象空间传给self参数.
3. 执行__init__方法里面的代码,给对象空间封装其属性.
1.6self

self 就是类中方法的第一个位置参数, 如果通过对象执行此方法,解释器就自动的将此对象空间当做实参传给self.约定俗称: 类中的方法第一个参数一般都设置成self.

1.7从空间角度研究类
class A:

    address = '美丽富饶的沙河'

    def __init__(self, name):
        self.name = name

    def func(self):
        if self.name == 'aa':
            self.skins = '吉利服'

    def func1(self):
        print(self.__dict__)
        A.aaa = '易水寒'
obj = A('aa')
类外面可以给对象封装属性
response = input('今天天气热不热')
if  response == '热':
    obj.weapon = 'abc'
print(obj.__dict__)
>>>{'name': 'aa', 'weapon': 'abc'}
类内部封装属性
obj.func()
print(obj.__dict__)
>>>{'name': 'aa', 'skins': '吉利服'}
obj = A('db')
A.func1(111)
A.func1(obj)把对象传到类的方法中
print(A.__dict__)#类空间增加了一个静态属性
class Person:

    mind = '有思想'
    language = '会使用语言'

    def __init__(self, name, age):

        self.name = name
        self.age = age

    def work(self):
        print('人类一般都需要工作')

p1 = Person('dsb', 21)
del p1.mind  # 报错,不能通过对象删除类的静态属性
p1.mind = '无脑'# 对象空间增加了一个属性
print(p1.mind)#无脑
print(Person.mind)#有思想
对象如果查询一个属性: 对象空间  ----> 类空间 ----> 父类空间  --->
类查询一个属性: 类空间  ----> 父类空间  ---->
单向不可逆
对象与对象之间原则上互相独立(除去组合这种特殊的关系之外).
1562553549390
1.8类与类之间的关系

1.依赖关系(主从关系)

大象进冰箱
方法一:将一个对象传给另一个类的的方法中:
class Elephant:
	def __init__(self,name):
		self.name = name
	def open(self,ref1):
		print(f'{self.name}大象默念三声:芝麻开门')
		ref1.open_door()
	def close(self,ref2):
		print(f'{self.name}大象默念三声:芝麻关门')
		ref2.close_door()
class Refrigerator:
	def __init__(self,name):
		self.name = name
	def open_door(self):
		print(f'{self.name}冰箱门被打开了')
	def close_door(self):
		print(f'{self.name}冰箱门被关上了')
ele = Elephant('琪琪')
re = Refrigerator('美菱')
ele.open(re)
ele.close(re)
注:当传的是对象的时候,无需再ref1.open_door()括号中添加东西,调用这个方法,会自动将对象传给self.
方法二:将一个类名传到另一个类的方法中:
class Elephant:
	def __init__(self,name):
		self.name = name
	def open(self,ref1):
		print(f'{self.name}大象默念三声:芝麻开门')
		ref1.open_door(re)
	def close(self,ref2):
		print(f'{self.name}大象默念三声:芝麻关门')
		ref2.close_door(re)
class Refrigerator:
	def __init__(self,name):
		self.name = name
	def open_door(self):
		print(f'{self.name}冰箱门被打开了')
	def close_door(self):
		print(f'{self.name}冰箱门被关上了')
ele = Elephant('琪琪')
re = Refrigerator('美菱')
ele.open(Refrigerator)
ele.close(Refrigerator)
'''
琪琪大象默念三声:芝麻开门
美菱冰箱门被打开了
琪琪大象默念三声:芝麻关门
美菱冰箱门被关上了
'''
注:当传的是类名的时候,需再ref1.open_door()括号中添加东西,调用这个方法,需将对象re传给self.
依赖关系: 将一个类的类名或者对象传给另一个类的方法中.
 实现两个:
大象执行open方法:
显示: '哪个大象  大象默念三声: 芝麻开门'
显示: '哪个冰箱门 冰箱门被打开了....'
关门的流程也需要完成.

2.组合:(聚合,组合,关联)

class Boy:

    def __init__(self, name):
        self.name = name

    def meet(self, girl_friend=None):

        self.girl_friend = girl_friend  # wu对象空间 : girl_friend : object对象

    def have_diner(self):  # self = wu这个对象空间

        if self.girl_friend:
            print(f'{self.name}请年龄为:{self.girl_friend.age},姓名为{self.girl_friend.name}一起吃六块钱的麻辣烫')
            self.girl_friend.shopping(self)  # (self = wu对象空间)
        else:
            print('单身狗,吃什么吃')
class Girl:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def shopping(self,boy_friend):
        print(f'{boy_friend.name},{self.name}一起去购物!')

wu = Boy('吴超')
flower = Girl('如花', 28)
wu.meet(flower)
wu.have_dinner()
>>>
吴超请年龄为:28,姓名为如花一起吃六块钱的麻辣烫
吴超,如花一起去购物!
组合: 将一个类的对象封装成另一个类的对象的属性.

1562592912562

上面例题的难点:
一个类的方法只能有此类的对象去调用.
一个类的方法的第一个self只接受此类的对象.

3.模拟英雄联盟写一个游戏人物的类(升级题).

要求:
1. 创建一个 Game_role的类.
2. 构造方法中给对象封装name,ad(攻击力),hp(血量).三个属性.
3. 创建一个attack方法,此方法是实例化两个对象,互相攻击的功能:
       例: 实例化一个对象 盖伦,ad为10, hp为100
       实例化另个一个对象 剑豪 ad为20, hp为80
       盖伦通过attack方法攻击剑豪,此方法要完成 '谁攻击谁,谁掉了多少血,  还剩多少血'的提示功能.

方法一:

class GameRole:
	def __init__(self,n,ad,hp):
		self.name = n
		self.ad = ad
		self.hp = hp
	def attack(self,p1):
		p1.hp = p1.hp - self.ad
		print(f'{self.name}攻击了{p1.name},{p1.name}掉了{self.ad}血,还剩{p1.hp}血')
gailun = GameRole('草丛伦', 10, 100)
jianhao = GameRole('风男', 20, 80)
gailun.attack(jianhao)
gailun.attack(jianhao)
返回结果:
草丛伦攻击了风男,风男掉了10血,还剩70血
草丛伦攻击了风男,风男掉了10血,还剩60血

方法二:

class GameRole:
	def __init__(self,n,ad,hp):
		self.name = n
		self.ad = ad
		self.hp = hp
	def equit_weapon(self,wea):
		self.weapon = wea
class Weapon:
	def __init__(self,name,ad):
		self.name = name
		self.ad = ad
	def weapon_attack(self,p1,p2):
		p2.hp = p2.hp - self.ad
		if p2.hp >= 0:
			print(f'{p1.name}利用{self.name}攻击了{p2.name},{p2.name}还剩{p2.hp}血')
		else:
			print('%s已死'%p2.name)
gailun = GameRole('盖伦',10,100)
zhaoxin = GameRole('赵信',20,90)
great_sword = Weapon('大宝剑',30)
spear = Weapon('红缨枪',50)
gailun.equit_weapon(spear)#依赖关系
gailun.weapon.weapon_attack(gailun,zhaoxin)# gailun.weapon == spear
gailun.weapon.weapon_attack(gailun,zhaoxin)
返回结果:
盖伦利用红缨枪攻击了赵信,赵信还剩40血
赵信已死

2.三大特性之继承(单,多继承)

  1. 什么是继承?

    • 专业角度: B 继承 A类, B就叫做A的子类,派生类, A叫做B的父类,基类,超类. B类以及B类的对象使用A类的所有的属性以及方法.
    • 字面意思: 继承就是继承父母所有的资产.
    • 单继承,多继承.
    • 如果多各类中有相同的方法,为了避免重复编写,可以将其放在父类中(基类)中
  2. 继承的优点:

    1. 节省代码.
    2. 增强的耦合性.
    3. 代码规范化.

    继承分为单继承与多继承.
    Person Dog Cat : 子类,派生类
    Animal: 父类, 基类, 超类
    单继承: 使用.
    多继承:有区别.

2.1从类名执行父类的属性。
class Animal(object):

    live = '有生命的'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def eat(self):
        print(f'self----> {self}')
        print('动物都需要进食')


class Person(Animal):
    pass
print(Person.__dict__)
print(Person.live)
Person.eat(55)
返回结果:
{'__module__': '__main__', '__doc__': None}
有生命的
self----> 55
动物都需要进食

1562673399366

2.2从对象执行父类的一切。

实例化对象一定一定会执行三件事. 一定会执行__init__

class Animal(object):

    live = '有生命的'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def eat(self):
        print(f'self----> {self}')
        print('动物都需要进食')


class Person(Animal):
    pass
p1 = Person('dsb', 21, 'laddy_boy')
print(p1.__dict__)
print(p1.live)
p1.eat()
print(f'p1--->{p1}')
返回结果:
{'name': 'dsb', 'age': 21, 'sex': 'laddy_boy'}
有生命的
self----> <__main__.Person object at 0x0000006797AB8A20>
动物都需要进食
p1--->    <__main__.Person object at 0x0000006797AB8A20>

注意: 子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改).

class Animal(object):

    live = '有生命的'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def eat(self):
        print(f'self----> {self}')
        print('动物都需要进食')


class Person(Animal):

    def eat(self):
        print('人类需要进食')



p1 = Person('dsb', 21, 'laddy_boy')
# 子类将父类的方法覆盖了,(重写父类的方法)
p1.eat = '李业'
print(p1.__dict__)
p1.eat()  # 对象查找顺序先从对象空间找名字, 子类找名字, 父类找名字.会直接报错

2.3同时执行父类方法和执行子类方法
class Animal:
    def __init__(self,n,a,s):
        self.name = n
        self.age = a
        self.sex = s
    def eat(self):
        print(f'self------->{self}')
        print('动物需要进食')
class Person(Animal):
    def __init__(self,name,age,sex,hobby):
        # 方法一:
        Animal.__init__(self,name,age,sex)
        # 方法二:
        # super(Person, self).__init__(name,age,sex)
        super().__init__(name,age,sex) # 和上面的一样,默认不写,已经传了Person,self
        self.hobby = hobby

    def eat(self):
        print('人类需要进食')
        super().eat()
p1 = Person('小红',12,'女','唱歌')
print(p1.__dict__)
print(f'p1--------->{p1}')
p1.eat()
返回结果:
{'name': '小红', 'age': 12, 'sex': '女', 'hobby': '唱歌'}
p1---------><__main__.Person object at 0x0000007F50BB1B38>
人类需要进食
self-------><__main__.Person object at 0x0000007F50BB1B38>
动物需要进食

习题

class Base:

    def __init__(self, num):
        self.num = num

    def func1(self):
        print(self.num)

class Foo(Base):
    pass

obj = Foo(123)
obj.func1()
返回结果:123
class Base:
    def __init__(self, num):
        self.num = num

    def func1(self):
        print(self.num)

class Foo(Base):

    def func1(self):
        print("Foo. func1", self.num)

obj = Foo(123)
obj.func1()
返回结果:Foo. func1 123

class Base:
    def __init__(self, num):  # 2
        self.num = num

    def func1(self):  # 4
        print(self.num)  # 123
        self.func2()  # self ---> obj  # 对象查询顺序:

    def func2(self):
        print("Base.func2")

class Foo(Base):
    def func2(self):
        print("Foo.func2")

obj = Foo(123)  # 1
obj.func1() # 3
返回结果:
123
Foo.func2
class Base:
    def __init__(self, num):
        self.num = num
    def func1(self):

        print(self.num)
        self.func2()

    def func2(self):
        print(111, self.num)

class Foo(Base):

    def func2(self):
        print(222, self.num)

lst = [Base(1), Base(2), Foo(3)]

for obj in lst:
    obj.func2()
返回结果:
111,1
222,2
333,3
class Base:

    def __init__(self, num):
        self.num = num

    def func1(self):
        print(self.num)
        self.func2()

    def func2(self):
        print(111, self.num)


class Foo(Base):

    def func2(self):
        print(222, self.num)


lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
    obj.func1()
返回结果:
1
111 1
2
111 2
3
222 3

2.4多继承

面向对象:

python2.2之前:都是经典类。

python2.2直至python2.7之间存在两种类型: 经典类,新式类.

经典类: 基类不继承object类,查询规则:深度优先的原则.

新式类: 基类继承object类,python3x 只有新式类.查询规则: mro算法.

经典类:Foo-> H -> G -> F -> E -> D -> B -> A -> C.深度优先
img
python2x
class A:  # 经典类
    pass

class B(object):  # 新式类
    pass


python3x:(默认继承object)
class C: # 新式类
    pass

class O:
    pass

class D(O):
    pass

class E(O):
    pass

class F(O):
    pass

class B(D,E):
    pass

class C(E,F):
    pass

class A(B,C):
    pass

# 工作中用mro()方法研究新式类的继承顺序
print(A.mro())
返回结果:
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class '__main__.F'>, <class '__main__.O'>, <class 'object'>]
mro算法  面试中有可能会遇到

2.5c3算法
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
mro(Foo(H,G)) = [Foo] + merge(mro(H), mro(G),[H,G])

表头:
  列表的第一个元素

表尾:
  列表中表头以外的元素集合(可以为空)
表头,表尾
[A,B,C] : 表头: A 表尾: [B,C]
[A] : 表头: A 表尾: []
mro(A) = mro(A(B,C))
       = [A] + merge(mro(B), mro(C), [B,C])

mro(B) = mro(B(D,E))
       = [B] + merge(mro(D), mro(E), [D,E])
       = [B] + merge([D,O], [E,O], [D,E])
       = [B,D] + merge([O], [E,O], [E])
       = [B,D,E,O]
       
mro(C) = mro(C(E,F))
       = [C] + merge(mro(E), mro(F),[E,F])
       = [C] + merge([E,O],[F,O],[E,F])
       = [C,E] + merge([O],[F,O],[F])
       = [C,E,F,O]

mro(A) = mro(A(B,C))
       = [A] + merge([B,D,E,O], [C,E,F,O], [B,C])
       = [A,B] + merge([D,E,O], [C,E,F,O], [C])
       = [A,B,D] + merge([E,O], [C,E,F,O], [C])
       = [A,B,D,C] + merge([E,O], [E,F,O])
       = [A,B,D,C,E] + merge([O], [F,O])
       = [A,B,D,C,E,F,O]


3.三大特性封装多态(鸭子类型)

3.1多态,封装

​ 1.方法封装到类中.

​ 2.数据封装到对象中.

​ 封装:将一些东西内容封装到一个地方,你还可以取出来.

​ 类设置静态属性,设置一些方法,

​ 对象.对象可以在其对象空间中封装一些属性.

​ 多态: 一个事物产生多种形态. 水: 气态液态固态.

​ python中 默认支持多态.

​ python中 定义变量不用规定变量的类型

3.2鸭子类型
class A:

    def login(self):
        pass

    def register(self):
        pass


class B:

    def login(self):
        pass

    def register(self):
        pass

A,B两个类,没有任何关系,独立两个,但是里面的功能相似,所以python一般会将类似于A,B两个类

里面的相似功能让其命名相同

1.A,B虽然无关系,但是很默契的制定了一个规范,让你使用起来更方便.

3.3super()
1.
class A:
    def f1(self):
        print('in A f1')

    def f2(self):
        print('in A f2')


class Foo(A):
    def f1(self):
        # super().f2()
        super(Foo, self).f2()
        print('in A Foo')


obj = Foo()
obj.f1()
'''
in A f2
in A Foo
'''
2.
class A:
    def f1(self):
        print('in A')

class Foo(A):
    def f1(self):
        super(Foo,self).f1()
        print('in Foo')  # 2

class Bar(A):
    def f1(self):
        print('in Bar')  # 1

class Info(Foo,Bar):

    def f1(self):
        super(Info,self).f1()
        print('in Info f1')  # 3

obj = Info()
print(Info.mro())  # [Info, Foo, Bar, A]
obj.f1()
'''
[<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
in Bar
in Foo
in Info f1
'''
super() 严格意义并不是执行父类的方法.
单继承: super() 肯定是执行父类的方法.
多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位.

class A:
    def f1(self):
        print('in A')

class Foo(A):

    def f1(self):
        super().f1()
        print('in Foo')

class Bar(A):

    def f1(self):  # self = obj
        print('in Bar')

class Info(Foo,Bar):

    def f1(self):  # self = obj
        super(Foo,self).f1()
        print('in Info f1')

obj = Info()  # [Info, Foo, Bar, A]
obj.f1()
多继承: super(S,self) 严格按照self从属于的类的mro的执行顺序,执行 S类的下一位.

super补充

特别注意:super().__init__会给对象封装新的属性,直接将原有的实例化对象中的name,a值覆盖掉.

class A:
	def __init__(self):
		self.name = 'Myclass'
		self.a    = 3 
class B(A):
	def __init__(self,name,a):
		self.name = name 
		self.a = a
		super().__init__()
	def run(self):
		print(self.name)
b = B('xiaohong',1)
print(b.__dict__)
b.run()
输出结果:
{'name': 'Myclass', 'a': 3}
Myclsoas
		

继承父类的方法中没有封装此属性,则不会覆盖.

class A:
	def __init__(self):
		self.a    = 3
	def rer(self):
		self.name = 'Myclass'
class B(A):
	def __init__(self,name,a):
		self.name = name
		self.a = a
		super().__init__()
	def run(self):
		print(self.name)
b = B('xiaohong',1)
print(b.__dict__)
b.run()
返回结果:
{'name': 'xiaohong', 'a': 3}
xiaohong


3.4类的约束
class QQpay:

    def pay(self, money):
        print(f'利用qq支付了{money}')


class Alipay:

    def pay(self, money):
        print(f'利用支付宝支付了{money}')


支付功能 规划一下

def pay(obj,money):  # 归一化设计
    obj.pay(money)

obj1 = QQpay()
obj2 = Alipay()

pay(obj1,100)
pay(obj2,200)

在上面的情况下(在一些重要的逻辑,与用户数据相关等核心部分),我们要建立一种约束,避免发生此类错误.类的约束有两种解决方式:1. 在父类建立一种约束.2. 模拟抽象类(指定一种规范)的概念,建立一种约束.

第一种解决方式:

class Payment:

    def pay(self,money):  # 约定俗称定义一种规范,子类要定义pay方法.
        raise Exception('子类必须定义此方法')


class QQpay(Payment):

    def pay(self, money):
        print(f'利用qq支付了{money}')


class Alipay(Payment):

    def pay(self, money):
        print(f'利用支付宝支付了{money}')

class Wechatpay(Payment):
    def pay(self,money):
        print(f'利用微信支付了{money}')

class Wechatpay(Payment):
    def fuqian(self,money):
        print(f'利用微信支付了{money}')

支付功能 规划一下

def pay(obj,money,choice):  # 归一化设计

    obj.pay(money)
    
obj3 = Wechatpay()
pay(obj3,300)
obj3.fuqian(300)
print(11)
    raise Exception('子类必须定义此方法')
Exception: 子类必须定义此方法
第一种约束:在父类定义一个pay方法,主动抛出异常,如果子类没有定义pay方法,并且沿用了父类的pay方法
即会报错. python推荐的一种约束方式.

第二种:
from abc import ABCMeta,abstractmethod

class Payment(metaclass=ABCMeta):
            # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
    @abstractmethod
    def pay(self, money):
        pass  # 抽象方法


class QQpay(Payment):

    def pay(self, money):
        print(f'利用qq支付了{money}')


class Alipay(Payment):

    def pay(self, money):
        print(f'利用支付宝支付了{money}')

class Wechatpay(Payment):
    def fuqian(self,money):
        print(f'利用微信支付了{money}')

    # def pay(self,money):
    #     pass


obj3 = Wechatpay()
TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
利用抽象类的概念: 基类如上设置,子类如果没有定义pay方法,在实例化对象时就会报错.

4.类的私有成员

  1. 对于类的公有静态属性,类的外部,类的内部,派生类都可以访问.
class B:
	school_name = '老男孩教育'
class A(B):
	class_name = 'python23'
	def func(self):
		print(self.class_name)
obj = A()
print(obj.class_name)
obj.func()
print(obj.school_name)
'''
python23
python23
老男孩教育
'''

  1. 私有静态属性:类外部,派生类不能访问,类内部可以访问
class B:
	school_name = '老男孩教育'
	__consc_edu = '良心教育'
class A(B):
	class_name = 'python23'
	__girlnum = '1个'
	def func(self):
		print(self.class_name)
		print(self.__girlnum)  # 可以访问
		print(self.__consc_edu)# 派生类不可访问
obj = A()
# 私有静态属性:类外部不能访问
print(obj.__girlnum) #不能访问
print(A.__girlnum)   #不能访问
# 私有静态属性:类内部可以访问
obj.func()#派生类不可以访问

  1. 对象的私有属性
class B:
	school_name = '老男孩教育'
	__consc_edu = '教育'
	def __init__(self,weight):
		self.__weight = weight
class A(B):
	def __init__(self,name,age,weight):
		super().__init__(weight)
		self.name = name
		self.__age = age
	def func(self):
		print(self.__age) #类的内部可以使用
		# print(self.__weight) #派生类中也不可以访问
obj = A('张强',18,180)
# print(obj.__age)#类的外部不能访问
obj.func()

  1. 私有方法
class B:
	def __func(self):
		print('B的类内部可以访问')
	def func3(self):
		self.__func()
class A(B):
	def __func1(self):
		print('类外部不可以访问')
	def func(self):
		self.__func1()
		super().func3()
		super(A, self).func3()
obj = A()
obj.func()
'''
类外部不可以访问
B的类内部可以访问
B的类内部可以访问
'''

  • 如果想设定一些私有的或者是不想让类外面用到,密码,加密方式,等设置成私有成员.
  • 拓展: 私有成员除了在类内部,当真访问不到么?
class A:
	__girlnum = '1个'
print(A.__dict__)
{'__module__': '__main__', '_A__girlnum': '1个', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
python中所有的私有成员: 就是在私有成员前面加上 _类名而已.
print(A._A__girlnum)#在前面加上_就可以访问,千万不要这么去访问!!!
print(A.__dict__['_A__girlnum'])# 和上面的一样的

5.类方法与静态方法

5.1.类方法:
class A:
	num = 1
	def func(self):
		print('实例方法')
	@classmethod #类方法:由类名直接调用的方法,他会自动的将类名传给cls
	def a_func(cls):
		print(cls.num)
		'''
		类内部可以实例化
		obj1 = cls()
		print(obj1)
		
		'''
		print(cls)
obj = A()
A.a_func()
print(A)
obj.a_func() #对象也可以调用类方法,但是会自动将其从属于的类名传给cls
'''
1
<class '__main__.A'>
<class '__main__.A'>	
'''

定义一个Student类,我要统计学生的个数.

class Student:
	num = 0
	def __init__(self,name):
		self.name = name
		self.count()
	@classmethod
	def count(cls):
		cls.num += 1
	@classmethod
	def get_num(cls):
		return cls.num
obj = Student('xi')
obj1 = Student('xi')
obj2 = Student('xi')
obj3 = Student('xi')
obj4 = Student('xi')
print(Student.get_num())

5.2静态方法:

不依赖于类,也不依赖于对象,他就是一个普通的函数放置于类中是结构更加清晰与合理.

class A:
	def func(self):
		print(111)
	@classmethod
	def a_func(cls):
		print(cls)
	@staticmethod
	def static_func(a,b,c):
		print(f'{a},{b},{c}静态方法')
# def static_func(a,b,c):
# 	print(f'{a},{b},{c}静态方法')
A.static_func(2,3,4)
obj = A()
obj.static_func(1,2,3)
2,3,4静态方法
1,2,3静态方法

import time
class TimeTest(object):
	def __int__(self,hour,minute,second):
		self.hour = hour
		self.minute = minute
		self.second = second

	def get_year(self):
		pass

	def get_day(self):
		pass

	def last_year(self):
		pass
	@staticmethod
	def showTime():
		return time.strftime('%H:%M:%S',time.localtime())
print(TimeTest.showTime())
obj = TimeTest(1,20,60)
obj.showTime()

6.属性

bmi值测试人体体脂:

class Bmi:

    def __init__(self, name, weight, height):

        self.name = name
        self.weight = weight
        self.height = height

    def bmi(self):
        return self.weight / self.height**2

tb = Bmi('太白',80, 1.75)
print(tb.bmi())


我们要让bmi方法伪装成属性,虽然在代码级别没有提升,但是看起来更合理.

class Bmi:
	def __init__(self,name,weight,height):
		self.name = name
		self.weight = weight
		self.height = height
	@property
	def bmi(self):
		return self.weight / self.height**2
xw = Bmi('小王',60,1.72)
print(xw.bmi)# 伪装属性时,不用在函数名后面加()了
print(xw.weight)

6.1property setter deleter
class Foo:
    def __init__(self,name):
        self.name = name
    @property
    def	aaa(self):
        print('get的时候运行我啊')
    @aaa.setter
    def aaa(self,v):
        print('修改的时候运行我啊')
    @aaa.deleter
    def aaa(self):
        print('删除的时执行我')
obj = Foo('alex')
obj.aaa
obj.aaa = 'taibai'
del obj.aaa
返回结果:
get的时候运行我啊
修改的时候运行我啊
删除的时执行我

6.2设置属性的另外一种写法:
class Foo:

    def get_AAA(self):
        print('get的时候运行我啊')

    def set_AAA(self,value):
        print('set的时候运行我啊')

    def delete_AAA(self):
        print('delete的时候运行我啊')

    bbb = property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应


f = Foo()
f.bbb
f.bbb = 'aaa'
del f.bbb
'''
get的时候运行我啊
set的时候运行我啊
delete的时候运行我啊
'''

7.isinstance,issubclass

  1. isinstance
class A:
	pass
class B(A):
	pass
class C(B):
	pass
obj = B()
print(isinstance(obj,B))
print(isinstance(obj,A))
print(isinstance(obj,C))
True
True
False

  • 对象与类之间的关系
    isinstance(obj,N): 判断 obj对象 是由N类(N的派生类)实例化的对象 返回 True.
    print(isinstance(obj, A))

2.issubclass

class A:
    pass

class B(A):
    pass

class C(B):
    pass
类与类之间的关系
issubclass(M,N) 判断是M类是N类的子孙.
print(issubclass(C, B))
print(issubclass(C, A))

7.type元类

from collections import Iterable
from collections import Iterator

s1 = 'seewfsdkfl'  # class str(Iterable)   Iterable
l1 = [1, 2, 3]
print(type(s1)) # 判断的是对象从属于哪个类
print(type(l1))
print("__iter__" in dir(s1))
print(isinstance(s1, Iterable))

  • type 到底是什么?
  • type 元类 python中一切皆对象 , 一个类也是一个对象.么这个(类)对象肯定是由类实例化出来的.python中你创建的所有类,以及大部分list str等等这些类,都是从type元类实例化得来的.
  • python中继承object类都是新式类.object 也是由type元类实例化得来的.type

8.异常处理

  1. 什么叫异常?
    • 你的程序出现中断,飘红,致使你的整个项目中断了.

9.函数vs方法

9.1通过函数名可以大致判断
def func():
	pass
class A:
	def func(self):
		pass
print(func)#<function func at 0x00000000005D1EA0>
obj = A()
print(obj.func) # <bound method A.func of <__main__.A object at 0x0000000001DE1CF8>>

9.2通过types模块去验证
from types import FunctionType
from types import MethodType


def func():
    pass


class A:

    def func(self):
        pass

    @staticmethod
    def f():
        pass
print(isinstance(func,FunctionType))# True
print(isinstance(func,MethodType))# False
类名调用func 就是一个函数
print(isinstance(A.func, FunctionType))
print(isinstance(A.func, MethodType))
obj = A()
对象调用func 就是一个方法
print(isinstance(obj.func, FunctionType))
print(isinstance(obj.func, MethodType))
对于静态方法的研究,是一个函数
print(isinstance(A.f,FunctionType))
print(isinstance(A.f,MethodType))
obj = A()
对象调用func,也是一个函数
print(isinstance(obj.f,FunctionType))
print(isinstance(obj.f,MethodType))

9.3函数与方法
  • 函数:全部都是显性传参
  • 方法:存在隐性传参

10.反射

​ 通过字符串去操作一个对象
字符串:字符串类型
对象:实例,类,当前文件(模块),其他模块.

10.1从实例的角度去研究反射
class A:
	static_field = '静态属性'
	
	def __init__(self,name,age):
		self.name = name 
		self.age = age
	def func(self):
		print('in A func')
obj = A('小王',18)
print(obj.name)
print(obj.__dict__)
print(hasattr(obj,'name')) #True
print(hasattr(obj,'name1'))#False
print(getattr(obj,'name')) #小王
print(getattr(obj,'name1',None)) #None
setattr(obj,'hobby','玩')#增加了一个属性
print(getattr(obj,'hobby'))
delattr(obj,'name') 删除
print(hasattr(obj,'name'))False
if hasattr(obj,'static_field'):
	print(getattr(obj,'static_field'))#静态属性
if hasattr(obj,'func'): #字符串操作.
	print(getattr(obj,'func')) # 得到一个方法
	getattr(obj,'func')() #可以执行函数.

10.2从类的角度研究反射
class A:
	static_field = '静态属性'
	
	def __init__(self,name,age):
		self.name = name 
		self.age = age
	def func(self):
		print('in A func')
obj = A('小张',18)
print(hasattr(A, 'static_field'))
print(getattr(A, 'static_field'))
print(getattr(A, 'func'))  # <function A.func at 0x0000003423EDFEA0>
getattr(A, 'func')(obj)
返回结果:
True
静态属性
<function A.func at 0x0000009C6A2732F0>
in A func

10.3从当前脚本研究反射.
class B:
	static = 'B类'
	
import sys

# print(sys.modules)
this_modules = sys.modules[__name__]
cls = getattr(this_modules, 'B')
print(cls)#<class '__main__.B'>
obj = cls()
print(obj.static)#B类
2.
def func1():
	print('in func1')
def func2():
	print('in func2')
def func3():
	print('in func3')
l1 = [func1,func2,func3]
l1 = [f'func{i}'for i in range(1,4)]
for i in l1:
	getattr(this_modules,i)()
'''
in func1
in func2
in func3
'''

other_modules
def test():
	print('in test')	
在其它模块研究反射
import other_modules as om 
om.test()
getattr(om,'test')() 也可以执行

class Auth:

	function_list = [('login','请登录'), ('register','请注册'), ('exit', '退出')]

	def login(self):
		print('登录函数')


	def register(self):
		print('注册函数')


	def exit(self):
		print('退出...')


while 1:
	obj = Auth()
	for num,option in enumerate(Auth.function_list,1):
		print(num,option[1])
	choice_num = input('请选择:').strip()
	if hasattr(obj,Auth.function_list[int(choice_num)-1][0]):
		getattr(obj,Auth.function_list[int(choice_num)-1][0])()

11.python中特殊的双下方法

11.1__len__
class A:

    def __init__(self,name,age,hobby):

        self.name = name
        self.age = age
        self.hobby = hobby
        # print(111)

    def __len__(self):
        # print('触发__len__方法')
        return len(self.__dict__)
obj = A('亚伟',1,2)
ret = len(obj)#触发__len__
print(ret)>>>3
一个对象之所以可以使用len()函数,根本原因是这个对象从输入的类中有__len__方法,

11.2__hash__
class A:

    pass

hash(obj) 会调用obj这个对象的类(基类)的__hash__方法
obj = A()
print(hash(obj))#53552261170

11.3 __str__ , __repr__***
class Student:

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        
    def __str__(self):
        return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}123'

obj = Student('小智', 18, '男')
obj1 = Student('dj智', 18, '男')
obj2 = Student('mc智', 18, '男')
#
print(str(obj))
print(str(obj))  # 会触发__str__
print(obj)  # 打印输出实例会触发__str__
print('此对象为%s' %obj)  # 格式化输出会触发__str__
'''
姓名:小智年龄:18性别:男123
姓名:小智年龄:18性别:男123
姓名:小智年龄:18性别:男123
此对象为姓名:小智年龄:18性别:男123
'''

class Student:

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        
    def __repr__(self):
        return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}'

obj = Student('小智', 18, '男')
obj1 = Student('dj智', 18, '男')
obj2 = Student('mc智', 18, '男')
print(obj)  # 触发__repr__
print('此对象是%r' %obj)  # 触发__repr__
'''
姓名:小智年龄:18性别:男
此对象是姓名:小智年龄:18性别:男
'''

两者合一

class Student:

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex


    def __repr__(self):
        return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}'

    def __str__(self):
        return f'姓名:{self.name}年龄:{self.age}性别:{self.sex}123'

obj = Student('小智', 18, '男')
obj1 = Student('dj智', 18, '男')
print(obj) 先触发__str__方法
'''
姓名:小智年龄:18性别:男123
'''

11.4__call__
class A:
    def __init__(self):
        self.a = 1
        print(111)

    def __call__(self, *args, **kwargs):
        print('触发__call__')

obj = A()触发__init__
obj()触发__call__
'''
111
触发__call__
'''

11.5__eq__
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        print(111)
        return True
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)  # 对一个类的两个对象进行比较操作,就会触发__eq__方法
'''
111
True
'''

11.6 __del__

__del__ 析构方法
class A:

    def __del__(self):
        print(111)

obj = A()
'''
111
'''

11.7__new__
 __new__ 构造方法
__new__创造并返回一个新对象.


class A(object):

    def __init__(self):
        print('in __init__')

    def __new__(cls, *args, **kwargs):
        # print(cls)  cls == A
        print('in __new__')
        object1 = object.__new__(cls)
        return object1
obj = A()
类名() 先触发__new__ 并且将类名自动传给cls.
print(obj)

1562985912465

11.8单例模式

一个类只能实例化一个对象,无论你实例化多少次,内存中都只有一个对象.

class A:
	__instance = None
	def __new__(cls, *args, **kwargs):
		if not cls.__instance:
			object1 = object.__new__(cls)
			cls.__instance = object1
		return cls.__instance
obj = A()
obj1 = A()
obj2 = A()
print(obj,obj1,obj2)

11.9 __item__
对对象进行类似于字典的操作

class Foo:
    def __init__(self, name):
        self.name = name

    def __getitem__(self, item):
        print(item)
        print('get时 执行我')

    def __setitem__(self, key, value):
        self.name = value
        print('set时执行我')

    def __delitem__(self, key):
        print(f'del obj{[key]}时,我执行')

obj = Foo('御姐')
# obj.__dict__
# obj['name']
# obj['name'] = '萝莉'
# print(obj.name)
del obj['name']

11.10 __enter__ __exit__
__enter__ __exit__

class A:
    def __init__(self,name):
        self.name = name

    def __enter__(self):
        print(111)

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(222)

# obj = A('mc小龙')

# 对一个对象类似于进行with语句上下文管理的操作, 必须要在类中定义__enter__ __exit__
with A('mc小龙') as obj:
    print(555)
# print(obj.name)


class A:

    def __init__(self, text):
        self.text = text

    def __enter__(self):  # 开启上下文管理器对象时触发此方法
        self.text = self.text + '您来啦'
        return self  # 将实例化的对象返回f1

    def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法
        self.text = self.text + '这就走啦'

# f1 = A('大爷')
with A('大爷') as f1:
    print(f1.text)
print(f1.text)

原文地址:https://www.cnblogs.com/pythonblogs/p/11253076.html