文章目录
1. 方法的动态性
Python是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类的已有的方法。
class Person:
def work(self):
print('努力上班')
def play_game(s):
print(f'{s}在玩游戏')
def work2(s):
print('tomorrow will be better')
Person.play = play_game
p = Person()
p.play() #等价于Person.play(p)
# <__main__.Person object at 0x0000026E4E877370>在玩游戏
Person.work = work2
p.work()
# tomorrow will be better
2. 私有属性和私有方法
关于私有属性和私有方法,有如下要点:
- 通常我们约定,两个下划线开头的属性是私有的,其他为公共的
- 类内部可以访问私有属性(方法)
- 类外部不能直接访问私有属性(方法)
- 类外部可以通过"_类名__私有属性(方法)名"访问私有属性(方法)
注:方法本质上也是属性,只不过是可以通过()执行而已。
2.1 私有属性举例
class Employee:
def __init__(self,name,age):
self.name = name
self.__age = age
p1 = Employee('Peter',23)
print(p1.name)
print(p1.age) #'Employee' object has no attribute 'age'
print(p1._Employee__age) #23
2.2 私有方法举例
class Employee:
def __init__(self,name,age):
self.name = name
self.__age = age
def __work(self):
print('好好工作')
print(f'{self.__age}')
p1 = Employee('Peter',23)
p1._Employee__work()
#好好工作
#23
3. @property装饰器
3.1 @property
可以将一个方法的调用方式变成“属性调用”
class Employee:
@property
def salary(self):
print('salary running...')
return 10000
p1 = Employee()
print(p1.salary)
# salary running...
# 10000
3.2 setter,deleter
class Foo:
@property
def bmi(self):
print('get的时候运行我啊')
# 可以设置返回值
@bmi.setter
def bmi(self, value):
print(value) # 666
print('set的时候运行我啊')
# 无法得到返回值
@bmi.deleter
def bmi(self):
print('delete的时候运行我啊')
# 无法得到返回值
obj = Foo()
obj.bmi # 改变了obj.bmi()的调用方式
obj.bmi = 666 # 操作命令,这个命令并不是改变bmi的值,而是执行被bmi.setter装饰器装饰的函数
del obj.bmi # 操作命名,没有删除bmi,而是执行被bmi.deleter装饰器装饰的函数
4. 继承
如果在类定义中没有指定父类,则默认父类是object类。也就是说,object是所有类的父类,里面定义了一些所有类共有的默认实现,比如__new__
。
子类以及对象可以调用父类的属性、方法,但不能改变
4.1 从类名执行父类的属性
class Animal:
live = '有生命的'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('动物都需要进食')
class Person(Animal): # 括号内为父类
pass
print(Person.__dict__) #虽然__dict__没有live属性,但子类可以执行父类的属性和方法
#{'__module__': '__main__', '__doc__': None}
print(Person.live)
#有生命的
Person.eat(1) #父类名.的方式调用父类方法。类名调用时,self需手动传,需手动写上要传递的内容
# 动物都需要进食
4.2 从对象角度执行父类的属性、方法
class Animal:
live = '有生命的'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('动物都需要进食')
class Person(Animal):
pass
p1 = Person('liye',21,'laddy_boy')
print(p1.__dict__) #从父类__init__为子类封装三个属性
# {'name': 'liye', 'age': 21, 'sex': 'laddy_boy'}
print(p1.live) #有生命的
p1.eat() #动物都需要进食
4.3 如何既要执行父类方法又要执行子类方法
- 方法一
class Animal:
live = '有生命的'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('动物都需要进食')
class Person(Animal):
def __init__(self,name,age,sex,hobby): #p1自动传给self, self = p1
Animal.__init__(self,name,age,sex) #这里的self等于上一行的self,也就是等于p1
# 父类名.的方式调用父类方法,类名调用时,self需手动传,需手动写上要传递的内容
# 这样实现通过父类__init__函数封装了name,age,sex三个属性
self.hobby = hobby
def eat(self):
print('人类需要进食')
p1 = Person('怼怼哥',23,'不祥','music')
print(p1.__dict__)
# {'name': '怼怼哥', 'age': 23, 'sex': '不祥', 'hobby': 'music'}
- 方法二
class Animal:
live = '有生命的'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('动物都需要进食')
class Person(Animal):
def __init__(self,name,age,sex,hobby):
super().__init__(name,age,sex)
self.hobby = hobby
def eat(self):
print('人类需要进食')
p1 = Person('怼怼哥',23,'不祥','laddy_boy')
print(p1.__dict__)
#{'name': '怼怼哥', 'age': 23, 'sex': '不祥', 'hobby': 'laddy_boy'}
4.4 object根类
object类是所有类的父类,因此所有的类都有object类的属性和方法。
4.4.1 mro()
通过类方法mro()或者类的属性__mro__
可以输出这个类的继承层次结构
class A:pass
class B(A):pass
class C(B):pass
print(C.mro()) #或者 print(C.__mro__)
# [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
4.4.2 dir()查看对象属性
内置函数dir(),可以让我们方便的看到指定对象所有的属性。
方法实际上也是属性。只不过这个属性的类型是‘method’而已
class Animal:
live = '有生命的'
def __init__(self,name):
self.name = name
def eat(self):
print('动物都需要进食')
class Person(Animal):
def __init__(self,name,age):
super().__init__(name)
self.age = age
def eat(self):
print('人类需要进食')
p1 = Person('怼怼哥',23)
print(p1.__dict__)#{'name': '怼怼哥', 'age': 23}
print(type(p1.name)) #<class 'str'>
print(type(p1.eat)) #<class 'method'>
print(dir(p1))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'eat', 'live', 'name']
4.4.3__str__
打印一个对象就会触发__str__
方法:打印对象传递给__str__
方法的self
class Person:
def __init__(self,name):
self.name = name
def __str__(self): #__str__必须返回字符串类型,print函数括号内的对象(即打印对象)传给self
return '名字是{}'.format(self.name)
s = Person('ALEX')
print(s) #名字是ALEX
4.5 多重继承
Python支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父类”的特点。但是这样会被“类的整体层次”搞的异常复杂,尽量避免使用。
如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将“从左向右”按顺序搜索。
5. 特殊属性
Python对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。
特殊方法 | 含义 |
---|---|
obj.__dict__ | 对象的属性字典 |
obj.__class__ | 对象所属的类 |
class.__bases__ | 类的基类元组(多继承) |
class.__base__ | 类的基类 |
class.__mro__ | 类层次结构 |
class.__subclasses__() | 子类列表 |
class A:pass
class B:pass
class C(A,B):
def __init__(self,name):
self.name = name
dog = C('Puppy')
print(dir(dog))
print(dog.__dict__) #{'name': 'Puppy'}
print(dog.__class__) #<class '__main__.C'>
print(C.__bases__) #(<class '__main__.A'>, <class '__main__.B'>)
print(C.mro()) #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
print(A.__subclasses__()) #[<class '__main__.C'>]
6. 组合
将一个类的对象封装成另一个类的对象的属性
'''需求:
1. 创建男生、女生类
2.在男生类中定义见面和吃饭方法,并实现吃完饭后去逛街(该方法在女生类中)
'''
class Boy:
def __init__(self,name):
self.name = name
def meet(self,girl_friend = None):
self.girl_friend = girl_friend # girl_friend 的属性值 即为 flower 对象
def have_a_dinner(self):
if self.girl_friend:
print('%s 和 %s 一起晚饭'%(self.name,self.girl_friend.name))
#self.girl_friend 整体相当于与flower对象
self.girl_friend.shopping(self)
#等同于flower.shopping(),括号里的self为wu的对象空间
else:
print('单身狗,吃什么饭')
class Girl:
def __init__(self,name,age):
self.name = name
self.age = age
def shopping(self,boy_friend):
#self == flower ,boy_friend 接收的是wu的对象空间
#这里直接调用boy_friend即wu这个空间,没有对flower这个空间进行属性封装,当调用 boy_friend.name 时,boy_friend相当于一个变量而已,这个变量指向了 wu 这个空间,因此是可以执行的。
#总结:对象空间里可以引用变量(变量未定义),但是变量指向了其他空间,因此是可以正常调用的
print(f'{self.name}和{boy_friend.name}一起去逛街')
wu = Boy('吴超')
flower = Girl('如花',48) #实例化一个Girl对象
#组合:将一个类的对象封装成另一个类的对象的属性
wu.meet(flower)
# 给吴超这个对象封装一个 girl_friend 属性,属性值是 flower 这个对象,可以调用 flower 对象的属性和方法
wu.have_a_dinner()
7. 设计模式
7.1 工厂模式
class CarFactory:
def create_car(self,brand):
if brand == '奔驰':
return Benz()
elif brand == '宝马':
return BMW
elif brand == '比亚迪':
return BYD()
else:
return '未知品牌,无法创建'
class Benz():
pass
class BMW():
pass
class BYD():
pass
factory = CarFactory()
c1 = factory.create_car('奔驰')
c2 = factory.create_car('比亚迪')
print(c1) #<__main__.Benz object at 0x0000016F90739250>
print(c2) #<__main__.BYD object at 0x0000016FA9668AC0>
7.2 单例模式
单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个’单例对象’,然后永久驻留内存中,从而极大的降低开销。
class MySingleton:
__obj = None
__init_flag =True
def __new__(cls, *args, **kwargs):
if cls.__obj == None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self,name):
if MySingleton.__init_flag:
print('init...')
self.name = name
MySingleton.__init_flag = False
a = MySingleton('AA') #init...
b = MySingleton('BB')
print(a)
# <__main__.MySingleton object at 0x000001DF072A9250>
print(b)
# <__main__.MySingleton object at 0x000001DF072A9250>