2024年Python最全Python中面向对象(学习笔记)_面相对象程序设计python的笔记(2),华为公司面试视频

(1)Python所有方向的学习路线(新版)

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。

在这里插入图片描述

(2)Python学习视频

包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。

在这里插入图片描述

(3)100多个练手项目

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

class Person1(object):
    def func1(self):
        print("111")
        # 注意:在类中,对象函数之间相互调用,语法:self.函数
        self.func2()

    def func2(self):
        print("222")

    def show(self):
        print("show")

p1 = Person1()
p1.func1()
# 111
# 222
p1.show()
# show


2. 函数被私有化
class Person2(object):
    def func1(self):
        print("111")
        # 间接调用
        self.__show()

    def func2(self):
        print("222")

    def __show(self):
        print("show")

p2 = Person2()
p2.func2()  # 222
# p2.show()  # 报错
# p2.__show()  # 报错
# p2._Person2__show()  # show
p2.func1()
# 111
# 222


六、继承

如果两个或者两个以上的类具有相同的属性和方法,我们可以抽取一个类出来,在抽取出来的类中声明各个类公共的部分。被抽取出来的类称之为父类(超类、基类),两个或两个以上的类称之为子类 (派生类),他们之间的关系是 子类继承自父类 或者 父类派生了子类

单继承
1. 基本使用

子类之继承一个父类,被称为单继承。

语法:

class 子类类名(父类类名):
	类体


注意:object 是 Python 中所有类的根类。

class Person(object):
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def eat(self):
        print("eating")

    def __show(self):
        print("showing")



  1. 在子类中未定义构造函数,则创建子类对象默认调用父类中的构造函数
class Doctor(Person):
    pass

d = Doctor("张医生", 30, "male")

# 注意:子类对象可以直接调用父类中未被私有化的函数
d.eat()  # eating
d._Person__show()  # showing 不建议这样使用
d._Doctor__show()  # AttributeError: 'Doctor' object has no attribute '_Doctor__show'



  1. 在子类中定义构造函数,则创建子类对象调用的是子类中的构造函数
# 有参数时
class Teacher(Person):
    def __init__(self, height):
        self.height = height


t = Teacher(180)
print(t.height)  # 180
# print(t.name, t.age, t.gender)  # AttributeError: 'Teacher' object has no attribute 'name'
t.eat()  # eating

# 无参数时
class Lawyer(Person):
    def __init__(self):
        print("lawyer~~~init")

la = Lawyer()  # lawyer~~~init

# print(la.name)  # AttributeError: 'Lawyer' object has no attribute 'name'
la.eat()  # eating



  1. 在子类的构造函数中调用父类的构造函数
方式一:
    super(当前类, self).__init__(参数列表)

方式二:
    super().__init__(参数列表)

方式三:
    父类名.__init__(self, 参数列表)


注意:在单继承中,三种方式都可以使用;在多继承中,只能使用方式三

class Worker(Person):
    def __init__(self, name, age, gender, type):
        super(Worker, self).__init__(name, age, gender)
        self.type = type

    def work(self):
        print("working")

w = Worker("工作者", 10, "男", "行政")
print(w.type)  # 行政
print(w.name, w.age, w.gender)  # 工作者 10 男



2. 继承中的 __slots__ 属性
  • __slots__ 定义的属性仅对当前类的实例起作用,对继承的子类实例是不起作用
class Aniaml(object):
    __slots__ = ("name", "age")

class Cat(Aniaml):
    pass

c = Cat()
c.name = "tom"
c.age = 6
c.num = 8
print(c.name, c.age, c.num)  # tom 6 8


  • 如果子类本身也有 __slots__ 属性,子类的属性就是自身的 __slots__ 加上父类的 __slots__
class Aniaml(object):
    __slots__ = ("name", "age")

class Cat(Aniaml):
    __slots__ = ("num",)

c = Cat()
c.name = "tom"
c.age = 6
c.num = 8
# c.weight = 80  # 报错
print(c.name, c.age, c.num)  # tom 6 8



3. 继承中的类属性
class MyClass1(object):
    x = 10

class SubClass1(MyClass1):
    pass

class SubClass2(MyClass1):
    pass

print(MyClass1.x, SubClass1.x, SubClass2.x)  # 10 10 10

# 通过子类修改继承自父类的类属性,只会改变该子类继承的类属性
SubClass1.x = 20
print(MyClass1.x, SubClass1.x, SubClass2.x)  # 10 20 10

# 通过父类修改类属性,子类继承的类属性也改变
MyClass1.x = 30
print(MyClass1.x, SubClass1.x, SubClass2.x)  # 30 20 30

# 子类先修改继承的类属性,父类再修改类属性,将不会再对已经修改过的子类类属性做出改变
SubClass2.x = 50
MyClass1.x = 40
print(MyClass1.x, SubClass1.x, SubClass2.x)  # 40 20 50



4. 继承的特点
  1. 子类对象可以直接访问父类中未被私有化的属性和函数
  2. 父类的 __slots__ 属性对子类不起作用
  3. 父类对象不能访问子类中特有的属性和函数
5. 继承的优缺点

继承的优点:

  • 可以简化代码,减少冗余
  • 提高代码的可维护性
  • 是多态的前提

继承的缺点:

  • 在继承关系中,类与类之间的耦合性相对较高【如果修改父类,所有的子类都可能会发生改变】
多继承

子类可以拥有多个父类,并且具有所有父类的属性和方法。

1. 基本使用
class Father1(object):
    def __init__(self, num1):
        self.num1 = num1

    def func1(self):
        print("func1~~~111")

    def show(self):
        print("show~~~1111")

class Father2(object):
    def __init__(self, n1, n2):
        self.n1 = n1
        self.n2 = n2

    def func2(self):
        print("func2~~~222")

    def show(self):
        print("show~~~2222")



如果一个子类继承了多个父类,在没有书写构造函数的前提下,创建子类对象,默认调用的父类列表中的第一个父类中的构造函数。

class Child(Father2, Father1):
    pass

c1 = Child(2, 3)
c2 = Child(1)  # 报错



如果需要继承父类中的属性,则需要调用父类的构造函数。

class Child(Father1, Father2):
    def __init__(self, num1, n1, n2, a):
        Father1.__init__(self, num1)
        Father2.__init__(self, n1, n2)
        self.a = a


c = Child(3, 4, 6, 8)
print(c.a)  # 8
print(c.num1, c.n1, c.n2)  # 3 4 6
c.func1()  # func1~~~111
c.func2()  # func2~~~222



如果多个父类中出现了重名的函数,则子类对象调用时,调用的是父类列表中的第一个父类中的函数。

class Child(Father1, Father2):
    def __init__(self, num1, n1, n2, a):
        Father1.__init__(self, num1)
        Father2.__init__(self, n1, n2)
        self.a = a


c = Child(3, 4, 6, 8)
c.show()  # show~~~1111


2. 继承的 __mro__ 属性

Python中针对提供了一个内置属性 __mro__ 可以用来查看方法的搜索顺序。

mromethod resolution order 的简称,主要用于在多继承时判断方法属性的调用顺序。

  • 在调用方法时,按照 __mro__ 的输出结果从左至右的顺序查找。
  • 如果再当前类中找到方法,就直接执行,不再向下搜索。
  • 如果没有找到,就顺序查找下一个类中是否有对应的方法,如果找到,就直接执行,不再向下搜索。
  • 如果找到了最后一个类,依然没有找到方法,程序就会报错。
class A(object):
    def show(self):
        print("aaaa")

class B(A):
    def show(self):
        print("bbbb")

class C(A):
    def show(self):
        print("cccc")

class D(B, C):
    def show(self):
        print("dddd")

print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
d = D()
d.show()  # ddd



3. 多继承中 super 本质(继承树问题)

不是直接查找父类,而是根据调用节点的广度优先顺序执行的。

举个例子,创建A、B、C、D、E类,E类继承B、C、D类,B类继承A类,C类继承A类,D类继承A类,在每个方法中都调用 super().show() 方法,查看执行顺序。

class A(object):
    def show(self):
        print("aaaa")

class B(A):
    def show(self):
        print("enter~~~~bbb")
        super().show()
        print("退出~~~~~bbb")

class C(A):
    def show(self):
        print("enter~~~~ccc")
        super().show()
        print("退出~~~~~ccc")

class D(A):
    def show(self):
        print("enter~~~~ddd")
        super().show()
        print("退出~~~~~ddd")

class E(B, C, D):
    def show(self):
        print("enter~~~~eee")
        super().show()
        print("退出~~~~~eee")

print(E.mro())
# [<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
e = E()
e.show()
"""
enter~~~~eee
enter~~~~bbb
enter~~~~ccc
enter~~~~ddd
aaaa
退出~~~~~ddd
退出~~~~~ccc
退出~~~~~bbb
退出~~~~~eee

"""



另外一个例子,在C类中没有调用 super().show() 方法。

class A(object):
    def show(self):
        print("aaaa")

class B(A):
    def show(self):
        print("enter~~~~bbb")
        super().show()
        print("退出~~~~~bbb")

class C(A):
    def show(self):
        print("enter~~~~ccc")
        print("退出~~~~~ccc")

class D(A):
    def show(self):
        print("enter~~~~ddd")
        super().show()
        print("退出~~~~~ddd")

class E(B, C, D):
    def show(self):
        print("enter~~~~eee")
        super().show()
        print("退出~~~~~eee")

print(E.mro())
# [<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
e = E()
e.show()
"""
enter~~~~eee
enter~~~~bbb
enter~~~~ccc
退出~~~~~ccc
退出~~~~~bbb
退出~~~~~eee
"""



函数重写
1. 自定义函数
  • 父类中函数的实现不满足子类的需求
class Person(object):
    def func1(self):
        print("父类~~~func1")

    def show(self):
        print("父类~~~show")

class Student(Person):
    # 建议:重写的时候,子类中的函数的声明部分尽量和父类中的函数保持一致
    def func1(self):
        print("子类~~~~func1")
        return 100

stu1 = Student()
stu1.func1()  # 子类~~~~func1



  • 父类中函数的实现 部分 满足子类的需求
class Person(object):
    def func1(self):
        print("父类~~~func1")

    def show(self):
        print("父类~~~show")

class Student(Person):
    def func1(self):
        super().func1()
        print("子类~~~~func1")
        return 100

stu1 = Student()
stu1.func1()
"""
父类~~~func1
子类~~~~func1
"""


2. 系统函数
  1. __str____repr__

打印对象时,会调用对象的 __str__ 方法,默认会打印类名和对象的地址名;

__repr__ 方法 和 __str__ 方法功能类似,都是用来修改一个对象的默认打印内容。在打印一个对象时,如果没有重写 __str__ 方法,它会自动来查找 __repr__ 方法。如果这两个方法都没有,会直接打印这个对象的内存地址。如果两个方法都写了,选择 __str__ 方法。

class Check1(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

    def __str__(self):
        return f"name:{self.name},age:{self.age},score:{self.score}"

    __repr__ = __str__

# 如果只是打印一个对象,则重写__str__即可
c1 = Check1("aaa", 10, 199)
c2 = Check1("bbb", 20, 88)

# 如果将对象添加到序列中,为了能看到对象的值,则重写__str__和__repr__
list1 = [c1, c2]
print(list1)
for c in list1:
    print(c)



  1. __add__
print("hello" + "Python")
print("hello".__add__("Python"))


class Book(object):
    def __init__(self, num):
        self.num = num

    # 重写
    def __add__(self, other):
        # 参与相加的两个对象:self 和 other
        # Book + Book = Book
        return Book(self.num + other.num)

    # 重写__str__,保证最后返回的结果
    def __str__(self):
        return f"{self.num}"

b1 = Book(100)
b2 = Book(400)
b3 = b1 + b2
print(b3)  # 500
print(b1.__add__(b2))  # 500



  1. __eq__

__eq__ 方法如果不重写,默认比较依然是内存地址

class Student(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age


s1 = Student('lucy', 18)
s2 = Student('lucy', 18)
s3 = Student('lucy', 20)

# s1 == s2本质是调用 p1.__eq__(p2),获取这个方法的返回结果
print(s1 == s2)  # True 
print(s1 == s3)  # False




  1. 比较运算符相关魔法方法
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):  # 等于
        return self.name == other.name and self.age == other.age

    def __ne__(self, other):  # 不等于
        return self.age != other.age

    def __lt__(self, other):  # 小于
        return self.age < other.age
        # return self.age < other

    def __gt__(self, other):  # 大于
        return self.age > other.age

    def __le__(self, other):  # 小于等于
        return self.age <= other.age

    def __ge__(self, other):  # 大于等于
        return self.age >= other.age


s1 = Student('zhangsan', 18)
s2 = Student('zhangsan', 18)
s3 = Student('lisi', 20)
print(s1 == s2)  # True
print(s1 != s2)  # False
print(s1 < s2)  # False
# print(s1 < 6)  # False
print(s1 > s2)  # False
print(s1 <= s2)  # True
print(s1 >= s2)  # True




  1. 算术运算符相关魔法方法
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __add__(self, other):
        return self.age + other

    def __sub__(self, other):
        return self.age - other

    def __mul__(self, other):
        return self.age * other

    def __truediv__(self, other):
        return self.age / other

    def __mod__(self, other):
        return self.age % other

    def __pow__(self, power, modulo=None):
        return self.age ** power


s = Student('zhangsan', 18)
print(s + 1)  # 19
print(s - 2)  # 16
print(s * 2)  # 36
print(s / 5)  # 3.6
print(s % 5)  # 3
print(s ** 2)  # 324




  1. 类型转换相关魔法方法
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __int__(self):
        return self.age

    def __float__(self):
        return self.age * 1.0

    def __str__(self):
        return self.name

    def __bool__(self):
        return self.age > 18

s = Student('zhangsan', 18)
print(int(s))  # 18
print(float(s))  # 18.0
print(str(s))  # zhangsan
print(bool(s))  # False




七、多态

不同的子类调用相同的父类方法,产生不同的执行结果,可以增加代码的外部灵活度。多态是以继承和重写父类方法为前提的,它是一种调用方法的技巧,不会影响到类的内部设计。

场景
  • 提供三个类:缉毒犬、军犬、人
  • 缉毒犬(追查毒品),军犬(攻击敌人),人(让小狗干活)
  • 设计类来完成功能
实现
class ArmyDog(object):

    def bite_enemy(self):
        print('追击敌人')

class DrugDog(object):

    def track_drug(self):
        print('追查毒品')

class Person(object):

    def work_with_army(self, dog):
        dog.bite_enemy()

    def work_with_drug(self, dog):
        dog.track_drug()

ad = ArmyDog()
dd = DrugDog()

p = Person()
p.work_with_army(ad)
p.work_with_drug(dd)



思考:这段代码设是否有问题?

新增需求:多了一个犬种,需要在Person类里新建一个方法,让这个方法操作新的狗。

class XiaoTianDog(object):

    def eat_moon(self):
        print('哮天犬把月亮吃了')

class Person(object):

    def work_with_xiaotian(self, dog):  # 添加方法
        dog.eat_moon()



Person 类总是不断的添加新的功能,每次都需要改动Person类的源码,程序的扩展性太差了!

最好是提供一个父类 Dog,具备 work 的功能,其他小狗继承它,这样只要是小狗类,则行为被统一起来了,我们人类完全可以保证,只要是小狗的子类,找它干活肯定不会有问题。这样人只要一个方法就能逗任意种类的狗玩,哪怕是添加新的狗,人的类都不需要修改。

最终实现
class Dog(object):

    def work(self):  # 父类提供统一的方法,哪怕是空方法
        pass

class ArmyDog(Dog):  # 继承 Dog

    def work(self):  # 子类重写方法,并且处理自己的行为
        print('追击敌人')

class DrugDog(Dog):

    def work(self):
        print('追查毒品')

class XiaoTianDog(Dog):

    def work(self):
        print('哮天犬把月亮吃了')

class Person(object):

    def work_with_dog(self, dog):
        dog.work()  # 使用小狗可以根据对象的不同而产生不同的运行效果, 保障了代码的稳定性

# 子类对象可以当作父类来使用
dog = Dog()
ad = ArmyDog()
dd = DrugDog()
xtd = XiaoTianDog()

p = Person()

# 同一个方法,只要是 Dog 的子类就可以传递,提供了代码的灵活性
# 并且传递不同对象,最终 work_with_dog 产生了不同的执行效果
p.work_with_dog(dog)
p.work_with_dog(ad)
p.work_with_dog(dd)
p.work_with_dog(xtd)



Person 类中只需要调用 Dog 对象 work() 方法,而不关心具体是 什么狗

work() 方法是在 Dog 父类中定义的,子类重写并处理不同方式的实现

在程序执行时,传入不同的 Dog 对象作为实参,就会产生不同的执行效果

多态总结
  • 定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果
  • 好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化!
  • 实现步骤:
    • 定义父类,并提供公共方法
    • 定义子类,并重写父类方法
    • 传递子类对象给调用者,可以看到不同子类执行效果不同
八、其他
对象的内置属性
1. __slots__

限制对象属性的动态绑定。

2. __doc__

表示类的描述信息,获取类中的文档注释(多行注释)。

class Check(object):
    """
    功能:实现校验的功能
    参数
    返回值
    """

    def show(self):
        pass

print(Check.__doc__)
c = Check()
print(c.__doc__)


3. __dict__

获取类或者对象的信息【属性和方法】,返回字典。

class MyClass(object):
    num = 10

    def __init__(self, m):
        self.m = m

    def show(self):
        pass

    @classmethod
    def func(cls):
        pass

    @staticmethod
    def test():
        pass

# 类名:类属性,构造函数,实例函数,类函数,静态函数
print(MyClass.__dict__)
m = MyClass(5)

# 对象:实例属性
print(m.__dict__)



总结:

  • 内置的数据类型没有__dict__属性
  • 每个类有自己的__dict__属性,就算存着继承关系,父类的__dict__ 并不会影响子类的__dict__
  • 对象也有自己的__dict__属性,存储实例属性信息
4. __module__

获取当前操作的对象在哪个模块。

如果被操作的对象在当前模块,则获取的结果为__main__ ,如果被操作的对象在其他模块,则获取的结果为 模块名

class MyClass(object):
    pass

m = MyClass()
print(m.__module__)  # __main__


from random import randint

print(randint.__module__)  # random


5. __class__

类似于type(xxx) ,返回当前对象的类型。

class MyClass(object):
    pass

m = MyClass()
print(m.__class__)  # <class '__main__.MyClass'>
print(type(m))  # <class '__main__.MyClass'>



print('abc'.__class__)  # <class 'str'>
print(type('abc'))  # <class 'str'>


对象的内置函数
1. id()

获取一个对象在内存中的地址

a = 99
print(id(a))
print(type(id(a)))

# 比较两个对象的地址是否相同
a = 19
b = 10
print(id(a) == id(b))
print(a is b)



2. type()
  • 获取对象的类型
print(type("abc"))  # <class 'str'>


  • type的返回值可以直接比较是否相等
print(type(20) == type(40))  # True
print(type(20) == int)  # True
print(type(type(10)))  # <class 'type'>


class Person(object):
    pass

p = Person()
print(type(p))  # <class '__main__.Person'>
print(type(Person))  # <class 'type'>



  • 借助 types 模块,可以判断函数的类型
import types

print(type(lambda x: x) == types.LambdaType)
print(type((x for x in range(10))) == types.GeneratorType)
print(type(abs) == types.BuiltinFunctionType)



3. isinstance()

判断一个实例对象是否是由某一个类(或者它的子类)实例化创建出来的。

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Student(Person):
    def __init__(self, name, age, score):
        super(Student, self).__init__(name, age)
        self.score = score


p = Person('tony', 18)
s = Student('jack', 20, 90)

print(isinstance(p, Person))  # True.对象p是由Person类创建出来的
print(isinstance(s, Person))  # True.对象s是有Person类的子类创建出来的



print(isinstance(18, int))
print(isinstance([1, 2, 3], (list, tuple, dict)))
print(isinstance(33, (str, int)))


4. dir()

查看对象内的所有的属性和方法。

# 获得当前模块的属性
print(dir())


print(dir("abcd"))


5. issubclass(子类, 父类)

判断两个类之间的继承关系。

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Student(Person):
    def __init__(self, name, age, score):
        super(Student, self).__init__(name, age)
        self.score = score

class Dog(object):
    def __init__(self, name, color):
        self.name = name
        self.color = color

print(issubclass(Student, Person))  # True
print(issubclass(Dog, Person))  # False



类方法
  • 形参列表的第一个参数为cls ,表示当前类;
  • 使用 @classmethod 装饰器来装饰。

使用场景

  • 当方法中 需要使用类对象 (如访问私有类属性等)时,定义类方法
  • 类方法一般和类属性配合使用
class Person(object):
    # 类属性
    __num = 3

    # 构造函数
    def __init__(self, name, age):
        # 实例属性
        self.name = name
        self.age = age

    # 实例函数:形参列表的第一个参数必须为self,表示当前对象
    def show(self):
        print("show", self)
        print("showing")

    @classmethod
    def func1(cls):
        # cls就相当于是Person,所以可以通过cls创建对象
        c = cls("jack", 18)
        # 在类方法中调用 实例函数,必须先通过cls创建对象,然后再调用
        c.show()
        return cls.__num


p = Person("tom", 5)

# 类函数可以通过类名或者对象调用
print(p.func1())
print(Person.func1())
"""
show <__main__.Person object at 0x000001D1865BB308>
showing
3
"""



静态方法
  • 需要通过装饰器 @staticmethod 来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)
  • 静态方法 也能够通过 实例对象类对象 去访问。

使用场景

  • 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
  • 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
class Dog(object):
    type = "狗"

    def __init__(self):
        name = None

    # 静态方法    
    @staticmethod
    def introduce():  # 静态方法不会自动传递实例对象和类对象
        print("工作赚钱了养只金毛")

dog1 = Dog()
Dog.introduce()  # 可以用 实例对象 来调用 静态方法
dog1.introduce()  # 可以用 类对象 来调用 静态方法



注意点

类中定义了同名的方法时,调用方法会执行最后定义的方法。

class Dog:

    def demo_method(self):
        print("对象方法")

    @classmethod
    def demo_method(cls):
        print("类方法")

    @staticmethod
    def demo_method():  # 被最后定义
        print("静态方法")

dog1 = Dog()
Dog.demo_method()  # 结果: 静态方法
dog1.demo_method()  # 结果: 静态方法



九、单例设计模式
概念

程序运行过程中,确保某一个类只有一个实例【对象】,不管在哪个模块获取这个类的对象,获取到的都是同一个对象。该类有一个静态方法,向整个工程提供这个实例,例如:一个国家只有一个主席,不管他在哪里。

单例设计模式的核心:一个类有且仅有一个实例,并且这个实例需要应用于整个程序中,该类被称为单例类。

应用场景

应用程序中描述当前使用用户对应的类,当前用户对于该应用程序的操作而言是唯一的,所以一般将该对象设计为单例。

实际应用:数据库连接池操作,应用程序中多处地方连接到数据库,连接数据库时的连接池只需一个就行,没有必要在每个地方都创建一个新的连接池,这种也是浪费资源 ,解决方案也是单例。

实现
1. 模块
class Person(object):
    def __init__(self, name):
        self.name = name

    def dance(self):
        print(self.name + "dancing")

p = Person("小彩旗")
print(id(p))



from Day15.singleton.person import p

# 依据:Python中的模块本身是一种单例,因为只有当第一次import的时候才会去加载源文件【.pyc】,
print(p)
print(id(p))



2. __new__
class Person(object):
    # 定义类属性,用于存储当前类可以创建的唯一的实例
    __instance = None

    # 只要执行创建对象的语法,都会调用__new__,也都会将__new__的返回值传递给__init__的self,进行属性的赋值
    def __new__(cls, *args, **kwargs):
        # 思路:判断__instance 值是否为None,如果为None,则赋值【当前实例】,如果不为None,则直接返回
        if not cls.__instance:
            cls.__instance = super(Person, cls).__new__(cls)
        return cls.__instance

    def __init__(self, name, age):
        self.name = name
        self.age = age


p1 = Person("jack", 10)  # 0x67345674   第一次肯定会创建
print(p1)
p2 = Person("aaa", 6)  # 0x67345674      第二次则表示获取,但是会将属性值重新赋值
print(p2)
print(id(p1) == id(p2))  # True
print(p1 is p2)  # True

print(p1.name, p2.name)  # aaa aaa



3. 装饰器

装饰器装饰函数

def outter(func):
    print("ouuter~~~~")

    def inner():
        print("inner~~~")
        func()

    return inner

@outter
def test():
    print("test")

test()



装饰器装饰类

def outter(cls):
    print("outter~~~222")

    def inner():
        print("inner~~~~222")

        return cls()

    return inner

@outter
class Check(object):
    pass

# 只要上述代码,会打印outter~~~222
c = Check()
print(c)
c1 = Check()
print(c1)

"""
outter~~~222
inner~~~~222
<__main__.Check object at 0x000002422E4E8B88>
inner~~~~222
<__main__.Check object at 0x000002422E4E5788>
"""


def outter(cls):
    print("outter~~~222")

    def inner(*args, **kwargs):
        print("inner~~~~222")

        return cls(*args, **kwargs)

    return inner

@outter
class Check(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age


c = Check("jack", 10)
print(c)
print(c.name, c.age)
"""
outter~~~222
inner~~~~222
<__main__.Check object at 0x0000020A220CB2C8>
jack 10
"""



实现单例

def singleton(cls):
    # 定义一个变量,用于存储被装饰的类唯一的实例
    instance = None

    # 建议:函数命名为getinstance/currentinstance/defaultinstance
    def getinstance(*args, **kwargs):
        # 思路:判断instance值是否为None,如果为None,则赋值【当前实例】,如果不为None,则直接返回
        # nonlocal  instance声明局部作用域中的instance不是定义了新的变量,而是来自于函数作用域的instance
        nonlocal instance
        if not instance:
            # cls()会自动调用原类的构造函数【__init__】
            instance = cls(*args, **kwargs)
        # 返回被装饰类唯一的实例
        return instance

    return getinstance

@singleton
class Person(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score


p1 = Person("zhangsan", 10, 99)
p2 = Person("lisi", 18, 100)
print(p1 is p2)  # True
print(id(p1) == id(p2))  # True

print(p1.name, p2.name)  # zhangsan zhangsan



def singleton(cls):
    instance_dict = {}

    def getinstance(*args, **kwargs):
        # 思路:判断instance_dict是否为空,如果为空,以被装饰的类作为key,唯一的实例作为value
        # 如果不为空,则直接返回value
        if not instance_dict:
            instance_dict[cls] = cls(*args, **kwargs)
        return instance_dict[cls]

    return getinstance

@singleton
class Person(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score


p1 = Person("zhangsan", 10, 99)
p2 = Person("lisi", 18, 100)
print(p1 is p2)  # True
print(id(p1) == id(p2))  # True

print(p1.name, p2.name)  # zhangsan zhangsan



类函数

# 思路:在当前类中创建一个实例,在类的外面只需要获取
class Person(object):
    # 定义一个类私有属性,保存当前类唯一的实例
    __instance = None

    @classmethod
    def getinstance(cls, *args, **keargs):
        # 创建对象
        if not cls.__instance:
            cls.__instance = cls(*args, **keargs)
        return cls.__instance

    def __init__(self, name, age):
        self.name = name


如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费**学习**大礼包,带大家一起学习,给大家剖析Python兼职、就业行情前景的这些事儿。



### 一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。



![](https://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)

### 二、学习软件



工欲善其必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。



![](https://img-blog.csdnimg.cn/img_convert/8c4513c1a906b72cbf93031e6781512b.png)



### 三、全套PDF电子书

书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。

![](https://img-blog.csdnimg.cn/img_convert/eec417a3d4d977b313558a11d3c13e43.png)



### 四、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。



![](https://img-blog.csdnimg.cn/img_convert/ec690501ea1dbe2cb209cbf4013c2477.png)  

![](https://img-blog.csdnimg.cn/img_convert/3eaeaa6747419c9d86c72e0d10d0a6a2.png)



### 四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。



![](https://img-blog.csdnimg.cn/img_convert/252731a671c1fb70aad5355a2c5eeff0.png)



### 五、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

![](https://img-blog.csdnimg.cn/img_convert/6c361282296f86381401c05e862fe4e9.png)

成为一个Python程序员专家或许需要花费数年时间,但是打下坚实的基础只要几周就可以,如果你按照我提供的学习路线以及资料有意识地去实践,你就有很大可能成功!
最后祝你好运!!!




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618317507)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值