Python系统学习-06

1.递归函数

  • 自己调用自己
  • 一般递归100多次,没有解决问题就不要用了

1.1用递归解决年龄问题

def age(n):
    if n == 1:    #终止条件
        return 23
    else:
        return age(n-1)+2   #通相式
print(age(4))

1.2二分查找

前提条件:列表必须是有序的不重复数字列表

l = [1,2,3,4,5]
def search(l, target,start=0,end=len(l)-1):
    if end >= start:
        mid_index = end-start // 2 + start
        if target > l[mid_index]:
            return search(l,target,start=mid_index+1,end=len(l)-1)
        elif target < l[mid_index]:
            return search(l,target,start=0,end=mid_index-1)
        elif target == l[mid_index]:
            return mid_index
        else:
            return 'no this value'
    else:
        return 'no this value'
print(search(l,3))

2.面向对象

实际工作中,python都是面向对象,写代码,或者面向对象+函数。

2.1面向对象编程:上帝式思维

class Person:   #class关键字,定义了一个类
    '''
    类里面所有内容
    '''
    animal = '高级动物'   #静态变量
    soup = '有思想'
    def __init__(self,name,eye):
        self.name = name  #属性
        self.eye = eye
        print(666)
    def work(self):   #动态变量,方法
        print('工作。。。。')

2.2什么是类?

  • “类”是具有相同属性和技能的一类事物
  • “对象”实例化的一个类,是类的具体体现
  • 类如何调用查看静态变量,动态变量\
  • 特殊的类属性
    类名.name# 类的名字(字符串)
    类名.doc# 类的文档字符串
    类名.base# 类的第一个父类(在讲继承时会讲)
    类名.bases# 类所有父类构成的元组(在讲继承时会讲)
    类名.dict# 类的字典属性
    类名.module# 类定义所在的模块
    类名.class# 实例对应的类(仅新式类中)

2.2.1类操作静态变量有两种方式:

1.类名.dict方法

print(Person.__dict__)  #打印所有静态变量,只能查看,不能增加,修改,删除
print(Person.__dict__['animal']) 

2.类名.变量名

print(Person.animal)
Person.animal = '低等动物' #可以增,删,改,查

2.2.2类操作方法有两种方式:

1类名.dict[方法名]()

print(Person.__dict__['work']())

3.2类名.方法名

Person.work(11)

2.3对象

  • 类名() #实例化一个对象
    p1 = Persion() #p1对象,实例化对象,类名()过程就叫做实例化。
    p2 = Person()

  • 只要创建一个类,里面的内容就已经加载到内存。
    p1 = Person() #init叫构造方法,创建对象时候自动调用。
    内部进行三步:
    1.实例化一个对象,在内存中产生一个对象空间。>
    2.自动执行init方法,并将这个空间对象传给self>
    3.通过构造方法里的代码给空间添加一些属性,并返回给对象。

2.4对象操作属性:

1.print(p1.dict)
2.对象.变量名
print(p1.name)
3.增删改查
p1.color = red
print(p1.color)

2.5对象操作方法有2种:

p1 = Person(‘Morgan’,’big’)
1. 对象.方法名()

p1.work()
print(p1)

2.类名.方法名(对象)

Person.work(111)

3.对象可以访问类的静态变量

print(p1.animal)

这里写图片描述

通过实例化对象查找属性,先从对象空间找,没有则通过类对象指针从类空间找。

3.组合

就是让不同的类混合并加入到其他类中,来增强功能和代码重用性

class Game_person:
    def __init__(self,nickname,sex,hp,ad):
        self.nickname = nickname
        self.sex = sex
        self.hp = hp
        self.ad = ad
    def attack(self,p):
        p.hp -= self.ad
        print('%s攻击了%s,%s还剩%s血量'%(self.nickname,p.nickname,p.nickname,p.hp))

    def weapon_attack(self,武器):
        self.武器 = 武器 #斧子对象

class Weapon:
    def __init__(self,name,ad):
        self.name=name
        self.ad=ad

    def fight(self,p1,p2):
        p2.hp -= self.ad
        print('%s使用%s打了%s%s血,%s还剩%s滴血'\
              %(p1.nickname,self.name,p2.nickname,self.ad,p2.nickname,p2.hp))

ts = Game_person('泰森','男',200,50)
barry = Game_person('太白','男',100,10)
fuzi = Weapon('斧子',60)

barry.weapon_attack(fuzi)
barry.武器.fight(barry,ts)

3.1面向对象三大特点

3.1.1封装

隐藏对象的属性和实现细节,仅对外提供公共访问方式。
【好处】
1. 将变化隔离;
2. 便于使用;
3. 提高复用性;
4. 提高安全性;
【封装原则】
1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。

3.1.1.1私有变量和私有方法

私有变量

  • 在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
  • 类中所有双下划线开头的名称如_x都会自动变形成:类名__x的形式:
class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #私有函数,变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.
#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

这种自动变形的特点:
1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
3.在子类定义的_x不会覆盖在父类定义的__x,因为子类中变形成了:子类名_x,而父类中变形成了:父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

私有方法

  • 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的,例如以下:
class A:
    def fa(self):
        print('from A')

    def test(self):
        self.fa()

class B(A):
    def fa(self):
        print('from B')

b = B()
b.test()     #输出:from B
====================================
#把fa定义成私有的,即__fa
====================================
class A:
    def __fa(self):
        print('from A')

    def test(self):
        self.__fa()

class B(A):
    def __fa(self):
        print('from B')

b = B()
b.test()    #输出:from A

3.1.2继承

  • 可以有效节省代码。
  • python3中,所有的类都默认继承object类,继承object类的类称为新式类。
  • python中,类分为两种:新式类,经典类。
  • 但是python3中只有新式类,python2中都有。
  • 新式类继承顺序:遵循广度优先(是一个算法,每个节点只走一次,用最少的次数。)
  • 经典类继承顺序:遵循深度优先

3.1.2.1继承:单继承,多继承。

重写父类方法

super().init

class FooParent:
    def __init__(self):
        self.parent = 'I \'m the parent.'
        print('Parent')

    def bar(self, message):
        print("%s from parent" % message)

class FooChild(FooParent):
    def __init__(self):
        super(FooChild, self).__init__()
        print('child')

    def bar(self, message):
        super(FooChild, self).bar(message)
        print('child bar function')
        print(self.parent)

if __name__ == '__main__':
    fooChild = FooChild()
    fooChild.bar('helloworld')
输出:
Parent
child
helloworld from parent
child bar function
I 'm the parent.

单继承:一个一个往上找。
多继承:先平级找,然后再下级中找。
这里写图片描述
Tips
类名.mro()查询继承顺序

经典类:深度优先
python2默认经典类,如果改成新式类就让类继承(object)
这里写图片描述
接口回去看

3.3多态

Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”。

class Animal:
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('Dog is running...')

class Cat(Animal):
    pass

class Tortoise(Animal):   #你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,
    # 任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
    def run(self):
        print('Tortoise is running slowly...')


def run_twice(animal):
    animal.run()
    animal.run()
dog = Dog()
cat = Cat()
run_twice(Tortoise())

多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:
对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:
对扩展开放:允许新增Animal子类;
对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。

3.4抽象类与接口类

继承有两种用途:

  • 继承基类的方法,并且做出自己的改变或者扩展(代码重用)
  • 声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

3.4.1接口继承

继承的第二种含义非常重要。它又叫“接口继承”。

借用abc模块来实现接口

class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass


class Wechatpay(Payment):
    def fuqian(self,money):
        print('微信支付了%s元'%money)

p = Wechatpay()    #TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
=============================================================
from abc import ABCMeta, abstractmethod

class IStream(metaclass=ABCMeta):
    @abstractmethod
    def read(self, maxbytes=-1):
        print('read1')

    @abstractmethod
    def write(self, data):
        print('write1')

class SocketStream(IStream):
    def read(self, maxbytes=-1):
        return 'read'

    def write(self, data):
        return 'write'
p = SocketStream()
print(p.read())           #输出:read

上面例子详细说明:
@abstractmethod 还能注解静态方法、类方法和 properties 。 你只需保证这个注解紧靠在函数定义前即可:

class A(metaclass=ABCMeta):
    @property
    @abstractmethod
    def name(self):
        pass

    @name.setter
    @abstractmethod
    def name(self, value):
        pass

    @classmethod
    @abstractmethod
    def method1(cls):
        pass

    @staticmethod
    @abstractmethod
    def method2():
        pass

4.call内置函数的作用和用法

Python中,一个特殊的魔术方法可以让类的实例的行为表现的像函数一样,你可以调用他们,将一个函数当做一个参数传到另外一个函数中等等。这是一个非常强大的特性让Python编程更加舒适甜美。 call(self, [args…])

class X(object):
    def __init__(self, a, b, range):
        self.a = a
        self.b = b
        self.range = range
    def __call__(self, a, b):
        self.a = a
        self.b = b
        print('__call__ with ({}, {})'.format(self.a, self.b))
    def __del__(self, a, b, range):
        del self.a
        del self.b
        del self.range

>>> xInstance = X(1, 2, 3)
>>> xInstance(1,2)
__call__ with (1, 2)

猜你喜欢

转载自blog.csdn.net/weixin_41765871/article/details/80630317