Skip to content

面向对象知识点内容汇总

1. 如何在Python中创建类
python
'''
class 类名:
    代码块
'''

    
# Python3示例代码
class Test:
    # 构造函数
    def __init__(self):
        pass
    
    # 实例方法
    def info(self):
        pass
2. 类与对象
  1. 类相当于一个代码模板,可以使用这个模板生产出多个"产品",这个"产品"在Python中为实例对象,一句话总结:一个类可以创建多个实例对象。
  1. 对象是类创建出来的,可以理解为一个具体事物的存在,通过这个对象我们可以使用在类中创建出来的属性与方法。
python
class Person:
    # 使用构造方法创建实例属性
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
        
    # 创建实例方法
    def info(self):
        return f'姓名: {self.name}, 性别: {self.gender}'

# 使用类创建一个实例对象 并使用实例对象使用类中的属性与方法
person = Person('Tom', '女')

# 打印属性
print(person.name)
print(person.gender)

# 打印实例方法的返回值
print(person.info())
3. 实例属性与实例方法

实例方法与普通的函数类似,不同点是实例方法是在类中定义的,并且方法中的第一个形式参数为self

python
class Person:
    # 请注意当前这个方法的第一个参数为self
    def info(self):
        return '这是一个返回个人信息的实例方法...'
    
# 调用实例方法必须先要创建一个实例对象
person = Person()
print(person.info())

实例属性与之前学习的变量类似,可以存储数据。但是实例属性只能被实例对象调用。定义实例属性的方式有多种,一般使用__init__方法创建实例属性。

python
class Person:
    pass

# 1.使用实例对象创建实例属性
person = Person()

person.name = 'Tom'
person.age = 18
person.gender = '女'

print(person.name, person.age, person.gender)
python
# 2. 使用普通实例方法创建属性
class Person:
    def create_attr(self):
        # 定义实例属性
        self.name = 'Tom'
        self.age = 18
        self.gender = '女'

# 当前定义方式必须创建实例对象后调用实例方法创建实例属性
person = Person()
person.create_attr()
print(person.name, person.age, person.gender)
python
# 3. 使用构造函数创建实例属性: 最常用的一种创建实例属性的方式
class Person:
    def __init__(self):
        self.name = 'Tom'
        self.age = 18
        self.gender = '女'

        
person = Person()
print(person.name, person.age, person.gender)

总结:

  1. 使用类创建的对象是实例对象,类创建对象的过程为类的实例化
  2. 如果一个类中的方法的第一个参数为self,那么这个方法就是实例方法
  3. 所谓的实例属性其实就是一个变量,用来存储数据。实例属性只能被实例对象访问。
4. 类中的self

在讲解self这个参数之前,我们必须要知道类实例化执行的大致过程!!!

  1. 在内存中开辟一个空间。
  2. 将类产出的实例对象存储在这个独立的空间中。

注意:类的代码与实例对象不在一个内存空间中,实例对象所占用的空间只是存储了实例属性等一些数据而已。

当我们了解到在实例化的过程中产出的实例对象保存在一个单独的内存空间之后,那么这个self其实就是指向了这个单独的实例对象的内存空间。

通过这一个特性,我们就可以使用self这个参数去访问类中的属性与方法了。一句话总结:类中的self指的是这个类的实例对象本身。

python
class Person:
    def __init__(self):
        self.name = 'Tom'
        
    def info(self):
        # 使用self访问实例属性
        print(self.name)
        
# 实例化类
person = Person()
person.info()

如果一个类创建了多个实例对象,那么self根据接收的实例对象的不同获取的属性也不同。

python
class Person:
    def __init__(self, name):
        self.name = name
        
    def info(self):
        # 使用self访问实例属性
        print(self.name)

        
# 实例化多个实例对象
anna = Person('Tom')
anna.info()

shuangshuang = Person('Jack')
shuangshuang.info()
5. __init__方法

所谓的__init__方法其实就是一种比较特殊的实例方法,也被称之为构造方法。这个方法特殊的地方在于在类实例化的过程中会自动执行该方法,无需开发者手动执行,一般用作创建实例属性。

对于__init__方法我们必须知道的是:构造方法不是我们创建出来的,这个方法在object基类中已经实现(object类是所有类的父类,也被称之为基类,在Python3中的类都默认继承了这个基类,至于什么是继承,在下面的内容中会进行讲解。)

在创建__init__方法时需要注意的是:第一个参数必须为self,构造方法没有返回值,也就是说构造方法不能写return

python
class Test:
    def __init__(self):
        print('这是一个构造函数,在类实例化的过程中会自动执行,无需手动调用...')
     

class Person:
    # 在构造方法中写入的形参需要在实例化的过程中传入指定的实参
    def __init__(self, name):
        # 一般使用构造方法创建实例属性
        self.name = name

# 实例化
test = Test()
person = Person('Tom')
6. 私有属性

私有属性不能在类的外部调用,只能在一个类的内部使用。这种特殊属性可以提供一定的数据安全性。

python
class Person:
    def __init__(self, name, gender):
        # 普通实例属性
        self.name = name
        # 私有属性, 创建方式: 在实例属性名称前加双下划线__
        self.__gender = gender
    
    # 私有属性只能在一个类的内部使用
    def set_gender(self, value):
        # 在当前方法中可以对传递过来的value进行判断并进行选择性的赋值。当前案例省略了这种代码需求
        self.__gender = value
        return self.__gender
    
    def get_gender(self):
        return self.__gender
    

person = Person('Tom', '女')

print(person.name)
print(person.get_gender())
person.set_gender('男')
print(person.get_gender())

# print(person.__gender) 当前获取方式会抛出异常
7. 私有方法

私有方法与私有属性类似,只能在一个类的内部使用。

python
class BankService:
    def __init__(self, money):
        # 私有属性
        self.__money = money
    
    # 实例方法
    def set_money(self, new_money):
        self.__money = new_money
        return self.__money
    
    # 私有方法
    def __get_money(self):
        return self.__money
    
    # 在普通的实例方法中调用私有方法
    def interface_get_money(self):
        return self.__get_money()
    
bs = BankService(10)
# 通过普通的实例方法调用私有方法获取私有方法的返回值
print(bs.interface_get_money())

# print(bs.__get_money()) 当前代码会抛出异常

'''
如果一个父类中定义私有属性与私有方法,那么继承这个父类的子类无法获取私有属性与私有方法
'''
8. 对象关联

使用对象关联可以让两个独立存在的类相互访问。

python
class ClassRoom:
    def __init__(self, name, stu_obj):
        self.class_room_name = name
        # 当前stu_obj接收的是另外一个类的实例对象
        self.stu_obj = stu_obj

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

stu_anna = Student('Tom')
class_python = ClassRoom('python_1班', stu_anna)


'''
使用班级类的实例对象访问学生类中的实例属性
	1. 班级类中的stu_obj指向了学生类中的实例对象
	2. 学生类中的实例对象可以访问学生类中的实例属性
	3. 因为班级类中的stu_obj指向的是学生类中的实例对象,所以可以使用stu.obj访问学生类中的实例属性
'''
print(class_python.stu_obj.student_name)

利用对象关联的特性实现将多个学生关联到一个教室

python
class ClassRoom:
    def __init__(self, name):
        self.class_room_name = name
        self.stus = list()
        
    def interface_add_stu(self, stu):
        # 使用实例方法完成对象关联
        self.stus.append(stu)

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

# 创建教室对象
class_python = ClassRoom('python_1班')

# 创建多个学生对象
stu_anna = Student('Tom')
stu_shuangshuang = Student('Jack')

# 使用interface_add_stu方法将学生类的多个实例对象添加到班级类的stus列表中
class_python.interface_add_stu(stu_anna)
class_python.interface_add_stu(stu_shuangshuang)

# 使用班级类中的stus属性访问多个学生对象中的name属性
for stu in class_python.stus:
    print(stu.student_name)
9. 继承

在大多数语言中都有继承的概念,所谓的继承其实就是将已经存在的类中的属性与方法传递给一个新的类,这种行为类似于我们人类社会中的遗产继承。

python
# 继承代码示例
class Animal:
    def __init__(self):
        print('这是动物的一些共有的行为...')
        
class Person(Animal):
    pass


class Dog(Animal):
    pass


class Cat(Animal):
    pass


person = Person()
dog = Dog()
cat = Cat()

# 通过代码执行发现在person、dog、cat这三个类的实例化过程中都执行了Animal类的构造方法
# 说明了只要子类继承了父类,那么子类也拥有了父类的方法与属性

在类的继承过程中有两个专业术语:父类、子类

  • 父类:被继承的类
  • 子类:继承的类

在一些其它资料中会将父类称之为基类,子类称之为派生类。所表达的含义都是一样的。

10. 单继承

所谓的单继承其实就是字面意思,子类继承了一个父类。

python
class Animal:
    def __init__(self):
        self.name = None
    
    def eat(self):
        print('吃饭...')
        
    def sleep(self):
        print('睡觉...')

        
class Person(Animal):
    pass

person = Person()
print(person.name)
person.eat()
person.sleep()

# 通过代码执行发现,子类可以打印和执行父类中的属性与方法

在子类中创建父类没有的属性并使用父类中的方法打印这些属性。

python
class Animal:
    def eat(self):
        print('吃饭...')
        
    def sleep(self):
        print('睡觉...')
    
    def info(self):
        print(f'姓名: {self.name}, 性别: {self.gender}')
        
        
class Person(Animal):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender


person = Person('Jack', '女')
person.eat()
person.sleep()

在使用继承时我们需要注意的是:如果需要添加新的属性与方法需要在子类中实现,不要在父类中实现新属性与新方法。原因是:只要在父类修改了代码,那么会影响所有继承这个父类的子类。

如果父类中含有私有属性与私有方法的情况下,在继承时子类不会获取父类的私有属性与私有方法。

11. 多继承

多继承就是一个子类继承了多个父类,类似日常生活中的 "干爹"。

python
# 多继承代码示例
class A:
    pass


class B:
    pass


# C类继承了A、B两个类
class C(A, B):
    pass

多继承的实际应用

python
# 照相功能
class Camera:
    def take_photo(self):
        print('照相功能...')

# 打游戏功能
class PlayGame:
    def game(self):
        print('打游戏功能...')

# 创建一个手机类, 并在这个手机类中添加多个功能
class Iphone(Camera, PlayGame):
    def call(self):
        print('打电话功能...')
        

# 实例化手机类, 并使用多个功能
iphone = Iphone()
iphone.call()
iphone.take_photo()
iphone.game()
12. 重写

如果一个子类中继承了一个父类,但是父类中的方法不能满足与当前的业务需求,那么我们就可以在子类中创建一个与父类同名的方法进行方法覆盖,这样的代码行为我们称之为重写。

python
class Father:
    def play_game(self):
        print('正在玩足球游戏...')
     
    
class Son(Father):
    # 当前子类中的方法与父类方法同名,会进行方法覆盖
    def play_game(self):
        print('正在玩篮球游戏...')
      
    
son = Son()
son.play_game()

在之后的日常开发中如果发现一个父类中的一些方法不能满足当前业务需求,则直接在子类中创建与父类同名的方法,并实现自己需要的业务逻辑即可。需要注意的是:方法修改限于子类,不能修改父类方法。修改父类方法会影响其它的子类。

13. super 方法

如果在子类使用父类中的方法,但是父类中的方法有一部分代码不满足业务需求。那么可以使用spuer()方法重用满足需求的部分代码。

python
class Father:
    def play_game(self):
        print('正在玩足球游戏...')
     
    
class Son(Father):
    # 当前子类中的方法与父类方法同名,会进行方法覆盖
    def play_game(self):
        # 在当前子类方法中调用父类方法
        super().play_game()
        # 新添加的功能代码
        print('正在玩篮球游戏...')
      
    
son = Son()
son.play_game()
python
# 如果父类中的部分属性可以被子类重用, 则可以使用spuer()进行属性的重载
class Father:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __str__(self):
        # 当前方法遇到print打印该类的实例对象会触发运行, 并且__str__方法的返回值必须为字符串
        return f'姓名: {self.name}, 年龄: {self.age}'
    

class Son(Father):
    def __init__(self, name, age, gender):
        # 重用父类中的name、age属性
        super().__init__(name, age)
        self.gender = gender
    
    def __str__(self):
        return f'姓名: {self.name}, 年龄: {self.age}, 性别: {self.gender}'
    

son = Son('Tom', 18, '女')
print(son)
python
# 如果父类中的属性过多, 可以使用不定长参数进行接收
class Father:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def __str__(self):
        # 当前方法遇到print打印该类的实例对象会触发运行, 并且__str__方法的返回值必须为字符串
        return f'姓名: {self.name}, 年龄: {self.age}'
    

class Son(Father):
    def __init__(self, *args, **kwargs):
        # 重用父类中的name、age属性
        super().__init__(*args)
        self.kwargs = kwargs
    
    def __str__(self):
        return f'姓名: {self.name}, 年龄: {self.age}, 其它信息: {self.kwargs}'
    
    # 获取字典数据
    def interface_get_dict(self, key):
        if self.kwargs.get(key) is None:
            return '暂无数据'
        else:
            return self.kwargs.get(key)
            
    

son = Son('Tom', 18, gender='女')
print(son)
print(son.interface_get_dict('gender'))

注意点:

  1. 使用spuer()方法可以调用父类中的方法,但是不能使用super()方法获取或修改父类中的实例属性。如果需要请使用父类的类对象或者父类的实例对象进行获取或修改。
  2. super()方法可以获取父类中的类属性,但是不能修改和删除。
14. 多态

多态从字面意思上分析的话就是多种形态的意思。如果多个子类(单个子类也可以)继承了同一个父类,并且同时对同一个父类中的方法进行了重写,那么这种代码行为我们称之为多态。

python
class Animal:
    def bark(self):
        print('动物在叫...')
        
class Person(Animal):
    def bark(self):
        print('人在叫...')
        
class Dog(Animal):
    def bark(self):
        print('狗在叫...')
        

animal = Animal()
person = Person()
dog = Dog()

animal.bark()
person.bark()
dog.bark()

# 通过上述代码发现,不同的实例对象调用相同方法名时返回了不同的行为,这种情况就是多态。

总结:实现多态必须满足以下条件:

  • 有继承关系
  • 有方法重写
15. 静态方法

如果类中的方法的第一个参数为self,则调用这个方法必须通过实例对象。这种方法也被称之为实例方法。但是现在我期望在不创建实例对象的情况下也能调用类中的方法的话,那么我们就需要创建静态方法进行方法调用。

python
class Person:
    @staticmethod  # 当前语法在python中称之为装饰器,装饰器内容会在之后进行讲解。
    def info():
        # 静态方法的特征是:1.被staticmethod所装饰。2.当前方法没有self参数。
        print('这是一个静态方法...')
        
        
# 使用类名.方法名来运行静态方法
Person.info()

总结:如果类中的某一个方法无需使用类中的属性与方法的情况下,则可以使用静态方法。

16. 类属性

如果使用构造方法创建出来的属性我们称之为实例属性。但是实例属性与实例对象是绑定关系,每个实例对象都有自己的实例属性,并且多个实例对象中的实例属性是相互隔离的。在某些场景中多个对象需要共用一个属性的情况下,就需要使用类属性进行数据共享。

python
# 统计学生人数
class Student:
    # 类属性
    stu_num = 0
    
    def __init__(self, name):
        self.name = name
        # 使用类名.属性名进行值的修改
        Student.stu_num += 1
        
    def info(self):
        print(f'学生名称: {self.name}, 学生人数: {Student.stu_num}')

anna = Student('Tom')
anna.info()
shuangshuang = Student('Jack')
shuangshuang.info()

# 通过代码执行发现,创建一个实例对象类属性的值加1
# 类属性可以被类本身与实例对象访问
17. 类方法

类方法的主要功能是对类中的类属性进行操作,相对于静态方法来说,类方法可以访问类属性,静态方法不能访问。

python
# 统计学生人数
class Student:
    # 类属性
    stu_num = 0
    
    def __init__(self, name):
        self.name = name
        # 使用类名.属性名进行值的修改
        Student.stu_num += 1
        
    def info(self):
        print(f'学生名称: {self.name}')
    
    # 单独定义方法获取学生人数
    @classmethod
    def get_student_num(cls):
        print(f'学生人数: {cls.stu_num}')

anna = Student('Tom')
anna.info()
shuangshuang = Student('Jack')
shuangshuang.info()

# 使用类名.类方法()进行方法调用
Student.get_student_num()

总结:

  1. 定义类方法时需要使用@staticmethod修饰。
  2. 类方法的第一个形式参数为clscls指向的是类对象,也就是类本身。
  3. 类方法可以使用实例对象类名调用。
18. 类对象

一个类创建的实例属性是保存在实例对象中的,那么在类中创建的类对象保存在哪里呢?答案是类对象中。类对象保存了当前这个类的方法与类属性。实例对象通过一个特殊的方法__class__来访问类对象中所保存的方法与属性。

python
class Student:
    stu_num = 0
   
	@classmethod
    def print_stu_num(cls):
        return '这是类方法返回的学生人数: {cls.stu_num}'

stu = Student()

# 使用__class__方法访问和调用类属性与类方法
# 如果这个类中存在实例方法,那么使用__class__也是可以调用的。
print(stu.__class__.stu_num)
print(stu.__class__.print_stu_num())

dir()方法:如果想要查看一个实例对象中的所有属性与方法,可以使用dir()方法查看。

python
class Student:
    stu_num = 0
   
	@classmethod
    def print_stu_num(cls):
        return '这是类方法返回的学生人数: {cls.stu_num}'

stu = Student()
print(dir(stu))
19. 多继承以及MRO继承顺序

在多继承中使用类名.__init__()的方式进行父类方法调用

python
print("******多继承使用类名.__init__发生的状态******\n\n")
class Parent(object):
    def __init__(self, name):
        print('parent的init开始被调用')
        self.name = name
        print('parent的init结束被调用')

class Son1(Parent):
    def __init__(self, name, age):
        print('Son1的init开始被调用')
        self.age = age
        Parent.__init__(self, name)
        print('Son1的init结束被调用')

class Son2(Parent):
    def __init__(self, name, gender):
        print('Son2的init开始被调用')
        self.gender = gender
        Parent.__init__(self, name)
        print('Son2的init结束被调用')

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init开始被调用')
        Son1.__init__(self, name, age)  # 单独调用父类的初始化方法
        Son2.__init__(self, name, gender)
        print('Grandson的init结束被调用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)

print("******多继承使用类名.__init__发生的状态******\n\n")

运行结果:

txt
******多继承使用类名.__init__发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用类名.__init__发生的状态******

在多继承中使用super()进行父类方法调用

python
print("******多继承使用super().__init__发生的状态******")
class Parent(object):
    def __init__(self, name, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
        print('parent的init开始被调用')
        self.name = name
        print('parent的init结束被调用')

class Son1(Parent):
    def __init__(self, name, age, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son1的init开始被调用')
        self.age = age
        super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son1的init结束被调用')

class Son2(Parent):
    def __init__(self, name, gender, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son2的init开始被调用')
        self.gender = gender
        super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
        print('Son2的init结束被调用')

class Grandson(Son1, Son2):
    def __init__(self, name, age, gender):
        print('Grandson的init开始被调用')
        # 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
        # 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
        # super(Grandson, self).__init__(name, age, gender)
        super().__init__(name, age, gender)
        print('Grandson的init结束被调用')

print(Grandson.__mro__)

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******多继承使用super().__init__发生的状态******\n\n")

运行结果:

txt
******多继承使用super().__init__发生的状态******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用super().__init__发生的状态******

上述两种调用父类的方法是有区别的

  1. 如果2个子类中都继承了父类,当在子类中通过父类名调用时,parent被执行了2次
  2. 如果2个子类中都继承了父类,当在子类中通过super调用时,parent被执行了1次

在单继承中使用super()

python
print("******单继承使用super().__init__发生的状态******")
class Parent(object):
    def __init__(self, name):
        print('parent的init开始被调用')
        self.name = name
        print('parent的init结束被调用')

class Son(Parent):
    def __init__(self, name, age):
        print('Son1的init开始被调用')
        self.age = age
        super().__init__(name)  # 单继承不能提供全部参数
        print('Son1的init结束被调用')

class Grandson(Son):
    def __init__(self, name, age, gender):
        print('Grandson的init开始被调用')
        self.gender = gender
        super().__init__(name, age)  # 单继承不能提供全部参数
        print('Grandson的init结束被调用')

gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******单继承使用super().__init__发生的状态******\n\n")

运行结果:

txt
******单继承使用super().__init__发生的状态******
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******单继承使用super().__init__发生的状态******

总结:

  1. super().__init__相对于类名.__init__,在单继承上用法基本没有区别
  2. 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,具体看前面的输出结果
  3. 多继承时,使用super方法,对父类的传参,由于super的算法导致的原因,必须把参数全部传递,否则会报错
  4. 单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错
  5. 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
20. 单例模式

如果对一个类进行了多次的实例化,那么在内存中产生多个实例对象。在某些场景下,并不需要多个实例对象。而是重用第一次创建的实例对象。例如:在一个类中创建了多个关于云服务器的连接信息,这些信息是不变的。那么只是需要一个实例对象来访问这些信息,而不是创建多个来占用内存。

python
# 单例模式代码示例
class Singleton:
    _instance = None
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls)
        return cls._instance
    
    def __init__(self):
        pass

single_1 = Singleton()
single_2 = Singleton()
print(id(single_1) == id(single_2))
python
class ConnectionServer:
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, host, port, password):
        self.host = host
        self.port = port
        self.password = password


server_1 = ConnectionServer('192.168.1.1', 1234, '123')
server_2 = ConnectionServer('192.168.1.2', 3456, '456')
print(id(server_1) == id(server_2))

print(server_1.host, server_1.port, server_1.password)
print(server_2.host, server_2.port, server_2.password)

总结:

  1. __new__方法是一个特殊的方法,与__init__方法类似。如果在类中存在以双下划线开头并且双下划线结尾的方法名时,则这个方法我们称之为魔术方法。魔术方法在基类object中已经实现。
  2. 在类的实例化过程中,__new__方法比__init__方法先执行。
  3. __new__方法的第一个参数为cls,而不是self。在object基类源码中可以发现__new__方法是一个类方法。
21. object基类

在Python3中,所有定义的类都默认继承了object。在object类中实现了多个方法,包括了魔术方法。

python
# object 源码
class object:
    """
    The base class of the class hierarchy.
    
    When called, it accepts no arguments and returns a new featureless
    instance that has no instance attributes and cannot be given any.
    """
    def __delattr__(self, *args, **kwargs): # real signature unknown
        """ Implement delattr(self, name). """
        pass

    def __dir__(self, *args, **kwargs): # real signature unknown
        """ Default dir() implementation. """
        pass

    def __eq__(self, *args, **kwargs): # real signature unknown
        """ Return self==value. """
        pass

    def __format__(self, *args, **kwargs): # real signature unknown
        """ Default object formatter. """
        pass

    def __getattribute__(self, *args, **kwargs): # real signature unknown
        """ Return getattr(self, name). """
        pass

    def __ge__(self, *args, **kwargs): # real signature unknown
        """ Return self>=value. """
        pass

    def __gt__(self, *args, **kwargs): # real signature unknown
        """ Return self>value. """
        pass

    def __hash__(self, *args, **kwargs): # real signature unknown
        """ Return hash(self). """
        pass

    def __init_subclass__(self, *args, **kwargs): # real signature unknown
        """
        This method is called when a class is subclassed.
        
        The default implementation does nothing. It may be
        overridden to extend subclasses.
        """
        pass

    def __init__(self): # known special case of object.__init__
        """ Initialize self.  See help(type(self)) for accurate signature. """
        pass

    def __le__(self, *args, **kwargs): # real signature unknown
        """ Return self<=value. """
        pass

    def __lt__(self, *args, **kwargs): # real signature unknown
        """ Return self<value. """
        pass

    @staticmethod # known case of __new__
    def __new__(cls, *more): # known special case of object.__new__
        """ Create and return a new object.  See help(type) for accurate signature. """
        pass

    def __ne__(self, *args, **kwargs): # real signature unknown
        """ Return self!=value. """
        pass

    def __reduce_ex__(self, *args, **kwargs): # real signature unknown
        """ Helper for pickle. """
        pass

    def __reduce__(self, *args, **kwargs): # real signature unknown
        """ Helper for pickle. """
        pass

    def __repr__(self, *args, **kwargs): # real signature unknown
        """ Return repr(self). """
        pass

    def __setattr__(self, *args, **kwargs): # real signature unknown
        """ Implement setattr(self, name, value). """
        pass

    def __sizeof__(self, *args, **kwargs): # real signature unknown
        """ Size of object in memory, in bytes. """
        pass

    def __str__(self, *args, **kwargs): # real signature unknown
        """ Return str(self). """
        pass

    @classmethod # known case
    def __subclasshook__(cls, subclass): # known special case of object.__subclasshook__
        """
        Abstract classes can override this to customize issubclass().
        
        This is invoked early on by abc.ABCMeta.__subclasscheck__().
        It should return True, False or NotImplemented.  If it returns
        NotImplemented, the normal algorithm is used.  Otherwise, it
        overrides the normal algorithm (and the outcome is cached).
        """
        pass

    __class__ = None # (!) forward: type, real value is "<class 'type'>"
    __dict__ = {}
    __doc__ = ''
    __module__ = ''

Sube's Study Notes.