一、面向对象
面向对象的三大特性:
封装、继承、多态
1. 函数式编程和面向对象的对比:
举例:开发一个消息提醒的功能(邮件/短信/微信)
函数:
def email(em, text):
"""
发送邮件
:return:
"""
print(em, text)
def msg(tel, text):
"""
发送短信
:return:
"""
print(tel, text)
def wechat(num, text):
"""
发送微信
:return:
"""
print(num, text)
# 编写功能:向所有的联系方式发送天气
if True:
msg('188888888',
'今天有小雨')
email('hao123@163.com.com',
'今天有小雨')
wechat('xxxx',
'今天有小雨')
面向对象:
class Message:
def email(self, em, text):
"""
发送邮件
:return:
"""
print(em,text)
def msg(self, tel, text):
"""
发送短信
:return:
"""
print(tel,text)
def wechat(self, num, text):
"""
发送微信
:return:
"""
print(num,text)
# 编写功能:向所有的联系方式发送天气
if True:
obj =
Message()
obj.email('hao123@163.com',
'今天有小雨')
obj.msg('188888888',
'今天有小雨')
obj.wechat('xxxx',
'今天有小雨')
对比:
函数:定义简单、调用简单
面向对象:定义复杂、调用复杂 好处:归类,将某些类似的函数功能写在一起
总结:
1 函数式编程可能会比面向对象好
2. Python中支持两种编程方式
3. 面向对象方式格式:
定义:
class 类名: # 定义了一个类
def 函数名(self): # 在类中编写一个“方法”
pass
调用:
x1 = 类名() # 创建了一个对象(实例化一个对象)
x1.函数名() # 通过对象调用其中一个方法
构造方法:
class Foo:
def __init__(self, name): # 构造方法,目的进行数据初始化
self.name = name
self.age = 18
obj = Foo("久末") # 给类名加括号,默认调用构造方法
通过构造方法,可以将数据进行打包,以后使用时,去其中获取即可
应用:
1、将数据封装到对象中,以供自己在方法中使用
class FileHandler:
def __init__(self, file_path):
self.file_path =
file_path
self.f = open(self.file_path,
'rb')
def read_first(self):
# self.f.read()
# ...
pass
def read_last(self):
# self.f.read()
# ...
pass
def read_second(self):
# self.f...
# ...
pass
obj = FileHandler(
'C:/xx/xx.log')
obj.read_first()
obj.read_last()
obj.read_second()
obj.f.close()
2、将数据封装到对象中,供其他函数调用
class FileHandler:
def __init__(self, file_path):
self.file_path =
file_path
self.f = open(self.file_path,
'rb')
def read_first(self):
# self.f.read()
# ...
pass
def read_last(self):
# self.f.read()
# ...
pass
def read_second(self):
# self.f...
# ...
pass
obj = FileHandler(
'C:/xx/xx.log')
obj.read_first()
obj.read_last()
obj.read_second()
obj.f.close()
2. 面向对象如何编写:
方式一:先归类,然后提取公共值
方式二:先在指定类中编写和当前类相关的所有代码,再提取公共值
三大特性:
封装:
将相关功能封装到一个类中
将数据封装到一个对象中
继承:
继承是为了复用,提高代码得重用性
先找子类(派生类),后找父类(基类)—— 子类和父类是相对存在的
先从子类中找,没有就从父类找
多继承(只存在python中的功能):左边更亲
多态:
多种形态或者多种状态
鸭子模型:只要可以嘎嘎嘎叫的就是鸭子
二、类成员
注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份
class Foo:
# 方法
def __init__(self, name):
# 实例变量/字段
self.name =
name
# 方法
def func(self):
pass
# obj,Foo类的对象
# obj,Foo类的实例
obj = Foo(
'jiumo')
1. 变量(字段):
字段包括实例变量和静态变量,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同
由上图可是:
静态变量在内存中只保存一份实例变量在每个对象中都要保存一份
应用场景: 通过类创建对象时,如果每个对象都具有相同的变量,那么就使用静态变量
# 类变量/实例变量
class Foo:
# 类变量/静态字段
country =
'中国'
# 方法
def __init__(self, name):
# 实例变量/字段
self.name =
name
def func(self):
pass
obj1 = Foo(
'jiumo')
obj2 = Foo(
'王XX')
obj1.country =
'美国'
print(obj1.country)
print(obj2.country)
obj1 = Foo(
'jiumo')
obj2 = Foo(
'王XX')
Foo.country =
'美国'
print(obj1.country)
print(obj2.country)
==>
美国
中国
美国
美国
实例变量(字段)
- 公有实例变量(字段)
# 公有实例变量(字段)
class Foo:
def __init__(self, name):
self.name =
name
self.age = 123
# 内部调用
def func(self):
print(self.name)
obj = Foo(
"jiumo")
# 外部调用
print(obj.name)
# jiumo
print(obj.age)
# 123
obj.func()
# jiumo
- 私有实例变量(字段)
# 私有实例变量(字段)
class Foo:
def __init__(self, name):
# 定义为私有
self.
__name =
name
self.age = 123
# 内部调用
def func(self):
print(self.
__name)
obj = Foo(
"jiumo")
# 外部不可直接调用
# print(obj.name) # 报错AttributeError: 'Foo' object has no attribute 'name'
print(obj.age)
obj.func() # 间接访问:让func帮助执行内部私有的__name 就相当在类的内部有认识的”关系” 间接的得到想要的内容
类变量(静态字段)
- 公有类变量(静态字段)
# 默认公有类变量(字段)
class Foo:
country =
"中国"
def __init__(self):
pass
def func(self):
# 内部调用
print(self.country)
print(Foo.country)
# 推荐
# 外部调用
print(Foo.country)
# 中国
- 私有类变量(静态字段)
# 私有
class Foo:
__country =
"中国"
def __init__(self):
pass
def func(self):
# 内部调用
print(self.
__country)
print(Foo.
__country)
# 推荐
# 外部无法直接调用
# print(Foo.__country)
obj =
Foo()
obj.func(
准则:
实例变量(字段)访问时,使用对象访问,即:obj1.name
类变量(静态字段)访问时,使用类访问,即:Foo.country(实在不方便时才使用对象)
易错点:
obj1 = Foo(
'jiumo')
obj2 = Foo(
'王XX')
obj1.name =
'老王'
print(obj1.name)
print(obj2.name)
==>
老王
王XX
什么时候用类变量:
当所有对象中有共同的字段,并且值永远同步,那么可以使用类变量
父类中的私有字段子辈无法知道,但是可以通过调用父类得到
# 子类也不能直接调用父类的私有字段
class Bsae(object):
__secret =
"RMB"
class Foo(Bsae):
def func(self):
# print(self.__secret) # AttributeError: 'Foo' object has no attribute '_Foo__secret'
print(Foo.
__secret)
# AttributeError: type object 'Foo' has no attribute '_Foo__secret'
obj =
Foo()
obj.func()
# 同样可以利用间接调用的方法得到私有字段
class Bsae(object):
__secret =
"RMB"
def money(self):
print(Bsae.
__secret)
class Foo(Bsae):
def func(self):
pass
obj =
Foo()
obj.money()
2. 方法
实例方法
静态方法
1. 定义时:
- 方法上方写 @staticmethod
- 方法参数可有可无
2. 调用时:
- 类.方法名() # 推荐使用
- 对象.方法名()
3. 什么时候使用静态方法:
- 无需调用对象中封装的值
- 类方法
1. 定义时:
- 方法上方写:@classmethod
- 方法的参数:至少有一个cls参数
2. 执行时:
- 类名.方法名 # 默认会将当前类传到参数中
3. 什么时使用类方法:
- 如果在方法中会使用到当前类,那么就可以使用类方法
# 没必要写实例方法
class Foo(object):
def __init__(self, name):
self.name =
name
def func(self):
print(
'实例方法')
# 没有用到构建方法中的值
obj = Foo(
'jiumo')
obj.func()
# 有意义的实例方法
class Foo(object):
def __init__(self, name):
self.name =
name
# 实例方法,最少有一个参数
def func(self):
print(self.name)
# wb
# 静态方法,可以没有参数. 如果方法中无需使用对象中封装的值,那么就可以使用静态方法
# 可以通过类直接调用,不需要实例化类这部操作
@staticmethod
def display():
print(
'静态方法')
# 静态方法
# 类方法
@classmethod
def train(cls, name):
print(cls)
# <class '__main__.Foo'>
print(name)
# 类方法
# 实例方法
obj = Foo(
'wb')
obj.func()
# 静态方法的调用
Foo.display()
# 类方法的调用
Foo.train(
'类方法')
==>
实例方法
wb
静态方法
<
class '__main__.Foo'>
类方法
方法的成员修饰符:方法也有公有方法和私有方法之分 用法同变量的成员修饰符
# 私有的实例方法
class Foo(object):
def __init__(self):
pass
def __display(self,arg):
print(
'私有方法',arg)
def func(self):
self.__display(123
)
obj =
Foo()
# obj.__display(123) # 无法访问
obj.func()
# 私有的静态方法
class Foo(object):
def __init__(self):
pass
@staticmethod
def __display(arg):
print(
'私有静态 方法',arg)
# 私有静态 方法 123
def func(self):
Foo.__display(123
)
@staticmethod
def get_display():
Foo.__display(888)
#私有静态 方法 888
# Foo.__display(123) 报错
obj =
Foo()
obj.func()
Foo.get_display()
3. 属性
class Foo(object):
def __init__(self):
pass
@property
def start(self):
return 1
@property
def end(self):
return 10
obj =
Foo()
print(obj.start)
print(obj.end)
1 编写时:
- 方法上方写@property
- 方法参数:只有一个self参数
2 调用时:
- 无需加括号 对象.方法
3 应运场景:
- 对于简单的方法,当无需传参且有返回值时
4. 特殊方法
class Foo():
# 1.
def __init__(self,a1, a2):
self.a1 =
a1
self.a2 =
a2
# 2.
def __call__(self, *args, **
kwargs):
print(
'wb', args, kwargs)
return 123
# 3.
def __getitem__(self, item):
print(item)
return 123
# 4.
def __setitem__(self, key, value):
# 无返回值
print(key, value, 123
)
# 5.
def __delitem__(self, key):
# 无返回值
print(key)
# 6.
def __add__(self, other):
return self.a1 +
other.a1
# 7.
def __enter__(self):
print(
'开始代码')
return 999
# 8.
def __exit__(self, exc_type, exc_val, exc_tb):
print(
"结束代码")
1.类名() 自动执行
__init__
obj = Foo(1, 2
)
2.对象() 自动执行
__call__
ret = obj(2018, 9, time = 2
)
print(ret)
3.对象[] 自动执行
__getitem__
ret = obj[
'wang']
print(ret)
4.对象[
'xx'] = 11 自动执行
__setitem__
obj['k1'] = 123
5.
del 对象[
'xx'] = 11 自动执行
__delitem__
del obj[
'wang']
6.对象+对象 自动执行
__add__
9. with 对象 自动执行__enter__ 和
__exit__
obj = Foo(1, 2
)
with obj as f:
print(f)
print(
'内部代码')
10.真正的构造方法
__new__
class Foo(object):
def __init__(self,a1, a2):
print(1
)
self.a1 =
a1
self.a2 =
a2
def __new__(cls, *args, **
kwargs):
print(2)
# 执行到此处中断了
Foo(1, 2)
三、反射
python中的反射功能是由以下四个内置函数提供的:
- getattr(): 根据字符串为参数(第二个参数),去对象(第一个参数)中去寻找与之同名的成员
- hasattr():根据字符串的形式,去判断对象中是否有成员
- setattr():根据字符串的形式,动态的设置一个成员(内存)
- delattr():根据字符串的形式,动态的删除一个成员(内存)
class Foo(object):
def __init__(self):
self.name =
'jiumo'
def func(self):
return 'func'
obj =
Foo()
# 检查是否含成员变量
print(hasattr(obj,
'name'))
# True
print(hasattr(obj,
'func'))
# True
# 获取成员
print(getattr(obj,
'name'))
# jiumo
print(getattr(obj,
'func'))
# <bound method Foo.func of <__main__.Foo object at 0x0000016810C9C908>>
# 设置成员
setattr(obj,
'age', 18
)
print(getattr(obj,
'age'))
# 18
setattr(obj,
'show',
lambda num: num + 1
)
# print(getattr(obj, 'show')) # <function <lambda> at 0x0000016811EA47B8>
# 删除成员
delattr(obj,
'name')
print(hasattr(obj,
'name'))
# Fals
delattr(obj,
'show')
print(hasattr(obj,
'show'))
# False
# 反射实例说明:
class Foo(object):
func_lst = [
'f1',
'f2',
'f3']
def f1(self):
print(
'注册成功')
def f2(self):
print(
'登陆成功')
def f3(self):
print(
'注销成功')
obj =
Foo()
while True:
print(
"""
选择需要的功能:
1. 注册
2. 登陆
3. 注销
""")
val = int(input(
"请输入要选择的功能:"))
try:
func_name = obj.func_lst[val-1
]
if hasattr(obj, func_name):
func =
getattr(obj, func_name)
func()
break
except Exception:
print(
"请输入正确的序号!")
转载于:https://www.cnblogs.com/jiumo/p/9545056.html
相关资源:面向对象软件工程