Python
一种设计思想
面向对象
- 面向对象
- 类
- 对象
- 属性
- 方法
- 构成
- 封装(私有化)
- 继承
- 多态(多父类)
- class
- 定义类
- 类的方法(函数)
- 普通
- 类
- 静态
- 魔术方法
代码示例:
class Foo: # 默认继承父类(object),可省略空括号
bar = 'bar'
object1 = Foo() # 创建对象object1
print(object1.bar) # bar
object2 = Foo() # 创建对象object2
object2.bar = 'foo' # 修改类作用于对象的属性(此修改仅作用于对象,类属性不会受影响)
print(object2.bar) # foo(调用顺序:对象属性 > 类属性)
Foo.bar = 'bar' # 修改类属性
普通方法
代码示例:
# 示例01:
class Foo:
def bar(self): # self相当于this,当前类的对象(self与object1的内存地址一样,也可以通过self调用函数本身递归)
print(self)
object1 = Foo()
object1.bar() # <__main__.Foo object at 0x000002EB78163EE0>
# 示例02(公共属性:类中函数都可以通过self来使用属性):
class Foo:
def __init__(self,name): # 只要创建对象,__init__函数就会执行(再将内存地址赋值给对象)
print('__init__',end = ' ')
self.name = name
def bar(self):
print(self.name)
object1 = Foo('HQSY') # 相当于执行__init__函数的内容
object1.bar() # __init__ HQSY
类方法
- @classmethod
- 定义类方法
- 特点(不依赖于对象,在创建对象之前就可以使用)
- 定义需要依赖装饰器(@classmethod)
- 类方法中的参数不是对象,而是类
- 类方法中只可以使用类属性
- 类方法可以直接使用(类名.类方法)来访问
- 类方法中不可以使用普通方法中的属性
代码示例:
class Foo:
bar = 'bar'
@classmethod
def app(self):
print(self.bar)
Foo.app() # bar
# 私有化:
class Foo:
__bar = 'bar'
def app(self):
self.__bar = 'app'
print(self.__bar)
object1 = Foo()
object1.app() # app
print(object1.__bar) # 报错
print(Foo.__bar) # 报错
静态方法
- 特点
- 需要装饰器(@staticmethod)
- 定义函数时可不带参数
- 只能访问类属性和方法,对象是无法访问的
- 加载时机同类方法一起同时加载
代码示例:
class Foo:
bar = 'bar'
@staticmethod
def app():
print(Foo.bar)
Foo.app() # bar
'''
类、静态方法总结:
1. 不相同
· 装饰器不同
· 类方法是有参数的,而静态方法无参数
2. 相同
· 只能访问类的属性和方法,对象是无法访问的
· 都可以通过类名调用访问
· 都可以在创建对象之前使用,因为都是不依赖对象的
3. 普通方法与类、静态方法的区别
· 没有装饰器
· 普通方法永远依赖于对象,因为每个普通方法都有一个必要参数(self)来存放对象的内存地址
· 只有创建了对象才可以调用普通方法,否则无法调用
'''
魔术方法
代码示例:
'''
1. __init__
· 初始化对象属性(执行时机:创建对象)
2. __new__
· 实例化(执行时机:创建对象)
3. __del__
· 析构(执行时机:手动删除,系统回收)
4. __call__
· 调用对象(执行时机:对象名被当作函数名调用)
5. __str__
· 方法中的return会返出值(执行时机:打印对象名)
'''
# __new__:
'''
逻辑:对象传的值先给了__new__,再随着return返给了__init__(整个过程地址从头到尾都是一个"新地址"),最后再把"加工"后的地址赋给了对象
'''
class Foo:
def __init__(self):
print('__init__')
def __new__(cls): # 按照规范形参名称填写cls
print('__new__')
return object.__new__(cls) # return返出创建的新地址给了__init__,cls:新地址(如果不return,那么bar接收的值为空)
bar = Foo()
'''
__new__
__init__
'''
# __call__:
'''
逻辑:执行时机满足时,就会执行__call__函数体
'''
class Foo:
def __call__(self,bar):
print(bar)
object01 = Foo()
object01('bar') # bar
# __del__:
'''
逻辑:当一块空间没有了任何引用时,就会执行__del__函数体(当执行完全部代码时,系统会先删除全部引用,再回收全部空间)
'''
class Foo:
def __init__(self,bar):
self.bar = bar
def __del__(self):
print(self.bar)
object01 = Foo('bar')
object02 = object01
object03 = object01
del object01
print('foo')
del object02,object03
'''
foo
bar
'''
# __str__:
'''
逻辑:打印对象时就会执行__str__函数体,返出的值给了对象(使类的信息更加完整)
'''
class Foo:
def __str__(self):
return 'bar' # 必须是字符串
object01 = Foo()
print(object01) # bar
# 引用补充:
class Foo:
def __init__(self,bar):
self.bar = bar
object01 = Foo('bar')
object02 = object01
object03 = object01
object01.bar = 'foo' # 在原有的地址空间做修改
print(object02.bar,object03.bar) # foo foo
P01 = 'foo'
P02 = P01
P01 = 'bar' # 直接改变地址
print(P02) # foo
# 类中的方法相互调用补充:
class Foo:
def a(self):
pass
def b(self):
self.a()
私有化
- 概念
- 不允许外界对象修改类中私有化类对象属性的值,只能从类里面修改
- 私有化属性、定义公有的set方法(赋值)和get方法(取值)
- 特点
- 隐藏属性不被外界直接随意更改
- 修改时必须通过set函数体的逻辑处理才可以做修改
- 如果想获取具体的某一个属性,可通过get函数体访问对应的属性
- 子类继承不了父类的私有化属性
- 符号
- __
代码示例:
class Foo:
def __init__(self, a):
self.__a = a # 不允许直接从外界改变
def mySet(self, b): # 允许从外界改变的方法
self.__a = b
def myGet(self):
return self.__a # 允许从外界查看属性的方法
object01 = Foo('foo')
print(object01.myGet())
object01.mySet('bar')
print(object01.myGet())
'''
foo
bar
'''
# 强制访问私有化的属性:
'''
1. __dict__
· 可以理解为dir()的子集(返回值:dict)
· 之所以访问不了私有化属性是因为系统底层进行了重命名(伪私有化)
'''
class Foo:
__bar = 'foo'
print(Foo.__dict__)
print(Foo._Foo__bar)
'''
{'__module__': '__main__', '_Foo__bar': 'foo', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
foo
'''
dir
查看类中所有属性与函数(返回值:list)
代码示例:
# 包括系统底层内置的东西
class Foo:
bar = 'foo'
def a(self):
pass
print(dir(Foo)) # ['__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__', 'a', 'bar']
# 特殊私有化处理:
class Foo:
def __init__(self, bar):
self.__bar = bar
@property # get(可单独使用)
def a(self):
return self.__bar
@a.setter # set(必须与@property配合使用)
def a(self, bar):
if bar == 'foo':
self.__bar = bar
object01 = Foo('bar')
object01.a = 'foo' # 给私有化的属性赋值
print(object01.a) # foo
关联关系
- has-a
- 一个类中使用了另一种自定义类型
- 自定义类型
- 算是自定义类,都可以将其当成一种数据类型
代码示例:
class Foo:
def __init__(self, bar):
self.bar = bar
def __str__(self): # 如果没有__str__方法,那么输出的将是自定义类型对象的内存地址
return self.bar
class Bar:
def __init__(self, bar):
self.bar = bar
def __str__(self):
return str(self.bar) # 不转str会报错,因为是自定义类型
# 自定义类型与系统类型是根本上的区别
object01 = Foo('bar') # 实参为自定义类型,object01为自定义类型的对象
object02 = Bar(object01) # 把自定义类型的对象当作实参传入到类中(转换为str时会自动调用Foo类中的__str__方法)
print(object02)
继承关系
- 作用
- 代码复用
- is-a
- 一个类中继承了父类的属性或动作
代码示例:
class Foo: # 父类
def __init__(self):
self.a = 'bar'
def b(self):
print(self.a)
class Bar(Foo): # 子类继承父类
pass
object01 = Bar()
object01.b() # bar
super
指向父类的内存地址
代码示例:
'''
1. super().__init__()
· 等同于 super(子类名, self).__init__()
· 只不过源式子多了一个类型判断(对象是不是类型造出来的)
class Bar(Foo):
def __init__(self):
Foo.__init__(self)
'''
class Foo: # 父类
def __init__(self):
self.a = 'foo'
def b(self):
print(self.a)
class Bar(Foo): # 子类继承父类
def __init__(self):
print('bar')
super().__init__() # 调用父类的__init__方法
super().b() # 调用父类的b方法
object01 = Bar()
object01.b()
'''
bar
foo
foo
'''
class Foo:
def __init__(self, a):
self.a = a
def b(self):
print('foo')
class Bar(Foo):
def __init__(self, c):
print('bar')
super().__init__(c) # 传给父类,且因为继承了父类,这块空间也同等地有了'self.a'属性
class Hoo(Foo):
pass
object01 = Bar('kurosaki')
object01.b()
object02 = Hoo('shigure') # 子类无__init__时默认传给父类,且因为继承了父类,这块空间也同等地有了'self.a'属性
object02.b()
'''
bar
foo
foo
'''
# 如果子类与父类有同名的方法,则优先级为子类 > 父类(重构)
class Foo:
def a(self):
return 'foo'
class Bar(Foo):
def a(self):
return 'bar'
object01 = Bar()
bar = object01.a()
print(bar) # bar
inspect
- 概念
- Python允许多重继承(如果类中有相同名称的方法,则依照搜索顺序)
- getmro
- 显示多重继承搜索顺序(返回值:tuple)
代码示例:
import inspect
class Foo:
def a(self):
print('foo')
class A(Foo):
def a(self):
print('a')
class B(Foo):
def a(self):
print('b')
class C(A, B):
pass
object01 = C()
object01.a() # a
print(inspect.getmro(C)) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Foo'>, <class 'object'>)
# __mer__:显示多重继承搜索顺序(返回值:tuple)
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Foo'>, <class 'object'>)
# 经典多重继承
class A:
def foo(self):
print('A foo')
def bar(self):
print('A bar')
class B:
def foo(self):
print('B foo')
class C(A, B):
pass
class D(A, B):
def bar(self):
print('D bar')
class F(C, D):
pass
object01 = F()
object01.foo()
object01.bar()
'''
A foo
D bar
'''
多态
代码示例:
class A:
def __init__(self, a):
self.a = a
def foo(self, args): # Python形参可以接收不同父类的子类的自定义类型的实参
if isinstance(args, B): # 判断是否继承或属于类B
print('foo')
else:
print('bar')
class B:
def __init__(self, b):
self.b = b
class C(B):
def bar(self):
print('C')
class D:
def how(self):
print('D')
object01 = C('object01')
object02 = A('object02')
object02.foo(object01)
object03 = D()
object02.foo(object03)
object04 = B('object04')
object02.foo(object04)
'''
foo
bar
foo
'''
单例模式
作用:节约内存空间(因为每次创建对象时都会产生新的内存空间)
代码示例:
'''
1. 每次创建对象时都会先访问类中的__new__方法,如果类中没有,则去父类object中寻找__new__方法
2. 如果类中有__init__,return时会先返给__init__方法,再返给创建的类对象
'''
class Foo:
__bar = None # 单例的地址就存放在__bar变量中,之所以私有化是因为不被外界访问与修改
def __new__(cls): # cls指的是当前的类(重写父类object的__new__方法,使得创建对象时不产生新的内存地址)
if cls.__bar is None:
cls.__bar = object.__new__(cls) # 本质上就是调用父类产生一个内存地址再返出去,则当多次创建类对象时走的else分支
return cls.__bar
else:
return cls.__bar # 返出相同的内存地址给类对象
object01 = Foo()
object02 = Foo()
print(object01)
print(object02)
'''
<__main__.Foo object at 0x0000022488E2DFA0>
<__main__.Foo object at 0x0000022488E2DFA0>
'''