Python基础(第八节)

我的未来我决定 提交于 2020-03-17 09:48:50

方法没有重载
1、在其他语言中,可以定义多个同名的方法
2、Python中方法的参数没有声明类型,参数的数量也可以由可变参数控制,因此Python中没有方法的重载
3、定义一个方法即可有多种调用方式,相当于实现了其他语言中的方法的重载
4、定义多个同名方法时,只有最后一个有效

方法的动态性
Python是动态语言,可以动态地为类添加新方法,或者动态地修改类的已有的方法

class Person:
    def work(self):
        print("努力工作!")

def play_game(a):
    print("{}在玩游戏".format(a))

def work2(n):    
    print("努力赚大钱,努力工作!")

Person.play = play_game
p = Person()
p.work()
p.play()    #解释器解释为Person.play(p)

Person.work = work2    #二者形参数量要对应
p.work()

运行结果为:
努力工作!
<__main__.Person object at 0x00000287ABF64CF8>在玩游戏
努力赚大钱,努力工作!

私有属性和私有方法
1、Python对于类的成员没有严格的访问控制权限,这与其他面向对象语言有区别
2、关于私有属性和私有方法有如下要点:
①通常我们约定,两个下划线开头的属性是私有的,其他为公共的
②类内部可以访问私有属性(方法)
③类外部不能直接访问私有属性(方法)
④类外部可以通过“__类名__私有属性(方法)名”访问

class Employee:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
    def __work(self):
        print("好好工作")
        print("年龄:{}".format(self.__age))    #类的内部可以调用

e = Employee("wyj",22)

print(e.name)
print(e._Employee__age)
e._Employee__work()

运行结果为:
wyj
22
好好工作
年龄:22

@property装饰器
可以将一个方法的调用变成“属性调用”

class Employee:
    @property
    def salary(self):
        print("salary runs ...")
        return 10000

emp1 = Employee()
print(emp1.salary)    #就像引用对象的一个元素
class Employee:
    def __init__(self,name,salary):
        self.__name = name
        self.__salary = salary    #设置私有属性,使在类外部不能修改

    def get_salary(self):    #返回薪水值
        return self.__salary

    def set_salary(self,salary):    #设置薪水值
        if 1000<salary<50000:
            self.__salary = salary
        else:
            print("录入错误!")

emp1 = Employee("wyj",10000)
print(emp1.get_salary())
emp1.set_salary(2000)
print(emp1.get_salary())

运行结果为:
10000
2000

用@property实现

class Employee:
    def __init__(self,name,salary):
        self.__name = name
        self.__salary = salary    #设置私有属性,使在类外部不能修改

    @property
    def salary(self):
        return self.__salary
    @salary.setter    #针对salary属性的设定
    def salary(self,salary):
        if 1000<salary<50000:
            self.__salary = salary
        else:
            print("录入错误!")

emp1 = Employee("wyj",10000)
print(emp1.salary)
emp1.salary = 20000
print(emp1.salary)

运行结果为:
10000
20000

面向对象三大特征

三大特征简介
1、封装(隐藏)
①隐藏对象的属性和实现细节,只对外暴露“相关调用方法”
②通过“私有属性、私有方法”实现“封装”,没有严格的语法级别的“访问控制符”,更多依靠程序员自觉实现
2、继承
①继承可以让子类具有父类的特性,提高了代码的重用性
②从设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或改进已有算法
3、多态
多态是指同一个方法的调用由于对象不同会产生不同的行为

继承
1、是实现代码复用的重要手段

2、语法格式:

class 子类类名(父类1[,父类2...]):
    类体

3、如果在类定义中没有指定父类,则默认父类是object类。也就是说,object是所有类的父类,里面定义了一些所有类共有的默认方法,比如:☆__new__()/4、定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下:
父类名.init(self,参数列表)

class Person:
    pass

class Student(Person):
    pass

print(Student.mro())

运行结果为:
[<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
class Person:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
    def say_hi(self):
        print("hi")

class Student(Person):
    def __init__(self,name,age,score):
        Person.__init__(self,name,age)    #必须显式地调用父类的初始化方法,不然解释器不会调用
        self.score = score


s = Student("wyj",22,60)
s.say_hi()
print(s._Person__age)

运行结果为:
hi
22

PS:父类中私有的方法和属性,子类继承了但是不能直接用,可以通过“__类名__私有属性(方法)名”访问

方法的重写
1、成员继承:子类继承了父类除构造方法之外的所有成员
2、方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类中的方法,也称为“重写”

class Person:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
    def say_age(self):
        print("我的年龄为:",self.__age)
    def say_introduce(self):
        print("我的名字是{}".format(self.name))
class Student(Person):
    def __init__(self,name,age,score):
        Person.__init__(self,name,age)    #必须显式地调用父类的初始化方法,不然解释器不会调用
        self.score = score
    def say_introduce(self):    #重写了父类的方法
        print("报告老师,我的名字是{}".format(self.name))

s = Student("wyj",22,60)
s.say_age()
s.say_introduce()

运行结果为:
我的年龄为: 22
报告老师,我的名字是wyj

查看类的继承层次结构
通过类的方法mro()或者类的属性__mro__可以输出这个类的继承层次结构

class A:
    pass
class B(A):
    pass
class C(B):
    pass
print(C.mro())

运行结果为:
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

object根类
object类是所有类的父类,因此有必要深入研究一下object类的结构

#object属性查看
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def say_age(self):
        print(self.name,"的年龄是",self.age)

obj = object()
print(dir(obj))    #查看object根类的所有属性

s2 = Person("wyj",22)
print(dir(s2))    #查看子类的所有属性

运行结果为:
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'say_age']

重写__str__()方法
1、str()是object中的一个方法用于返回一个对于对象的描述
2、对应的内置函数str()经常用于print()方法

class Person:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        return "名字是:{}".format(self.name)

p1 = Person("wyj")
print(p1)

运行结果为:
名字是:wyj

多重继承
1、Python支持多重继承,一个子类可以有多个“直接父类”
2、但是这样,类的整体层次会变得复杂,尽量避免使用

class A:
    def aa(self):
        print("aa")
class B:
    def bb(self):
        print("bb")

class C(A,B):
    def cc(self):
        print("cc")

c1 = C()
c1.aa()
c1.bb()
c1.cc()

运行结果为:
aa
bb
cc

mro()
1、通过mro()方法获得“类的层次顺序”
2、解释器的寻找方法是从左向右

class A:
    def say(self):
        print("aa")
class B:
    def say(self):
        print("bb")
class C(B,A):
    pass


c1 = C()
print(C.mro())
c1.say()

运行结果为:
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
bb

super()获得父类定义
super()代表父类的定义,不是父类对象

class A:
    def say(self):
        print("A:",self)

class B(A):
    def say(self):
        super().say()    #等同于 A.say()、最终找到的是A类
        print("B:",self)

B().say()

运行结果为:
A: <__main__.B object at 0x00000268A5DDADA0>
B <__main__.B object at 0x00000268A5DDADA0>

多态
1、多态是指同一方法调用由于对象不同可能会产生不同的行为
2、多态是方法的多态,属性没有多态
3、多态的存在有2个必要条件:继承、方法重写

class Man:
    def eat(self):
        print("吃饭啦")

class Chinese(Man):
    def eat(self):
        print("筷子")
class English(Man):
    def eat(self):
        print("叉子")

class Indian(Man):
    def eat(self):
        print("右手")

def manEat(m):
    if isinstance(m,Man):    #注意isinstance()的参数格式
        m.eat()
    else:
        print("不能吃饭")

manEat(Chinese())
manEat(English())
manEat(Indian)    #类后边要加括号

运行结果:
筷子
叉子
不能吃饭

特殊方法和运算符重载
Python的运算符实际上是通过调用对象的特殊方法实现的
例如:

a = 20
b = 30
c = a+b    #实际上本质是c = a.__add__(b)

重写运算符对应的方法,即实现了“运算符的重载”

class Person:
    def __init__(self,name):
        self.name = name
    def __add__(self,other):
        if isinstance(other,Person):
            return "{}---{}".format(self.name,other.name)
        else:
            print("不是同类方法,不能相加")

p1 = Person("wyj")
p2 = Person("JJ")
x = p1+p2
print(x)

运行结果为:
wyj---JJ

特殊属性
Python对象中包含了很多双下划线开始和结束的属性,这些都是特殊属性,有特殊用法

常见的特殊属性:
obj.dict:对象的属性字典
obj.class:对象所属的类
class.bases:类的基类元组(多继承)
class.base:类的基类
class.mro:类的层次结果
class.subclasses():子类列表

对象的浅拷贝与深拷贝
1、变量的赋值操作:只形成两个变量,实际还是指向同一个对象
2、浅拷贝:Python拷贝一般都是浅拷贝;拷贝时,对象包含的子对象内容不拷贝,因此,源对象和拷贝对象会引用同一个子对象
3、深拷贝:使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不同

import copy
class MobilePhone:
    def __init__(self,cpu,screen):
        self.cpu = cpu
        self.screen = screen
class CPU:
    def calculate(self):

        print("cpu对象:",self)
class  Screen:
    def show(self):
        print("显示")
        print("screen对象:",self)

#测试变量赋值
c1 = MobilePhone
c2 = c1    #变量赋值
print(c1)
print(c2)    #赋值后二者指向一个对象,地址相同

#测试浅拷贝
s1 = Screen()
m1 = MobilePhone(c1,s1)
m2 = copy.copy(m1)
print(m1,m1.cpu,m1.screen)
print(m2,m2.cpu,m2.screen)    #手机不同,其中的cpu和screen是一样的


#测试深拷贝
m3 = copy.deepcopy(m1)
print(m1,m1.cpu,m1.screen)
print(m3,m3.cpu,m3.screen)    #手机、cpu、screen都不一样

运行结果为:
<class '__main__.MobilePhone'>
<class '__main__.MobilePhone'>
<__main__.MobilePhone object at 0x000001D2F614B1D0> <class '__main__.MobilePhone'> <__main__.Screen object at 0x000001D2F32E7898>
<__main__.MobilePhone object at 0x000001D2F614B400> <class '__main__.MobilePhone'> <__main__.Screen object at 0x000001D2F32E7898>
<__main__.MobilePhone object at 0x000001D2F614B1D0> <class '__main__.MobilePhone'> <__main__.Screen object at 0x000001D2F32E7898>
<__main__.MobilePhone object at 0x000001D2F614B358> <class '__main__.MobilePhone'> <__main__.Screen object at 0x000001D2F614B2E8>

组合
1、组合与继承类似,使用组合也能实现一个类拥有另一个类的方法和属性
2、继承是“is”的关系,例如狗类继承动物类
3、组合是“has”的关系,例如手机拥有CPU

#使用继承实现代码的复用
class A1:
    def say_a1(self):
        print("a1")
class B1(A1):
    pass
b1 = B1()
b1.say_a1()
#使用组合实现代码的复用
class A2:
    def say_a2(self):
        print("a2")
class B2:
    def __init__(self,a):
        self.a = a
a2 = A2()
b2 = B2(a2)    #B2包含A2
b2.a.say_a2()    #调用了A2中的函数

运行结果为:
a1
a2

设计模式_工厂模式
1、设计模式是指在面临某一问题时的固定的做法
2、对于初学者最常用的两个模式是工厂模式和单例模式
3、工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制

class CarFactory:
    def create_car(self,brand):
        if brand == "奔驰":
            return Benz()
        elif brand == "宝马":
            return BWM()
        elif brand == "比亚迪":
            return BYD()
        else:
            return "未知品牌,无法创建"
class Benz:
    pass
class BMW:
    pass
class BYD:
    pass

factory = CarFactory()
c1 = factory.create_car("奔驰")
c2 = factory.create_car("比亚迪")
print(c1)
print(c2)

运行结果为:
<__main__.Benz object at 0x000002651A094CF8>
<__main__.BYD object at 0x000002651B0F57B8>

设计模式_单例模式
1、单例模式的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点
2、单例模式只生成一个实例对象,减少了对系统资源的开销

class MySingleton:

    __obj = None    #类属性
    __init_flag = True
    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:
            cls.__obj = object.__new__(cls)
        return cls.__obj

    def __init__(self,name):
        if MySingleton.__init_flag:    #为了只初始化一次
            print("init......")
            self.name = name
            MySingleton.__init_flag = False

a = MySingleton("aa")
b = MySingleton("bb")
print(a)
print(b)

运行结果为:
init......    #只初始化了一次
<__main__.MySingleton object at 0x000001B9B7A6ADD8>
<__main__.MySingleton object at 0x000001B9B7A6ADD8>    #两次引用的同一个地址
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!