22 python 初学(类,面向对象)
python: 函数式 + 面向对象
函数式可以做所有的事,是否合适?
面向对象:
一、定义:
-
函数: def + 函数名(参数)
面向对象: class -》 名字叫 Bar 类
def -> 名字叫 foo 的方法。第一个参数是 self
-
class Bar(): def __init__(self, name, age): ''' 构造方法,构造方法的特性,类名()自动执行构造方法 ''' # 字段 self.name = name self.age = age print('123') def foo(self): print('foo') print(self.name) print(self.age) obj = Bar('lily', 18) obj.foo()
二、执行:
-
函数:函数名(参数)
面向对象: obj = Bar()# 创建中间人,对象
obj.foo()
# self:代指调用方法的对象(中间人)
中间人里面可以存值:obj.name = ‘lily’
self 永远指调用此方法的调用者
封装:将属性封装到对象里
# 构造方法:
特殊作用:
obj = 类名():完成两件事(1. 创建对象 2. 通过对象执行类中的一个特殊方法 __init__)
小结1:
创建类: class 类名
创建方法: 构造方法: __init__ 创建对象时自动调用此构建方法
普通方法:先创建对象,然后用对象调用普通方法
面向对象三大特性之一:封装
class Bar():
def __init__(self, name, age):
'''
构造方法,构造方法的特性,类名()自动执行构造方法
'''
self.name = name
self.age = age
print('123')
obj = Bar('lily', 18)
适用场景:如果多个函数中有一些相同参数时,转换成面向对象
面向对象三大特性之二:继承
重写:防止执行父类中的方法
主动调用父类方法有两种方式: super(son, self).football() 和 father.football(self)
推荐使用 super 方法
python中支持多继承: a. 左侧优先 b. 一条道走到黑 c. 同一个根时,根最后执行
# ---------------继承----------------------- class father: # 父类,基类 def basketball(self): print('father.basketball') def football(self): print('father.football') class father1: # 父类,基类 def basketball(self): print('father1.basketball') class son(father, father1): # 子类、派生类 gender = 'male' def cooking(self): print('cooking') # 重写 def football(self): # # super 可以实现执行父类中的方法,传的参数: 子类名, self, 以及调用的父类方法 # super(son, self).football() # 方法2:实现调用父类中的方法,传入参数:self father.football(self) print('son.football') s = son() s.cooking() s.basketball() # s.football()
面向对象三大特性之三:多态(python原生多态)
面向对象中高级:
成员:
字段:普通字段(保存在对象中)、 静态字段
普通字段属于对象,保存在对象中,只能通过对象访问;
静态字段属于类,内存中只保存一份,执行时可以通过对象访问,也可以通过类访问
方法:- 普通方法:保存在类中,由对象来调用 self - > 调用对象
- 静态方法:@staticmethod; self 不是必须的;保存在类中,通过类直接调用
- 类方法: @classmethod ;保存在类中,由类直接调用; cls -> 当前类
应用场景:
如果对象中需要保存一些值,执行某功能时,需要使用对象中的值 -》 普通方法
不需要任何对象中的值 -》 用静态方法
属性:定义像方法,调用像字段
class Foo: name = 'foo' def __init__(self): print('init') def bar(self): print('bar') @staticmethod def static_bar(): print('static bar') @classmethod def cls_bar(cls): print('class_bar') # 用于执行 obj.per @property def per(self): print('per') return 1 # 用于执行 obj.per = 123,此处内部实现并没有实现赋值功能,而是实现了一个打印的功能。 当 执行此赋值语句时就会执行此方法 @per.setter def per(self, val): print(val) @per.deleter def per(self): print('del') obj = Foo() print(obj.name) # foo obj.bar() # bar Foo.static_bar() # static bar Foo.cls_bar() # class_bar r = obj.per # per print(r) # 1 obj.per = 123 del obj.per
一、成员修饰符:
公有成员:
私有成员:__字段名,无法直接访问,只能间接访问
二、特殊成员(参考博客:http://www.cnblogs.com/duanv/p/5947525.html)
__init__
__call__
__int__
__str__
__add__
__dict__:打印出对象的属性。(如果是类的属性,且对象没有对该属性进行单独更改,那么就不会保存在对象中,要使用的时候会去上一级找)
__getitem__(self, item): # 切片或索引
__setitem__(self, key, value): 相当于中括号赋值
__delitem__(self, key): 删除 del list[100]
__iter__:
class Foo: __v = '123' def __init__(self, name, age): self.name = name # self.age = age self.__age = age # 私有对象,外部无法直接访问 def __call__(self, *args, **kwargs): print('call') def __int__(self): return 1 def __iter__(self): # 如果类中有 __iter__方法,对象 -》 可迭代对象 # 对象, __iter__()的返回值,迭代器 # for 循环: 迭代器, next # for 循环: 可迭代对象,对象 __iter__(),迭代器,next return iter([11, 22, 33, 44]) # return [11, 22, 33, 44] def show(self): return self.__age @staticmethod def stat(): return Foo.__v @staticmethod def __f1(): return 111 def f2(self): r = self.__f1() return r obj = Foo('lily', 18) print(obj.name) # lily # print(obj.age) r1 = obj.show() print(r1) # 18 r2 = Foo.stat() print(r2) # 123 r3 = obj.f2() print(r3) # 111 # 相当于 Foo()(),对象后面加()会调用 call()方法 obj() # call # int(对象),自动执行对象的 __int__方法,并将返回值赋给int对象 r4 = int(obj) print(r4) # 1 d = obj.__dict__ print(d) li = Foo('su', 18) # 执行 li 对象的类Foo类中的 __iter__方法,并获取其返回值 # 循环上一步返回的对象 for i in li: print(i)
三、metaclass:类的祖宗
- python中一切事物都是对象
- class Foo:
pass
obj = Foo()
# obj是 Foo的对象
# Foo 类是一个对象,type的对象,type 是 metaclass
类都是 type 类的对象
class Mytype(type): def __init__(self, *args, **kwargs): print('mytype') pass def __call__(self, *args, **kwargs): obj = self.__new__(self, *args, **kwargs) self.__init__(obj) class Myfoo(object, metaclass=Mytype): def __init__(self): pass def __new__(cls, *args, **kwargs): return object.__new__(cls, *args, **kwargs) def myfunc(self): print('hello')
obj_of_foo = Myfoo()
#####
首先会创建一个 Myfoo 类对象,会去调用 Mytype 中的 __init__ 方法。
接下来,Myfoo()会去调用 Mytype 中的 __call__方法,执行里面的内容:1. 调用 self,也就是 Myfoo 的 __new__ 方法,生成了一个 Myfoo 类的对象返回赋值给 obj。
2. 调用 Myfoo 里面的 __init__ 方法,并传入 obj 对象,初始化完成。
四、异常处理
# Exception
# 主动抛出异常
# 断言:强制用户服从,不服从报错。可捕获异常,但一般不捕获。
assert + 条件,如果不满足直接报错
五、反射
getattr
setattr
delattr
# _author: lily # _date: 2019/1/21 class Foo: def __init__(self, name, age): self.name = name self.age = age obj = Foo('lily', 18) obj1 = Foo('su', 18) b = 'name' print(obj.__dict__[b]) # 去什么东西里面获取什么内容 v = getattr(obj, 'name') print('v = ', v) # func = getattr(Foo, 'show') # 找到 show 函数 # print(func()) # hasattr(obj, 'name') # 判断有无某种属性 # setattr(obj, 'k1', 'v1') # 设置属性 # print(obj.k1) # v1 delattr(obj, 'name') # print(obj.name) # 会报错 print(obj1.name) # su
六、单例模式
好处:省内存,对象之创建一份
应用:数据库连接
__init__ __call__ __new__:
init 方法是将 对象 初始化的时候调用(比如说: 解释器遇到一个类的定义时,会调用 type 的 init 方法)
call 方法是 对象 被调用的时候调用(比如说:解释器遇到 Foo()、obj() 的时候会调用 call 方法)。
如:1. Foo 类被调用,会去执行 type的call 方法,在 call 方法的实现里,去调用self.new 和 slef.init,此处self 指的是对象Foo。
2. self.new 去实现Foo里面的 new方法(Foo里面的new 默认去调用object的new方法),并返回一个对象。
3. self.init(obj)去实现Foo里面的init 方法,将对象进行初始化。
new 方法才是真正创建一个对象
# _author: lily # _date: 2019/1/21 # 单例模式,永远使用同一份实例(对象) class Foo: __instance = None def __init__(self, name, age): self.name = name self.age = age @classmethod def get_instance(cls, name, age): print(cls) if cls.__instance: return cls.__instance else: cls.__instance = Foo(name, age) return cls.__instance obj1 = Foo.get_instance('lily', 18) print(obj1) del obj1 # # obj2 = Foo.get_instance('su', 18) # print(obj2) # print(obj2.name)