python面向对象

OOP 面向对象的程序开发

用几大特征表达一类事物称为一个类,类更像是一张图纸,表达的是一个抽象概念
对象是类的具体实现,更像是由这图纸产出的具体物品,类只有一个,但对象可以通过这个类实例化出多个
对象是类的实例,类是对象的模板
*类中的成员只有方法和属性,不要裸露的把判断和循环直接写在类中,而是用方法包起来

(1)类的定义
# 定义一
class Myclass:
    pass

# 定义二
class Myclass():
    pass

# 定义三
class Myclass(object):
    pass
(2)类的实例化 产生的是对象
>>> class Car():
...   color = "red"
...
>>> obj = Car()
>>> print(obj)
<__main__.Car object at 0x0000026497119BE0>
>>>
(3)类的基本结构
  1.成员属性
  2.成员方法
>>> class MyCar():
...   # 成员属性
...   color = "red"
...   # 成员方法
...   def run():
...     pass
...
>>>
(4)类的命名
  推荐使用驼峰命令,每个单词首字母大写
  myclass --> MyClass

面向对象三大特征: 封装 继承 多态

封装:对类中成员属性和方法的保护,控制外界对内部成员的访问,修改,删除等操作
  对象的使用方式:
    对象.属性
    对象.方法
class MyCar():
    # 公有成员属性
    attra = "属性"
    # 私有成员属性
    __attrb = "私有属性"
    # 公有成员方法
    def run(self):
        print("调用属性",self.attra)
    # 私有成员方法
    def __private_info(self):
        print("私有成员方法")

"""
绑定方法:
  1.绑定到对象,默认把对象当成参数进行传递,self形参接受
  2.绑定到类,默认把类当成参数进行传递,形参接受
"""
# 实例化对象
obj = MyCar()

# 1.实例化的对象防卫公有成员属性和方法
print(obj.attra)
obj.run()

# 2.实例化的对象动态添加公有成员属性和方法
"""
__dict__ 获取对象或者类的内部成员
"""
print(obj.__dict__) # 当前对象没有成员
obj.attra = "改变属性"
print(obj.__dict__)

# 动态添加成员方法
# 1) 添加无参方法
def methoda():
    print("新添加的方法1")
# 类外的函数赋值给obj对象一个成员方法
obj.methoda = methoda
obj.methoda()
print(obj.__dict__)

# 2) 添加有参方法
def methodb(self,arge):
    print(self.attra,arge)
# 赋值
obj.methodb = methodb
# 需要手动传入对象
obj.methodb(obj,"有参方法")

# 3) 添加lambda表达式
obj.methodc = lambda : print("添加方法c")
obj.methodc()

# -------------------------------
# 运行结果
属性
调用属性 属性
{}
{'attra': '改变属性'}
新添加的方法1
{'attra': '改变属性', 'methoda': <function methoda at 0x0000020F70DA2EA0>}
改变属性 有参方法
添加方法c
继承
一个类除了自身所拥有的属性方法之外,还获取了另外一个类的成员属性和方法
   一个类继承另外一个类,当前类是子类(衍生类),被继承的类是父类(基类、超类)。所有类的父类都是object
   单继承
    -1.子类可以使用父类的共有方法
>>> class Father():
...   attra = 'a'
...   def func(self):
...     print('func')
...
>>> class Son(Father):
...   pass
...
>>> obj = Son()
>>> print(obj.attra)
a
>>> obj.func()
func
>>>

    -2.子类不能调用父类的私有方法

>>> class Father():
...   __attrb = 'b'
...   def __func(self):
...     print('private func')
...
>>> class Son(Father):
...   pass
...
>>> obj = Son()
>>> obj.__attrb
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Son' object has no attribute '__attrb'
>>> obj.__func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Son' object has no attribute '__func'
>>>

    -3.子类可以改写父类方法

      self对象优先调用本类中的方法,如果本类中没有调用父类的

  多继承

# 基本语法
class Father():
    attra = "属性a"
    def methoda(self):
        print("methoda")

class Mother():
    attrb = "属性b"
    def methodb(self):
        print("methodb")

class Son(Father,Mother):
    pass

obj = Son()
print(obj.attra)
obj.methoda()

# 执行结果
属性a
methoda

 

   类的相关操作

    语法:类.属性  类.方法()

  1.调用类中成员的时候,要么使用对象,要么使用类

      对象可以使用类中的相关公有成员,但是没有归属权

   类中的成员都归当前这个类所有,但是不能使用对象中的成员

  2.对象中如果有成员,使用自己的,如果没有,使用类中的

class Person():
    attra = "公有成员属性"
    __attrb = "私有成员属性"
    def method():
        print("普通公有方法",Person.__attrb)
    def __private_method():
        print("普通私有方法")

obj = Person() # 实例化一个对象
print(Person.attra) # 类访问成员属性
print(Person.method()) # 类访问成员方法
"""
1.对象无法调用无参的普通方法,必须加上self
2.无论是对象还是类,都无法在类外调用类中的私有成员
"""
print(Person.__dict__) # 查看类的所有成员

# 定义的类动态添加公有成员属性和方法
Person.attrc = "添加成员属性"
print(Person.__dict__)
print(obj.__dict__)

# 1) 添加无参方法
def methoda():
    print("添加无参方法")
Person.methoda = methoda
Person.method()

# 2) 添加有参方法
def methodb(name):
    print("方法",name)
Person.methodb = methodb
Person.methodb("有参方法")

# 3) lambda表达式
Person.methodc = lambda : print("lambda表达式")
Person.methodc()

# 执行结果
公有成员属性
普通公有方法 私有成员属性
None
{'__module__': '__main__', 'attra': '公有成员属性', '_Person__attrb': '私有成员属性', 'method': <function Person.method at 0x00000280E4203598>, '_Person__private_method': <function Person.__private_method at 0x00000280E4203488>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{'__module__': '__main__', 'attra': '公有成员属性', '_Person__attrb': '私有成员属性', 'method': <function Person.method at 0x00000280E4203598>, '_Person__private_method': <function Person.__private_method at 0x00000280E4203488>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'attrc': '添加成员属性'}
{}
普通公有方法 私有成员属性
方法 有参方法
lambda表达式

多态:不同的子类对象,调用相同的父类方法,产生不同的执行结果
   好处:多态是针对对象来说的,在不改变原有代码的前提下,完成不同的功能。不同的对象,调用相同的方法,达到不同的功能
# 定义一个父类
class Father():
    # 方法
    def methoda(self):
        pass

# 定义子类调用父类方法
class Sona(Father):
    def methoda(self):
        print("调用父类,定制化子类a")

class Sonb(Father):
    def methoda(self):
        print("调用父类,定制化子类b")

# 实例化
obja = Sona()
objb = Sonb()
listvar = [obja,objb]
for i in listvar:
    i.methoda()

# 执行结果
调用父类,定制化子类a
调用父类,定制化子类b

python对成员的保护分为两个等级

私有的: private
在本类内部可以访问,类的外部不可以访问.(python中 属性或者方法前面加上两个下划线__)
公有的: public
在本类的内部和外部都可以访问.
(了解)在其他高级语言当中,如java php c++等语言,有三个等级 private public protected
 私有成员的改名策略 [_类名__成员名]
对象的相关操作
  (1)实例化的对象访问公有成员属性和方法
  (2)实例化的对象动态添加公有成员属性和方法
  (3)实例化的对象删除公有成员属性和方法
类的相关操作
  (1)定义的类访问公有成员属性和方法
  (2)定义的类动态添加公有成员属性和方法
  (3)定义的类删除公有成员属性和方法
   
普通方法: 没有任何参数传递,只能类调用
绑定方法: 把默认传参的方法叫做绑定方法,绑定到对象(默认传对象),绑定到类(默认传类)
非绑定方法:静态方法(无需传任何参数,对象和类都能调用)
私有的:只能载类或者对象的结构中访问
公有的:可以载任何位置访问
受保护:可以载当前类或者对象 和子类或者子类对象中访问

类内   子类中   类外部
公有的: √       √       √  
私有的: √       X       X
受保护: √       √       X (python语言不支持)

编程语言的发行时间

1972    C
1983 C++(即带有类概念的C语言,更名于1983年7月)
1989 Python
1991 Visual Basic
1993 Ruby
1995 JavaScript
1995 PHP
1996 Java
2001 C#
2009 Go


多继承弊端

多继承的弊端会造成菱形继承这种情况,找不清调用顺序
super对象按照mro列表的顺序依次调用,解决菱形继承存在的问题

经典类:深度优先 (python2.x)
新式类:广度优先 (python3.x)

写多继承时,尽量避免造成不同类相同方法名的情况,提高代码质量 高内聚,低耦合
高内聚:一个模块只完成一个任务,专一性高
低耦合:模块与模块之间可以彼此独立不冲突,方便移植复用.

super调用父类方法

(1)super本身是一个类 super()是一个对象 用于调用父类的绑定方法
(2)super() 只应用在绑定方法中,默认自动传递self对象 (前提:super所在作用域存在self)
(3)super用途: 解决复杂的多继承调用顺序
class Father():
    attra = "aaa"
    def methoda():
        print("aaa")

class Mother():
    attrb = "bbb"
    def methodb(self):
        print("bbb")

class Son(Father,Mother):
    attra = "s-aaa"
    def methodb(self):
        print("s-bbb")
    def calla(self):
        print(Father.attra)
        Father.methoda()
    """
    self在调用时,本类有,优先调用自己,本类没有,调用父类
    """
    def callb(self):
        print(self.attrb)
        self.methodb()
    def callc(self):
        print(super().attra)
        super().methodb()

obj = Son()
obj.calla()
obj.callb()
obj.callc()

# 执行结果
aaa
aaa
bbb
s-bbb
aaa
bbb

魔术方法(特定时机自动触发)

__init__魔术方法(构造方法)
'''
触发时机:实例化对象,初始化的时候触发
功能:为对象添加成员
参数:参数不固定,至少一个self参数
返回值:无
'''
# 基本语法
class MyClass():
    def __init__(self):
        self.name = "Python"

obj = MyClass()
print(obj.name)

# 多个参数的__init__
class MyClass():
    def __init__(self,name):
        self.name = name

obj = MyClass("Python")
print(obj.name)

# 综合
class MyClass():
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def score(self):
        print("-->111")
    def course(self):
        print("-->222")
obj = MyClass("Python",18)
obj.score()
obj.course()

# 执行结果 
Python
Python
-->111
-->222 
__new__ 魔术方法
'''
触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
功能:控制对象的创建过程
参数:至少一个cls接受当前的类,其他根据情况决定
返回值:通常返回对象或None
'''
# 可以通过__new__来控制对象创建的过程
class MyClassa():
    attra = 'a'
obja = MyClassa()

class MyClassb():
    def __new__(cls, *args, **kwargs):
        print(cls) # 通过父类object 中的 __new__ 魔术方法 ,返回该类的对象,参数是类
        return obja # 可以返回别人的对象

objb = MyClassb()
print(objb)
print(obja.attra)

 

__new__和__init__之间的区别
"""
__new__ 创建对象
__init__ 初始化对象
__new__ 在 __init__触发之前
"""
class MyClass():
    def __new__(cls,name): # __new__和__init__形参和实参要匹配
        print(111)
        return object.__new__(cls) # 需要返回给__init__中参数
    def __init__(self,name):
        print(222)
        self.name = name

obj = MyClass("test")
print(obj.name)

# 升级
class MyClass():
    def __new__(cls, *args, **kwargs):
        print(111)
        return object.__new__(cls)
    def __init__(self,name,age,sex):
        print(222)
        self.name = name
        self.age = age
        self.sex = sex

obj = MyClass("A",22,"M")
print(obj.name)

# __init__只会初始化自己的对象
class MyClassa():
    def __new__(cls, *args, **kwargs):
        print(111)
        return obj
    def __init__(self):
        print(222)

obj = MyClassa()
print(obj)

# 执行结果
111
222
test
111
222
A
111
<__main__.MyClass object at 0x000002AD34F1E1D0> 
__del__ 魔术方法(析构方法)
触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候]
  功能:对象使用完毕后资源回收
参数:一个self接受对象
返回值:无
1.执行完毕触发析构方法
class Del():
    def __init__(self,name):
        self.name = name

    def splitline(self):
        print('-----')

    def __del__(self):
        print('析构方法触发')

obj = Del('析构方法测试')
# 1.执行完毕触发析构方法
print('--程序执行完毕--')

# 执行结果
--程序执行完毕--
析构方法触发

 2.所有对象被del后触发

class Del():
    def __init__(self,name):
        self.name = name

    def splitline(self):
        print('-----')

    def __del__(self):
        print('析构方法触发')

obj1 = Del('析构方法测试')
print('--程序执行完毕start--')
obj2 = obj1
del obj1
del obj2 # 此处不执行del则在最后触发析构方法
print('--程序执行完毕end--')

 3.例:文件读取操作(应用)

class ReadFile():
    def __new__(cls,filename):
        if os.path.exists(filename):
            return object.__new__(cls)
        return print("改文件不存在")
            
    def __init__(self,filename):
        self.fp = open(filename,mode="r",encoding="utf-8")
        
    def readcontent(self):
        res = self.fp.read()
        return res
        
    def __del__(self):
        self.fp.close()

obj = ReadFile("ceshi111.txt")
res = obj.readcontent()
print(res)
__call__ 魔术方法
'''
触发时机:把对象当作函数调用的时候自动触发
功能: 模拟函数化操作
参数: 参数不固定,至少一个self参数
返回值: 看需求
'''
# 统一调用
class MyClass():
    def __call__(self,task):
        print("统一调用{}".format(task))
        self.step1()
        self.step2()
        self.step3()
    def step1(self):
        print(111)
    def step2(self):
        print(222)
    def step3(self):
        print(333)

obj = MyClass()
obj('test')

# 执行结果
统一调用test
111
222
333 
__str__ 魔术方法
'''
触发时机: 使用print(对象)或者str(对象)的时候触发
功能:     查看对象
参数:     一个self接受当前对象
返回值:   必须返回字符串类型
'''
class MyClass():
    attra = 'attra'
    def __init__(self,name):
        self.name = name
    def info(self):
        return "测试属性{},测试名称{}".format(self.attra,self.name)
    def __str__(self):
        return self.info()

obj = MyClass("test")
# 打印时触发
print(obj) # 没有__str__时 :<__main__.MyClass object at 0x000001F1DEACA208>
print(obj) # 有__str__时 :测试属性attra,测试名称test 
__repr__ 魔术方法
'''
触发时机: 使用repr(对象)的时候触发
功能:     查看对象,与魔术方法__str__相似
参数:     一个self接受当前对象
返回值:   必须返回字符串类型
'''
class MyClass():
    attra = "attra"
    def __init__(self,name):
        self.name = name
    def info(self):
        return "属性{},名称{}".format(self.attra,self.name)
    def __repr__(self):
        return self.info()
    # 系统底层自动添加下面语句
    __str__ = __repr__

obj = MyClass("test")
print(obj)
print(str(obj)) 
----普通变量的基本操作,如果应用在对象上,也有相应的魔术方法

__bool__ 魔术方法
'''
触发时机:使用bool(对象)的时候自动触发
功能:强转对象
参数:一个self接受当前对象
返回值:必须是布尔类型
'''
class MyClass():
    def __bool__(self):
        return False 
        
# 实例化对象
obj = MyClass()        
res = bool(obj)
print(res)
'''
类似的还有如下等等(了解):
__complex__(self)     被complex强转对象时调用
__int__(self)         被int强转对象时调用
__float__(self)       被float强转对象时调用
...
...
'''
__add__ 魔术方法  (与之相关的__radd__ 反向加法)
'''
触发时机:使用对象进行运算相加的时候自动触发
功能:对象运算
参数:二个对象参数
返回值:运算后的值
'''
class MyClass():
    def __init__(self,num):
        self.num = num
        
    # 当对象在+加号的左侧时,自动触发;
    def __add__(self,other):
        return self.num * 2 + other
        
    # 当对象在+加号的右侧时,自动触发
    def __radd__(self,other):
        return self.num * 3 + other

a = MyClass(3)
# self 接收到 a ,other 接收到 1 self.num * 2 + 1 = 3 * 2 +1 = 7
res = a+1
print(res)


b = MyClass(5)
# 第一次参数永远接受的是对象,self接收的 b ,other 接受的是 2 => 5 * 3 + 2 => 17
res = 2 + b
print(res)

 


'''
类似的还有如下等等(了解):
__sub__(self, other)           定义减法的行为:-
__mul__(self, other)           定义乘法的行为:
__truediv__(self, other)       定义真除法的行为:/
...
...
'''
__len__ 魔术方法
'''
触发时机:使用len(对象)的时候自动触发
功能:用于检测对象中或者类中某个内容的个数
参数:一个self接受当前对象
返回值:必须返回整型
'''
# 计算类中的成员个数
class MyClass():
    pty1 = 1
    __pty2 = 2
    pty3 = 3
    
    def func1(self):
        pass
    
    def func2(self):
        pass
        
    def __func3(self):
        pass
        
    def __len__(self):
        dic = MyClass.__dict__
        """
        lst = []        
        for i in dic:
            if not( i.startswith("__") and i.endswith("__") ):
                lst.append(i)
        """
        lst = [i for i in dic if not( i.startswith("__") and i.endswith("__") )]
        return len(lst)

obj =  MyClass()
print(len(obj))
'''
类似的还有如下等等(了解):
__iter__(self)                 定义迭代容器中的元素的行为
__reversed__(self)             定义当被 reversed() 调用时的行为
__contains__(self, item)       定义当使用成员测试运算符(in 或 not in)时的行为
...
...
''' 


反射

 概念:通过字符串去操作类对象 或者 模块中的属性方法
 (1)类中的反射
hasattr() 检测对象/类是否有指定的成员
getattr() 获取对象/类成员的值
setattr() 设置对象/类成员的值
delattr() 删除对象/类成员的值

 (2)模块的反射
sys.modules 返回一个系统字典,字典的键是加载的所有模块

class Myclass():
    attra = '属性a'
    __attrb = "私有属性b"
    def methoda():
        print("普通方法")
    def methodb(self):
        print("绑定方法")
    def __methodc(self):
        print("私有方法")

obj = Myclass()
# 1.hasattr() 检测对象/类是否有指定的成员
print(hasattr(obj,"attra"))
print(hasattr(Myclass,'attra'))

# 2.getarrt() 获取对象/类成员的值
print(getattr(obj,"attra"))
getattr(obj,"methodb")()

# 3.setarrt() 设置对象/类成员的值
setattr(obj,"attrc","属性c")
print(obj.attrc)

# 4.delattr() 删除对象/类成员的值
delattr(obj,"attrc")

 

posted @ 2019-08-04 10:48  wangzihong  阅读(180)  评论(0编辑  收藏  举报