Python-面向对象

本文介绍了初识面向对象编程的概念,包括类的静态属性与动态方法、实例化过程、对象操作、类间关系(依赖、关联、组合与继承)、封装与多态,以及异常处理的基本原理。通过实例代码演示了如何创建类、使用依赖和关联关系,以及如何实现继承和多态。
摘要由CSDN通过智能技术生成

初识面向对象

class Human:
    '''
    此类主要是用于创建人类
    '''
    mind = '有思想' # 第一部分 静态属性 属性 静态变量 静态字段
    language = 'CN'
    dic = {}
    l1 = []
    def __init__(self,name,sex,age,hobby):
        self.n = name
        self.s = sex
        self.a = age
        self.h = hobby
        print(123)
        print(self)
    def work(self):  # 第二部分 方法 函数 动态属性
        print('人类需要工作')
    def tools(self):
        print('人类会使用工具')
        
类名操作静态属性
    1 类名.__dict__ 只能用来查询 不能增删改 查询类中所有的内容
    2 万能的点  可以进行增删改查操作 操作单个属性
类名操作动态方法
    前提 除了两个特殊方法 静态方法和类方法以外 一般不会通过类名操作一个类的方法

实例化对象发生了三件事:
    1 在内存中开辟一个对象空间
    2 自动执行类中 __init__ 方法 并将这个对象空间(内存地址)传递给__init__方法的第一个位置参数self
    3 在__init__方法中通过self给对象空间添加属性

对象操作对象空间属性
    1 对象查询对象中的所有属性 对象.__dict__
    2 对象查询对象中的单个属性 对象.属性 增删改查
对象查看类中的属性
    1 万能.
对象操作类中的方法
    1 万能.
    类中的方法一般都是通过对象执行的(除去类方法 静态方法) 并且对象执行这些方法都会自动将对象空间传给
    方法中的一个参数self
self是什么?
    self其实就是类中方法(函数)的第一个位置参数 只不过解释器会自动调用这个函数的对象传给self
    所以把类中的方法的第一个参数约定俗成设置为self 代表这个就是对象

1 添加对象属性
    对象的属性不仅可以在__init__ 中添加 还可以在类的其他方法或者类外添加
2 添加类的静态属性
    类外或者类内都可以添加

类与类的关系

    1 依赖
        将一个类的对象或者类名传给另一个类的方法中使用 我使用你 但是你不属于我
    2 关联
        两种事物必须是相互关联的 但是在某些特殊情况下是可以更改和更换的
        A需要B B也属于A 失去一个 另一个无法执行
    3 组合
        属于关联关系中的一种特列 组合关系比聚合还要亲密 
        将一个类的对象封装到另一个类的对象的属性中
    4 聚合
        属于关联关系中的一种特例 侧重点是xx和xx聚合成xxx 各自有各自的生命周期
    5 实现
    6 继承
依赖关系代码
class Elphant:
    def __init__(self,name):
        self.name = name
    def open(self,obj1):
        '''
        开门
        :return:
        '''
        print('大象开门 默念三声 开门')
        obj1.open_door()
    def close(self,obj1):
        '''
        关门
        :return:
        '''
        print('大象关门 默念三声 关门')
        obj1.close_door()
class Refrigerator:
    def open_door(self):
        print('冰箱门被打开了')
    def close_door(self):
        print('冰箱门被关上了')

elephant1 = Elphant('大象')
haier = Refrigerator()
elephant1.open(haier)
elephant1.close(haier)
关联关系代码
class Boy:
    def __init__(self,name,girlFriend=None):
        self.name = name
        self.girlFriend = girlFriend
    def have_a_dinner(self):
        if self.girlFriend:
            print(f'{self.name}{self.girlFriend.name}一起吃晚饭')
        else:
            print('单身狗 吃什么吃')
class Gril:
    def __init__(self,name):
        self.name = name
# b = Boy('alex')
# # b.have_a_dinner()
# b.girlFriend = 'xela'
# b.have_a_dinner()
组合关系代码
class Gamerole:
    def __init__(self,name,ad,hp):
        self.name = name
        self.ad = ad
        self.hp = hp
    def attack(self,p1):
        p1.hp -= self.ad
        print(f'{self.name}攻击{p1.name} {p1.name} 掉了 {self.ad}血 还剩{p1.hp}血')
    def equip_weapon(self,wea):
        self.wea = wea
class Weapon:
    def __init__(self,name,ad):
        self.name = name
        self.ad = ad
    def weapon_attack(self,p1,p2):
        p2.hp = p2.hp - self.ad - p1.ad
        print(f'{p1.name}利用{self.name}攻击了{p2.name} {p2.name}还剩{p2.hp}血')

barry = Gamerole('bb',10,200)
panky = Gamerole('pp',20,100)
pillow = Weapon('xx',2)
barry.equip_weapon(pillow)
barry.wea.weapon_attack(barry,panky)

封装 继承 多态

继承代码
class Animal(object):
    def __init__(self,name,sex,age):
        self.name = name
        self.sex = sex
        self.age = age
class Person(Animal):
    pass
class Cat(Animal):
    pass
class Dog(Animal):
    pass
继承的优点:
    1 增加了类的耦合性(耦合性不宜多 宜精
    2 减少了重复代码
    3 使得代码更加规范化 合理化

继承的分类
    Animal 父类 基类 超类
    Person Cat Dog 子类 派生类
继承可以分为单继承和多继承
Python3 中使用的使新式类 如果基类谁都不继承 那么这个类会默认继承object

子类同时执行父类方法以及子类方法

方式一 父类.func(对象,其他参数)
class Animal(object):
    type_name = '动物类'
    def __init__(self,name,sex,age):
        self.name = name
        self.sex = sex
        self.age = age
    def eat(self):
        print('吃东西')
class Person(Animal):
    def __init__(self,name,sex,age,mind):
        Animal.__init__(self,name,sex,age)
        self.mind = mind
    def eat(self):
        super().eat()
        print(f'{self.name} 吃饭')
p1 = Person('alex','male',24,'思想')
print(p1.__dict__)
方式二 super().func(参数)
class Animal(object):
    type_name = '动物类'
    def __init__(self,name,sex,age):
        self.name = name
        self.sex = sex
        self.age = age
    def eat(self):
        print('吃东西')
class Person(Animal):
    def __init__(self,name,sex,age,mind):
        # Animal.__init__(self,name,sex,age)
        super(Person, self).__init__(name,sex,age)
        self.mind = mind
    def eat(self):
        super(Person, self).eat()
        print(f'{self.name} 吃饭')
p1 = Person('alex','male',24,'思想')
# print(p1.__dict__)
p1.eat()

新式类多继承

新式类的多继承
    1 mro序列
        mro是一个有序列表 在类被创建时就计算出来
        计算公式 mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
        Child继承Base1 Base2
    2 表头和表尾
        表头: 列表的第一个元素
        表尾: 列表中表头以外的元素集合(可以为空
    3 列表之间的 +操作
        [A] + [B] = [A,B]
    merge操作示例
        如计算merge( [E,O], [C,E,F,O], [C] )
        有三个列表 :  ①      ②          ③
        
        1 merge不为空,取出第一个列表列表①的表头E,进行判断                              
           各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
        2 取出列表②的表头C,进行判断
           C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
           merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
        3 进行下一次新的merge操作 ......
    计算mro(A)方式
    mro(A) = mro( A(B,C) )
    
    原式= [A] + merge( mro(B),mro(C),[B,C] )
    
      mro(B) = mro( B(D,E) )
             = [B] + merge( mro(D), mro(E), [D,E] )  # 多继承
             = [B] + merge( [D,O] , [E,O] , [D,E] )  # 单继承mro(D(O))=[D,O]
             = [B,D] + merge( [O] , [E,O]  ,  [E] )  # 拿出并删除D
             = [B,D,E] + merge([O] ,  [O])
             = [B,D,E,O]
    
      mro(C) = mro( C(E,F) )
             = [C] + merge( mro(E), mro(F), [E,F] )
             = [C] + merge( [E,O] , [F,O] , [E,F] )
             = [C,E] + merge( [O] , [F,O]  ,  [F] )  # 跳过O,拿出并删除
             = [C,E,F] + merge([O] ,  [O])
             = [C,E,F,O]
    
    原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
        = [A,B] + merge( [D,E,O], [C,E,F,O],   [C])
        = [A,B,D] + merge( [E,O], [C,E,F,O],   [C])  # 跳过E
        = [A,B,D,C] + merge([E,O],  [E,F,O])
        = [A,B,D,C,E] + merge([O],    [F,O])  # 跳过O
        = [A,B,D,C,E,F] + merge([O],    [O])
        = [A,B,D,C,E,F,O]

封装和多态

封装
class Foo:
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
obj1 = Foo('a',24) # 将a和24封装给对象属性
obj2 = Foo('l',23)
# 通过对象直接调用 属性
print(obj1.name)
print(obj1.sex)
print(obj2.name)
print(obj2.sex)
多态
# 多态 同一个对象 多种形态 Python默认支持多态
# 鸭子类型
# python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
# 对于代码上的解释其实很简答:
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
# 这样的例子比比皆是:str  tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。

类的约束

类的约束
    1 提取父类 在父类中定义好方法 这个方法什么都不用干 只需要抛出一个异常 所有的子类必须重写这个方法 不然报错
    2 使用元类描述父类 在元类中给出一个抽象方法 这样子类就不得不给出抽象方法的具体实现 也可以起到约束效果
# 第一种 提取父类
class Payment:
    """此类什么都不做 只是指定一个标准 谁继承 必须要定义我里面的方法"""
    def pay(self,money):
        raise Exception("请实现Pay方法")
class QQpay(Payment):
    def pay(self,money):
        print(f'使用QQ支付{money}元')
class WeChatpay(Payment):
    def pay(self,money):
        print(f'使用微信支付{money}元')
class Alipay(Payment):
    def pay(self,money):
        print(f'使用支付宝支付{money}元')
def pay(obj,money):
    obj.pay(money)
a = Alipay()
b = QQpay()
c = WeChatpay()
pay(a,100)
pay(b,200)
pay(c,300)
# 第二种 引入抽象类
from abc import ABCMeta
from abc import abstractmethod
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass
class Alipay(Payment):
    def pay(self,money):
        print('使用支付宝支付了%s元'%money)

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付了%s元'%money)

class Wechatpay(Payment):
    # def pay(self,money):
    #     print('使用微信支付了%s元'%money)
    def recharge(self):pass
def pay(a,money):
    a.pay(money)

a = Alipay()
# a.pay(100)
pay(a,100)
q = QQpay()
pay(q,111)
w = Wechatpay()
pay(w,123) # 用到的时候才会报错

类的成员

# class obj:
#     company_name = 'alex'  # 静态变量(静态字段
#     __phone = '1234567' # 私有静态变量(私有静态字段
#     def __init__(self,name,sex): # 特殊方法
#         self.name = name # 对象属性(普通字段
#         self.__sex = sex # 私有对象属性(私有普通字段
#     def func1(self): # 普通方法
#         print('func1')
#     def __func2(self): # 私有方法
#         print('__func2')
#     @classmethod # 类方法
#     def class_func(cls):
#         '''
#         定义类方法 至少有有一个cls参数 类似于self
#         :return:
#         '''
#         print('类方法')
#     @staticmethod # 静态方法
#     def static_func():
#         '''
#         定义静态方法 没有默认参数
#         :return:
#         '''
#         print('静态方法')
#     @property # 属性
#     def prop(self):
#         print('属性')

类的成员
    公有成员 在任何地方都能访问
    私有成员 只有在类的内部才能访问
静态字段
    公有  类 类内部 派生类
    私有 类内部
普通字段
    公有 对象 类内部 派生类
    私有 类内部
方法
    公有 对象 类内部 派生类
    私有 类内部

四种方法

类方法
    1 实例方法 第一参数必须使实例对象self 用它来传递实例的属性和方法 也可以传递类的属性方法
        只能通过实例对象调用
    2 类方法 使用装饰器@classmethod 第一个参数必须是当前类对象 cls 用来传递类的属性方法(不可实例
        实例对象和类对象都可以调用
    3 静态方法 使用装饰器@staticmethod 参数随意 方法中不能使用类或者实例的任何属性以及方法
        实例对象或者类对象都可以调用
    4 双下方法 是特殊方法 __方法__ 
        不用的双下方法有着不同的出发方式
# 类方法
class Student:
    __num = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age
        Student.addNum()
    @classmethod
    def addNum(cls):
        cls.__num += 1
    @classmethod
    def getNum(cls):
        return cls.__num
# a = Student('太白金星', 18)
# b = Student('武sir', 36)
# c = Student('alex', 73)
# print(Student.getNum())

# 静态方法
import time
class TimeTest(object):
    def __init__(self,hour,minute,second):
        self.hour = hour
        self.minute = minute
        self.second = second
    @staticmethod
    def showTime():
        return time.strftime("%H:%M:%S", time.localtime())
# print(TimeTest.showTime())
# t = TimeTest(2,2,2)
# nowtime = t.showTime()
# print(nowtime)

# 属性
class Human:
    def __init__(self,name,weight,height):
        self.name = name
        self.weight = weight
        self.height = height
    @property
    def bmi(self):
        return self.weight/pow(self.height,2)
# p1 = Human('alex',90,1.80)
# print(p1.bmi)
为什么要使用property
    将一个类的函数定义成特性后 对象再去使用obj.name 根本无法察觉name是执行了一个函数然后进行了
    计算 这种特性的使用方式遵循了统一访问原则
class Goods(object):
    def __init__(self):
        self.original_price = 100
        self.discount = 0.8
    def get_price(self):
        new_price = self.original_price * self.discount
        return new_price
    def set_price(self,value):
        self.original_price = value
    def del_price(self):
        del self.original_price
    price = property(get_price,set_price,del_price)

isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象

issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类

这些可迭代的数据类型,list str tuple dict等 都是 Iterable的子类。

反射

反射: 通过字符串的形式操作对象相关的属性 Python中的一切事物都是对象(都可以使用反射
四个自省函数:
    1 对对象的反射
    2 对类的反射
    3 当前模块的反射
    4 其他模块的反射
反射的作用:
class User:
    def login(self):
        print('欢迎来到登录页面')
    def register(self):
        print('欢迎来到注册页面')
    def save(self):
        print('欢迎来到存储页面')
user = User()
while 1 :
    choose = input('>>>').strip()
    if hasattr(user,choose):
        func = getattr(user,choose)
        func()
    else:
        print('输入错误')

函数vs方法

# 1 通过打印函数(方法)名确定
def func():
    pass
print(func) # <function func at 0x000001AC0B97E280>
class A:
    def func(self):
        pass
print(A.func) # <function A.func at 0x00000222AD82F1F0>
obj = A()
print(obj.func) # <bound method A.func of <__main__.A object at 0x0000020124E6FFD0>>
# 2 通过types模块验证
from types import FunctionType
from types import MethodType
def func():
    pass
class A:
    def func(self):
        pass
obj = A()
print(isinstance(func,FunctionType))
print(isinstance(A.func,FunctionType))
print(isinstance(obj.func,FunctionType))
print(isinstance(obj.func,MethodType))
# 3 静态方法是函数
from types import FunctionType
from types import MethodType
class A:
    def func(self):
        pass
    @classmethod
    def func1(cls):
        pass
    @staticmethod
    def func2():
        pass
obj = A()
# 静态方式其实是函数
print(isinstance(A.func2,FunctionType)) # True
print(isinstance(obj.func2,FunctionType)) # True
print(isinstance(obj.func2,MethodType)) # False
# 4 函数与方法的区别
    1 函数是显示传递数据的 比如我们使用len()函数传递处理一些数据
    2 函数与对象无关
    3 方法中的数据是隐式传递的
    4 方法可以操作类的内部数据
    5 方法跟对象是关联的 s.strip() strip() 方法需要str调用
    6 Java中只有方法 C中只有函数 C++ 却决于是否在类中

双下方法

定义:
    双下方法是特殊方法,他是解释器提供的由双下划线加方法名加双下划线的具有
    特殊意义的方法 不常用 
调用: 
    不同的双下方法有不同的触发方式 __init__() 在实例化对象的时候自动调用
# __len__
# class B:
#     def __len__(self):
#         print(666)
# b = B()
# len(b) # len 一个对象就会触发 __len__方法。
# class A:
#     def __init__(self):
#         self.a = 1
#         self.b = 2
#     def __len__(self):
#         return len(self.__dict__)
# a = A()
# print(len(a))

# __hash__
# class A :
#     def __init__(self):
#         self.a = 1
#         self.b = 2
#     def __hash__(self):
#         return hash(str(self.a)+str(self.b))
# a = A()
# print(hash(a))

# __str__ 如果一个类定义了__str__方法 那么在打印对象时 默认输出该对象的返回值
# class A:
#     def __init__(self):
#         pass
#     def __str__(self):
#         return 'alex'
# a = A()
# print(a)
# print(f'{a}')

# __repr__ 如果一个类中定义了__repr__方法 那么在repr(对象)时 默认输出该方法的返回值
# class A:
#     def __init__(self):
#         pass
#     def __repr__(self):
#         return 'alex'
# a = A()
# print(repr(a))
# print(f'{a}')

# __call__ 对象后面加括号 触发执行
# 构造方法 __new__的执行是由创建对象触发的 对象=类名()
# __call__方法的执行是由括号加括号触发的 即 对象() 或者 类()()
# class Foo:
#     def __init__(self):
#         pass
#     def __call__(self, *args, **kwargs):
#         print('__call__')
# obj = Foo() # 执行 __init__()
# obj() # 执行 __call__()

# __eq__
# class A:
#     def __init__(self):
#         self.a = 1
#         self.b = 2
#     def __eq__(self, other):
#         if self.a == other.a and self.b == other.b:
#             return True
# a = A()
# b = A()
# print(a==b)

# __del__
# 析构方法 当对象在内存中被释放时 自动触发执行
# 此方法一般不用定义 Python是一门高级语言 程序员在使用时无需关心内存的
# 分配以及释放

# __new__
# class A:
#     def __init__(self):
#         self.x = 1
#         print('in the init function')
#     def __new__(cls, *args, **kwargs):
#         print('in the new function')
#         return object.__new__(A)
# a = A()
# print(a.x)

# __item__系列
# class Foo:
#     def __init__(self,name):
#         self.name = name
#     def __getitem__(self, item):
#         print(self.__dict__[item])
#     def __setitem__(self, key, value):
#         self.__dict__[key]= value
#     def __delitem__(self, key):
#         print('del obj[key]时 执行')
#         self.__dict__.pop(key)
#     def __delattr__(self, item):
#         print('del obj.key 时 执行')
#         self.__dict__.pop(item)
# f1 = Foo('alex')
# f1['age'] = 18
# f1['age1'] = 19
# del f1.age1
# del f1['age']
# f1['name'] = 'alex'
# print(f1.__dict__)

# 上下文管理器相关
# __enter__ __exit__
# 对一个类的对象进行 with as 操作不行
# class A:
#     def __init__(self,text):
#         self.text = text
# with A('alex') as  f1:
#     print(f1.text)

# class A:
#     def __init__(self,text):
#         self.text = text
#     def __enter__(self): # 开启上下文管理器对象时触发此方法
#         self.text = self.text + '你来啦'
#         return self # 将实例化对象返回给f1
#     def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发该方法
#         self.text = self.text + '你走啦'
# with A('alex') as f1:
#     print(f1.text)
# print(f1.text)

# 自定义文件管理器
# class Diycontextor:
#     def __init__(self,name,mode):
#         self.name = name
#         self.mode = mode
#     def __enter__(self):
#         print('Hi Enter here')
#         self.filehander = open(self.name,self.mode)
#         return self.filehander
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('Hi Exit here')
#         self.filehander.close()
# with Diycontextor('1 初识.py','r') as f:
#     for i in f:
#         print(i)

异常处理

怎样进行异常处理?
    1 if 判断式
        1 id判断式的异常处理只能针对某一段代码 对于不同的代码的相同类型的错误需要写重复的if处理
        2 在程序中频繁的写与本程序无关的代码 与异常处理有关的if 会是代码的可读性变得很差
        3 if是可以解决异常的 只是存在1 2 的问题
    2 Python异常处理的私人定制
        Python为每一种异常定制了一个类型 然后提供了一种特定的语法结构来进行异常处理
        1 基本语法
            try:
                被检测的代码块
            except 异常类型:
                try一旦检测异常 执行此位置的逻辑
        2 异常类只能用来处理指定的异常情况
        3 多分支
        4 万能异常 Exception
        5 其他结构
        6 主动触发异常
        7 自定义异常
        8 断言
    3 try exception vs if
        1 不牺牲可读性的前提下增强健壮性以及容错性
        2 把错误处理和真正的工作分开
        3 代码更加容易组织 更清晰 复杂的工作更容易实现
        4 更安全 不至于由于小错误使程序崩溃
    4 什么时候使用异常处理
        在一些异常无法预知的情况下 使用try except 其他逻辑错误应尽量修正
    5 常用异常
    		AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
            IOError 输入/输出异常;基本上是无法打开文件
            ImportError 无法引入模块或包;基本上是路径问题或名称错误
            IndentationError 语法错误(的子类) ;代码没有正确对齐
            IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
            KeyError 试图访问字典里不存在的键
            KeyboardInterrupt Ctrl+C被按下
            NameError 使用一个还未被赋予对象的变量
            SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
            TypeError 传入对象类型与要求的不符合
            UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
            导致你以为正在访问它
            ValueError 传入一个调用者不期望的值,即使值的类型是正确的
# 万能异常
s1 = 'alex'
try:
    int(s1)
except Exception as e:
    print(e)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值