python之面向对象
7.1 面向对象的基本内容
7.1.1 格式
-
对象和类的关系,对象是类的实例
-
具有相同方法和属性的一类事物称为类
-
一个拥有具体属性值和动作的具体个体
class Files: #类中的函数不再称为函数,称为方法
def write(self,name):
print(name)
return 666
def read(self,name):
print(name)
def append(self,name):
print(name)
obj = Files() #创建该类的对象
result = obj.write('alex') #通过对象调用方法
print(result)
-
类内部数据(包括嵌套的类)在解释器解释的时候就执行,方法内部 调用的时候才执行
class Foo(object):
print(123) #一运行就执行
def func(self):
pass
class Base(object):
print(456)
7.1.2 面向对象的特性
-
特性:面向对象有三个主要特征,分别是封装性、继承性和多态性。
7.1.2.1 封装
-
封装分为数据储存的封装和对方法的封装归类
class Person:
def __init__(self,n,a,g):
self.name = n
self.age = a
self.gender = g
def show(self):
temp = '我是%s,年龄%s,性别%s'%(self.name,self.age,self.gender,)
print(temp)
obj = Person('薛奎','20','太监') #将数据直接封装到对象里,方便使用 ,得有__init__
obj.shouw()
class Files:
def write(self,content):
with open(self.file,mode='w',encoding ='utf-8')as f1:
f1.write(content)
f1.close()
def read(self):
with open(self.file,mode='r',encoding='utf-8')as f2:
content = f2.read()
f2.close()
obj = Files() #又称实例化一个对象
obj.file = 'read.txt' #obj就是方法中的self ******
obj.write('123')
obj.read()
7.1.2.2 继承
class Base:
def f1(self):
pass
class Foo(base): #类(类)即代表括号外是派生类, 里面是基类,运行类内部,没有的会去基类里寻找
def f2(self):
pass
obj = Foo()
obj.f1()
obj.f2()
-
多个类中如果有公共的方法,可以放到基类中避免重复编写。
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
self.f1()
print('foo.f2')
def f1(self):
print('foo.f1')
obj = Foo()
obj.f2() #结果 'foo.f1' 'foo.f2' obj是实例化的foo,优先在 Foo中寻找
class Base:
def f1(self):
self.f2()
print('base.f1')
def f2(self):
print('base.f2')
class Foo(Base):
def f2(self):
print('foo.f2')
obj = Foo()
obj.f1() #结果 'foo.f2' 'base.f1'
-
注意事项:self 到底是谁?self 是哪个类创建的,就从此类开始找,自己没有就找父类。
7.1.2.3 多态
-
一个类表现出来的多种状态
-
什么是鸭子模型?
对于一个函数而言,python对参数的类型并不受限制,传入的参数也可以是任何类型,但是在函数中如果有一些方法(send),那么就会默认对传入的参数有了一定的限制,即传入的参数必须要有send方法。这就是鸭子模型。 -
Python本身没有多态的概念,本身必须遵循多态
-
函数重写就是多态的体现形式。即多个类继承同一个父类,多个类有的会重写这个方法有的不会,结构调用这些不同的类,结果也不同。
7.1.3 基础概念
-
什么是类 : 具有相同方法和属性的一类事物
-
什么是对象、实例 : 一个拥有具体属性值和动作的具体个体
-
实例化 :从一个类 得到一个具体对象的过程
7.1.4 面向对象应用场景
-
函数(业务功能)比较多,可以使用面向对象来进行归类。
-
想要做数据封装(创建字典存储数据时,面向对象)。
-
游戏示例:创建一些角色并且根据角色需要再创建人物。
7.2 类成员
7.2.1 实例变量
class Foo:
def __init__(self,name):
self.name = name
def info(self):
pass
obj1 = Foo('alex')
obj2 = Foo('eric') #这俩都是实例变量,由对象引入的变量
7.2.2 类变量
class Foo:
city = '北京' #类变量
def __init__(self,name):
self.name = name
def func(self):
pass
obj1 = Foo('李杰')
obj2 = Foo('女神')
-
定义就是写在类的下一级和方法同级
-
访问:类.类变量名称 / 对象.类变量名称
7.2.3 绑定方法/普通方法
-
定义:至少有一个self参数执行:先创建对象,由对象.方法()。
-
执行:先创建对象,由对象.方法()
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
obj = Foo()
obj.func(1,2)
7.2.4 静态方法
-
定义:@staticmethod装饰器 参数没有限制
-
执行:类.静态方法名() 对象.静态方法() (不推荐)
class Foo:
@staticmethod
def f1(): #直接通过类就可以调用,不用绑定参数self
print(123)
Foo.f1() #也可以obj.f1()也可以 不推荐
7.2.5 类方法
-
定义:@classmethod装饰器
-
要点:得有cls参数,当前类
-
执行:类.类方法() 对象.类方法() (不推荐)
class Foo:
@classmethod
def f2(cls,a,b):
print('cls是当前类',cls)
print(a,b)
Foo.f2(1,2) #通过类直接执行
# 问题: @classmethod和@staticmethod的区别? """一个是类方法一个静态方法。 定义: 类方法:用@classmethod做装饰器且至少有一个cls参数。 静态方法:用staticmethod做装饰器且参数无限制。 调用: 类.方法直接调用。 对象.方法也可以调用。
7.2.6 属性
-
定义:property装饰器 / 只有一个self参数
-
执行:对象.方法不用加括号
class Foo:
@property
def func(self):
print(123)
return 666
obj = Foo()
print(obj.func) #不用加括号 123 666
7.3 成员修饰符
-
公有,公共访问
-
私有,只有自己内部可以访问(同一类之间的函数之间也可以,但不适用派生类和基类)
-
类也不可以访问自己私有的类变量
class Foo:
def __fun(self):
print('msg')
def show(self):
self.__fun()
obj = Foo()
obj.__fun() #无法访问, 对象访问类内部
obj.show() #通过访问show 可以再调用__fun
-
强制访问
class Foo:
def __init__(self,name):
self.__x = name
obj = Foo('alex')
print(obj._Foo__x) _Foo 强制访问
7.4 类嵌套
-
函数:参数可以是任意类型的
-
字典:对象和类都可以作为字典的key和value
class StackConfig(object):
list_display = '李邵奇'
def changelist_view(self):
print(self.list_display) #搞清楚self每次是谁的对象
class UserConfig(StackConfig):
list_display = '利奇航'
class AdminSite(object):
def __init__(self):
self._register = {}
def registry(self,key,arg=StackConfig):
self._register[key] = arg
def run(self):
for key,value in self._register.items():
obj = value()
obj.changelist_view()
site=AdminSite() #创建AdminSite类的对象
site.registry(1) #构建字典1:StackConfig
site.registry(2,StackConfig) #构建字典2:StackConfig
site.registry(3,UserConfig) #构建字典3:UserConfig
site.run() #执行run方法,结果 '李邵奇' '李邵奇' '利奇航'
7.5 类中的特殊成员
7.5.1 __init__
-
将实例的对象初始化
class Foo(object):
def __init__(self,a):
self.a = a
obj = Foo('alex')
7.5.2 __new__
-
类没有定义new的时候,自动找父类的
__new__方法 -
init负责实例化对象,而new则是在类实例化的时候是否要用这个init方法,即构造方法
-
一般涉及到用new是需要重载父类的new方法来达到结果
class Foo(object):
def __new__(cls,*args,**kwargs):
return object.__new__(cls) #基类的new
7.5.3 __call__
-
对象直接加括号,直接输出
class Foo(object):
def __call__(self,*args,**kwargs):
print('执行方法')
obj = Foo()
obj()
# 也等于 Foo()()
7.5.4 __setitem__ __getitem__ __delitem__
class Foo(object):
def __setitem__(self, key, value):
pass
def __getitem__(self, item):
return item + 'uuu'
def __delitem__(self, key):
pass
obj1 = Foo()
obj1['k1'] = 123 # 内部会自动调用 __setitem__方法
val = obj1['xxx'] # 内部会自动调用 __getitem__方法
print(val)
del obj1['ttt'] # 内部会自动调用 __delitem__ 方法
7.5.5 __str__
-
打印对象,自动调用这个方法 ,用作是一个对象的描写,只有打印生效
class Foo(object):
def __str__(self):
return 'asdf'
obj = Foo()
print(obj)
7.5.6 __dict__
-
去对象中找到对应变量并转化为字典
class Foo(object):
def __init__(self,name,age,email):
self.name = name
self.age = age
self.email = email
obj = Foo('alex',19,'xxx@qq.com')
print(obj)
print(obj.name)
print(obj.age)
print(obj.email)
val = obj.__dict__
print(val)
7.5.7 __enter__ __exit__ 上下文管理
#方法1
class Context:
def __enter__(self):
print('进入')
return self
def do_something(self):
print('内部执行')
def __exit__(self, exc_type, exc_val, exc_tb):
print('推出')
#方法2 放到另一个类
class Foo(object):
def do_something(self):
print('内部执行')
class Context:
def __enter__(self):
print('进入')
return Foo()
def __exit__(self, exc_type, exc_val, exc_tb):
print('推出')
with Context() as ctx:
print('内部执行')
ctx.do_something()
7.5.8 __add__
-
两个对象相加,(其实都可以)
class Foo(object):
def__add__(self,other):
return 13
obj1 = Foo()
obj2 = Foo()
val = obj1 + obj2
print(val)
7.5.9 __repr__
-
如果有str和repr,打印对象 调用str方法,打印列表或其他对象容器,调用repr方法
-
如果只有str,无论什么时候都是调用str,repr也是同理
-
实际应用上,str面向对象 repr面向更多面向程序员
-
打印使用str 调用使用repr
class D(object):
def __str__(self):
return "a __str__"
def __repr__(self):
return "a __repr__"
>>> dr = D()
>>> print dr
a __str__
>>> dr
a __repr__
7.6 可迭代对象
-
只要能被for循环,内部就有iter方法
-
在类中实现
__iter__方法且返回一个迭代器(或者是生成器)
class Foo(object):
def __iter__(self): #实现方法
return iter([1,2,3,4]) #返回迭代器
class Foo(object): #生成器是特殊的迭代器
def __iter__(self):
yield 1
yield 2
...
obj = Foo()
7.7 约束
-
寻找方便:在源代码或者别人写的代码中加入代码,根据查看基类代码,要在子类中都要添加此send
-
别人也方便:从上往下看,可以看到基类中存在raise中的约束,也方便掌握代码结构
-
更加规范:代码不会轻易出BUG
-
没有也可以,只要不调用这个send也不会出错,只是为了规范,同上。
class base(object):
def send(self):
raise NotImplementedError('子类中必须有方法')
class Foo(base):
def send(self):
print('我是真的')
class Fooo(base):
def send(self):
print('我也是真的')
class Foooo(base):
def func(self):
print('我不知道发生了什么')
obj = Foooo()
obj.send() #报错 NotImplementedError 提醒
7.8 反射
-
实现了根据输入的字符查找元素并操作
-
根据字符串形式去操作对象中的元素
7.8.1 getattr
-
根据字符串的形式去某个对象中操作他的成员,(对象,‘方法’)
class Foo(object):
def __init__(self,name):
self.name = name
def login(self):
print('对了对了')
obj = Foo('alex')# 获取变量
v1 = getattr(obj,'name')# 获取方法
method_name = getattr(obj,'login')
method_name()
7.8.2 setattr
-
根据字符串的形式去某个对象中设置成员,(对象,‘要设置的元素’,‘要设置的结果’)
class Foo(object):
def __init__(self,name):
self.name = name
obj = Foo(888)
v1 = setattr(obj,'name',7) #obj.name = 7 改变原值
print(obj.name)
7.8.3 delattr
-
根据字符串的形式去某个对象中删除成员,(‘要删除哪个对象里的’,‘要删除的变量或元素’)
class Foo:
pass
obj = Foo()
obj.k1 = 999
print(obj.k1) # 999
delattr(obj,'k1')
print(obj.k1) #已删除 'Foo' object has no attribute 'k1'
7.8.4 hasattr
-
根据字符串形式去某个对象中判断是否有该成员 (‘对象’,‘元素’)
from wsgiref.simple_server import make_server
class View(object):
def login(self):
return '登陆'
def logout(self):
return '等处'
def index(self):
return '首页'
def func(environ,start_response):
start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
#
obj = View()
# 获取用户输入的URL
method_name = environ.get('PATH_INFO').strip('/')
if not hasattr(obj,method_name):
return ["sdf".encode("utf-8"),]
response = getattr(obj,method_name)()
return [response.encode("utf-8") ]
# 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
server = make_server('192.168.12.87', 8000, func)
server.serve_forever()
7.9 单例模式
-
无论实例化多少次,永远都是第一次实例化的对象
-
优点是可以增加效率,防止链接太多导致的崩溃
class Singleton(object):
instance = None
def __new__(cls,*args,**kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
#当运行第一次,创建new的对象,赋值给类变量instance,之后在使用这个类,对象相同
obj1 = Singleton()
obj2 = Singleton()
class FileHelper(object):
instance = None
def __init__(self, path):
self.file_object = open(path,mode='r',encoding='utf-8')
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
obj1 = FileHelper('x')
obj2 = FileHelper('x') #无论打开多少次都是同一个链接
7.10 项目结构目录
-
bin 程序入口 可执行文件
-
config 配置文件
-
db 数据
-
lib 公共代码
-
src 业务代码
-
项目设计的要求:通过改变配置文件,不改变其他代码(即源代码),可以达成调解代码的目的。是项目设计的最终需求

浙公网安备 33010602011771号