类: 通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。

class Person:
    a=10
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def attack(self):
        pass    

alex=Person(name,age)
=========================
名词:
类对象 --> Person
类变量 --> a = 10
类方法 --> attack()
类实例对象 --> alex
实例变量 --> name,age
类指针 --> alex对象的空间,里面有个指向Person类对象的内存地址
实例
=========================

定义一个类, 类名首字母大写
Person是一个类对象,指向类代码体的内存地址(地址存放类变量,类方法)

当类实例化一个对象时
1.创建对象,开辟一块新的内存空间
2.把空间传给self,调用__init__方法,创建示例变量(属性)
3.然后在把self(新开辟的内存地址)传给类实例化的对象(alex),
    所以self和alex指向同一块内存地址,他两是相同的。

总结:类的实例对象指向的是一块内存地址,里面存放对象的实例变量和类指针,
类指针指向的是:对应类的内存地址

属性的增删改查操作
  alex.name
  alex.age=1000
  del alex.age
  alex.gender="male"

面向对象的三大特性

面向对象继承

面向对象单继承
 一个实例对象查找某个变量一定严格按着如下顺序:
 先从实例的内存空间——>  实例对象的对应的类空间——>   当前类空间对应的父类空间
  
面向对象多重继承:
 python2经典类:深度优先
 python3新式类:c3算法优先

 面向对象基础 随笔

class A1: pass
class A2: pass
class A3: pass
class B1(A1,A2): pass
class B2(A2): pass
class B3(A2,A3): pass
class C1(B1): pass
class C2(B1,B2): pass
class C3(B2,B3): pass
class D(C1, C2, C3): pass

 规则:从左往右算,没有儿子的先被继承
 d > c1 > c2 > b1 > a1 > c3 > b2 > b3 > a2 > a3 > obj 
继承补充:
# 在继承的情况下为添加新的示例变量
# 使用super().__init__() 调用父类的__init__()
class Animal(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def run(self):
        print("animal run.....")
    def sleep(self):
        print('sleep....')
        
class Dog(Animal):
    def __init__(self,name,age,type):
        super().__init__(name, age)
        self.type=type
alex=Dog("alex",34,"金毛")
print(alex.type)
alex.run()

面向对象封装

封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:将变化隔离、便于使用、提高重用性、提高安全性
封装原则:将不需要对外提供的内容都隐藏起来、把属性都隐藏,提供公共方法对其访问。

使用封装有三大好处:
    1、良好的封装能够减少耦合。
    2、类内部的结构可以自由修改。 
    3、可以对成员进行更精确的控制。
    4、隐藏信息,实现细节。
私有化
    在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。         
    
    私有化变量    
    
        如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),
        只有内部可以访问,外部不能访问。
        如果外部需要获取实例变量,可以定义方法把实例变量return
        如果又要允许外部代码修改怎么办?可以再给类增加方法
        
        1 私有化变量: 保护数据   __变量:  私有变量
        2 可以对外提供读写接口
        def get_age():pass
        def set_age():pass
        接口可以实现更精准的控制
 
    class  Student(object):
        x=100
        def __init__(self,name,age):
            self.__name=name   # 私有属性  __变量
            self.__age=age     

        def get_age(self): # 获取实例变量
            # print("年龄:%s"%self.__age)
            return self.__age

        def set_age(self,new_age): # 允许外部代码修改,限制性的修改
            if isinstance(new_age,int) and (new_age>0 and new_age <100):
                self.__age=new_age                      ******# self.__age == self._Student__age = new_age
            else:   
                raise ValueError("年龄不符合条件!")
                #print("年龄不符合条件!")

    alex=Student("alex",34)
    
    #print(alex.__name)
    # 提供可读属性接口
    # print(alex.get_age())
    # # 提供可写属性接口
    # alex.set_age(580)
    # print(alex.get_age())

    注意点:
    1 外部可以控制私有属性,强烈不建议去这样做,不符合规范
    2 私有化不止适用于实例变量,也适用于类变量
    3 私有变量不能继承!
    4.单下划线、双下划线、头尾双下划线说明:
        __foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。
        _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问。(约定成俗,不限语法)
        __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。
      
    
    私有化方法
    
        在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
        
        #把fa定义成私有的,即__fa
        
        ###############################################################
        class A():
            def f(self):
                print('FROM A')
            def k(self):
                self.f()  

        class B(A):
            def f(self):
                print('FROM B')

        b=B()
        print(b.k())   # 结果为 FROM B

        1. B类继承A类,A类继承object类,获取__init__,生成一块空间给实例对象b
        2. b.k() 从b的空间找方法k,再到相应类对象B中找方法k,在从A类找到方法k,
        3. k(),执行了self.f()
        4. self.f() 先从b的空间里面找f(),再从B空间里面找f(),
        5. 找到后,打印'FROM B'

        ###############################################################

        class A():
            def __f(self):
                print('FROM A')
            def k(self):
                self.__f()

        class B(A):
            def __f(self):
                print('FROM B')

        b=B()
        print(b.k())  # 结果为 FROM A

        1. B类继承A类,A类继承object类,获取__init__,生成一块空间给实例对象b
        2. b.k() 从b的空间找方法k,再到相应类对象B中找方法k,在从A类找到方法k,
        3. k(),执行了self.f()
        4. self.f() == self._A__f(),先从b的空间里面找self._A__f(),再从B空间里面找self._A__f(),最后在A空间中找到self._A__f()
        5. 找到后,打印'FROM A'
什么是特性property
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现。
#####################################
# 使用property 可以向调用属性一样调用方法,不用加括号
# 一个静态属性property本质就是实现了get,set,delete三种方法

class Goods:

    def __init__(self):
        # 原价
        self.__original_price = 100
        # 折扣
        self.__discount = 0.8

    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.__original_price * self.__discount
        return new_price

    @price.setter
    def price(self, value):
        self.__original_price = value

    @price.deleter
    def price(self):
        del self.__original_price


obj = Goods()
print(obj.price)  # 获取商品价格
obj.price = 200   # 修改商品原价
print(obj.price)
del obj.price     # 删除商品原价
classmethod方法
class Classmethod_Demo():
    role = 'dog'

    @classmethod
    def func(cls):
        print(cls.role)

Classmethod_Demo.func()
实例对象.func()
#  classmethod 类方法  不需要用到self
#  这是一个规范,当方法只调用类变量时可以用,@classmethod 可以让其更方便看出这是一个类自己的方法
staticmethod方法
class Staticmethod_Demo():
    role = 'dog'

    @staticmethod
    def func():
        print("当普通方法用")

Staticmethod_Demo.func()
实例对象.func()
# staticmethod 静态方法 不需要用到self
# 把写在类里面的方法,当时一个函数用,

面向对象多态

基类(超类/父类)
派生类(子类) 
多态:一个基类的多个派生类呈现出来的多种状态。
归一化设计 (统一接口)
##################### 归一化设计 #####################

# 支付宝 微信 银行卡 nfc支付

class AliPay(object):
    def __init__(self,name,money):
        self.money=money
        self.name=name
    def pay(self):
        # 支付宝提供了一个网络上的联系渠道
        print('%s通过支付宝消费了%s元'%(self.name,self.money))

class WeChatPay(object):
    def __init__(self,name,money):
        self.money=money
        self.name=name
    def pay(self):
        # 微信提供了一个网络上的联系渠道
        print('%s通过微信消费了%s元'%(self.name,self.money))

def pay_func(pay_obj):
    pay_obj.pay()

alipay=AliPay("alex",100)
wechatpay=WeChatPay("yuan",200)

pay_func(alipay)
pay_func(wechatpay)
规范化方法
'''
支付宝 微信 银行卡 nfc支付
同事协作之间的代码规范问题
规定:Payment 就是一个规范类,这个类存在的意义不在于实现实际的功能,而是为了约束所有的子类必须实现pay的方法
Payment : 抽象类
    pay = Payment() # 抽象类: 不能实例化
    抽象类主要就是作为基类/父类,来约束子类中必须实现的某些方法
    抽象类的特点:
        必须在类定义的时候指定metaclass = ABCMeta
        必须在要约束的方法上方加上@abstractmethod方法
'''

from abc import ABCMeta,abstractmethod #(抽象方法)

class Payment(metaclass=ABCMeta):   # metaclass 元类  metaclass = ABCMeta表示Payment类是一个规范类
    def __init__(self,name,money):
        self.money=money
        self.name=name

    @abstractmethod      # @abstractmethod表示下面一行中的pay方法是一个必须在子类中实现的方法
    def pay(self,*args,**kwargs):
        pass

    @abstractmethod
    def back(self):
        pass

class AliPay(Payment):

    def pay(self):
        # 支付宝提供了一个网络上的联系渠道
        print('%s通过支付宝消费了%s元'%(self.name,self.money))

class WeChatPay(Payment):

    def pay(self):
        # 微信提供了一个网络上的联系渠道
        print('%s通过微信消费了%s元'%(self.name,self.money))

def pay_func(pay_obj):
    pay_obj.pay()

alipay=AliPay("alex",100)
wechatpay=WeChatPay("yuan",200)

pay_func(alipay)
pay_func(wechatpay)


当子类和父类都存在相同的pay()方法时,我们说,子类的pay()覆盖了父类的pay(),在代码运行的时候,总是会调用子类的pay()。这样,我们就获得了继承的另一个好处:多态。
多态的概念
就是类的不同状态
'''
你会发现,新增一个Payment的子类,不必对pay()做任何修改,实际上,任何依赖Payment作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

多态的好处就是,当我们需要传入AliPay、WeChatPay、ApplePay……时,我们只需要接收Payment类型就可以了,因为AliPay、WeChatPay、ApplePay……都
是Payment类型,然后,按照Payment类型进行操作即可。由于Payment类型有pay()方法,因此,传入的任意类型,只要是Payment类或者子类,就会自动调用实
际类型的pay()方法,这就是多态的意思:

对于一个变量,我们只需要知道它是Payment类型,无需确切地知道它的子类型,就可以放心地调用pay()方法,而具体调用的pay()方法是作用在AliPay、WeChatPay、
ApplePay哪个类对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Payment的子类时,只要确保pay()方
法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

      对扩展开放:允许新增Payment子类;
      对修改封闭:不需要修改依赖Payment类型的pay()等函数。
'''

鸭子类型

对于静态语言(例如Java)来说,如果需要传入Payment类型,则传入的对象必须是Payment类型或者它的子类,否则,将无法调用pay()方法。

对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个pay()方法就可以了:
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

弱类型语言都有鸭子类型

class CardPay(object):
    def __init__(self,name,money):
        self.money=money
        self.name=name
    def pay(self):
       print('%s通过银联卡支付消费了%s元'%(self.name,self.money))

def pay_func(pay_obj):
    pay_obj.pay()

cp=CardPay("alvin",1000)
pay_func(cp)
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。