Python avanzado ----- orientado a objetos 7.0 (discutir el método __nuevo__ y el método __init__ en detalle)

Tabla de contenido

Prefacio:

método __init__

__nuevo__ método (¡importante!)

1. El proceso de llamada del método __new__

2. Anule el método __new__

3. El método __nuevo__ devuelve valores diferentes

3. Modo único


Prefacio:

        El método __new__() se introdujo inicialmente en el número anterior, pero de hecho, todavía hay muchos contenidos de los que vale la pena hablar en este método. Después de aprender este método, podemos controlar de manera flexible la asignación de espacio de nuestros objetos (enlace en el número anterior Python avanzado-----Facing Object 6.0 (método de enlace [método de clase, método estático] y método integrado)_Python Ouni Sauce's Blog-CSDN Blog ), ¡echemos un vistazo en el próximo número!

método __init__

Este método debería ser familiar para todos. Sí, este es un método de inicialización, también llamado método de construcción. Cuando creamos un nuevo objeto, necesitamos inicializar las propiedades o métodos de este objeto. Este método va acompañado de Se ejecuta automáticamente. cuando se crea el objeto. Aquí hay un ejemplo:

class Person(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age  #定义实例化对象的属性
        print('person message')
dick=Person('Dick',18)
#输出结果:person message
print(dick.name,dick.age)
#输出结果:Dick 18

A partir de este ejemplo, es fácil ver que el método __init__ se llama automáticamente y el mensaje de persona se generará automáticamente, pero antes de eso, hay otro método llamado antes que el método __init__, que es para asignar espacio para el objeto __nuevo__ método

__nuevo__ método (¡importante!)

1. El proceso de llamada del método __new__

        La clase principal de todas las clases en Python es la clase de objeto, y la clase de objeto también se llama superclase.Cuando creamos un objeto de instancia, primero asignamos el espacio de memoria del objeto y luego podemos poner datos en él. En este momento, el método __nuevo__ se usará para crear este espacio y luego devolverá este espacio de objetos al método __init__ para su inicialización. Es decir, el método __nuevo__ devolverá este espacio y lo pasará al parámetro de instancia propia en el __init__ , por lo que el método __new__ se llama automáticamente igual que el método __init__.

__new__ El método es un método de clase estático incorporado . Después de que el intérprete de python obtiene la referencia del objeto devuelta por este método, pasa esta referencia como el primer parámetro al método init, por lo que el nuevo método se ejecuta antes que el método init.   

 Entendimiento popular:

La afirmación anterior puede ser un poco difícil de entender, aquí haré una metáfora: En la vida diaria, los muebles de madera que usamos se obtienen procesando la madera. El método __nuevo__ también es un leñador que se encarga de obtener la madera. maderas al método __init__, es decir, el carpintero, que puede utilizar estas maderas para hacer todo tipo de muebles para que los usemos

        Algunas personas pueden preguntar aquí, cada vez que defino una clase, no defino el método __new__, sino que solo defino el método __init__, pero ¿de dónde proviene el espacio de memoria?

        respuesta: tenga en cuenta que todas las clases heredan la clase de objeto, por lo que cuando escribimos contenido en una clase, en realidad reescribimos la clase de objeto. Tanto el método __init__ como el método __new__ pertenecen al método de clase de objeto, cuando vamos a def __init__(self ): , en realidad reescribimos el método __init__ en el objeto, pero no vamos a def __new__(cls): Es decir, no reescribimos el método __new__, entonces la clase que definimos retendrá y llamará a esto y luego devolver el espacio del objeto instanciado al método __init__.

Ejemplo:

class A(object):
    def __init__(self,name):
        self.name=name
class B(object):
    object.__new__(object) #当我们没有重写__new__方法,默认继承并且调用object类__new__方法
    def __init__(self,name):
        self.name=name
user=A('dick')
user2=B("hao")
print(user.__sizeof__(),user2.__sizeof__()) #查看占内存
#输出结果:32 32

En el ejemplo anterior, podemos ver que los efectos de la clase A y la clase B son exactamente los mismos, pero acabo de escribir la llamada al método __new__ de la clase B, por lo que, de hecho, el método __new__ heredará automáticamente y llamará a la clase de objeto , no tenemos que preocuparnos por

Nota : el método __new__ se llama antes que el método __init__

 Mira un ejemplo:

class User(object):
    def __init__(self,name):
        self.name=name
        print(f'我的名字是{self.name}')
    def __new__(cls, *args, **kwargs): #对__new__方法重写
        print('这个是__new__方法')
        return object.__new__(cls) #返回这个类对象的空间
jb=User('Dick')
#输出结果:
# 这个是__new__方法
# 我的名字是Dick

Se puede ver en el resultado de salida que el contenido en el método __new__ se muestra primero, y luego se muestra el contenido en el método __init__, por lo que el método __new__ se ejecuta primero.

2. Anule el método __new__

        A veces no nos gusta el método __nuevo__ de la clase principal, por lo que reescribimos el método, entonces, ¿a qué debemos prestar atención al reescribir este método?

Cuando reescribimos el método __nuevo__, necesitamos un valor de retorno del índice del espacio de objetos. Este valor de retorno generalmente usa el método __nuevo__ de la clase principal 

 Precauciones:

1. Debe haber una referencia al objeto devuelto (es decir, el espacio del objeto)

2. Preste atención a la clase del objeto devuelto

Ejemplo 1: ¿Qué sucede si no se devuelve ninguna referencia al objeto?

class A(object):
    def __new__(cls, *args, **kwargs):
        print('重写new方法')
    #这里我没有写返回值会怎么样呢?
    def __init__(self,name):
        print('初始化方法')
        self.name=name
user=A('dick')
print(user)
#输出结果:重写new方法
#         None

Aquí no tengo valor de retorno. Cuando creo un objeto de instancia, no sé dónde está el espacio asignado, por lo que no puedo inicializar el objeto, por lo que no se puede ejecutar el método __init__, por lo que no se obtiene el objeto de instancia. espacio, es decir, se crea un espacio, pero no se encuentra el espacio, y los datos no se pueden almacenar.

Ejemplo 2:

class B(object):
    def __init__(self,name):
        self.name=name
        print('初始化方法')
    def __new__(cls, *args, **kwargs):
        print('这是new方法')
        return object.__new__(cls)
user=B('Dick')
print(user.name)
#输出结果:
# 这是new方法
# 初始化方法
# Dick

El método __new__ aquí tiene el valor de retorno del índice del objeto, y pasará el objeto instanciado de la clase actual al parámetro self en el método __init__, y luego lo inicializará, para que este objeto pueda obtener el espacio.

3. El método __nuevo__ devuelve valores diferentes

Hemos aprendido el método de clase antes, y todos sabemos que el método de clase tendrá un parámetro --cls, que significa representar la clase en sí, y el método __new__ también tiene un parámetro cls, pero este parámetro no representa necesariamente su propia clase Es decir, también se pueden pasar otras clases principales. Entonces, cuando este parámetro tiene diferentes valores de entrada, ocurrirán diferentes situaciones, y a continuación se explicarán una por una con el código como ejemplo.

Ejemplo 1:

class A(object):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        print('这个是A类重写的方法')
        res=object.__new__(cls)
        return res
class B(A):
    def __init__(self,sound):
        self.sound=sound
user=B('汪汪')
print(user.sound)
#输出结果:
# 这个是A的类
# 汪汪

Aquí A vuelve a escribir el método __nuevo__ en la clase de objeto, B hereda A, pero B no vuelve a escribir el método __nuevo__ en A, por lo que B usa directamente el método __nuevo__ en A y lo pasa a la clase actual (cls ), y luego devuelve el instanciado espacio de la clase actual (cls)

Ejemplo 2:

class A(object):
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        print('这个是A类重写的方法')
        res=object.__new__(cls)
        return res
class B(A):
    def __init__(self,sound):
        self.sound=sound
    def __new__(cls, *args, **kwargs):
        print('这个是B类重写的方法')
        res=cls.__new__(cls)  #这里是返回自身的实例对象空间引索
        return res
user=B('汪汪')
print(user.sound)
#结果:报错,进入死循环

 Nota: al reescribir el método __new__, no puede devolver el índice de espacio de su propio objeto de clase, de lo contrario, ingresará a un ciclo infinito

Ejemplo 3: 

class A(object):
    jk='beauty'
    def __init__(self,name):
        self.name=name
    def __new__(cls, *args, **kwargs):
        res=object.__new__(cls)
        return res
    def fun(self):
        print('大家好!')
class B(A):
    def __init__(self,sound):
        self.sound=sound
    def __new__(cls, *args, **kwargs):
        res=super().__new__(A)  #返回的是类对象A的空间引索
        return res
user=B('汪汪') #实际上这里创建是类A的实例化对象
print(user.jk)  #输出结果:beauty
user.fun()  #输出结果:大家好!
print(user.sound) #报错'A' object has no attribute 'sound'
print(user.name)   #报错'A' object has no attribute 'name'

 Este ejemplo es para devolver el índice de espacio asignado por la clase A, pero es diferente del tipo de clase B, por lo que no puede ingresar la inicialización __init__ de la clase B, lo que lleva a la situación de que solo hay espacio pero no inicialización. creamos un Al instanciar el objeto usuario, el usuario es un objeto instanciado de clase A, no un objeto instanciado de clase B. (El usuario del objeto instanciado aquí no pasa por la inicialización __init__ de la clase A y la inicialización __init__ de la clase B)

3. Modo único

        El modo singleton es un modo de asignación de espacio de objetos muy común para las computadoras.Por ejemplo: cuando abrimos la ventana de configuración en la computadora, cuando volvemos a abrir la ventana de configuración, la computadora detectará si la ventana existe y, si existe, la no volverá a aparecer una ventana, es decir, se generará una nueva ventana solo después de bifurcar esta ventana, lo que puede evitar las ventanas emergentes de varias ventanas y también evitar la ocupación de memoria no válida (cada vez que aparece una ventana Requiere memoria), esto se llama el modo singleton.

 En Python, cada vez que creamos un objeto de instancia, necesitamos ocupar una dirección de memoria.Al trabajar en un proyecto, algunos objetos de instancia inútiles siempre ocupan esta dirección, lo que hace que el programa se ejecute lentamente. ¿Cómo implementar el modo singleton a través del método __new__ en Python? Miremos hacia abajo.

Beneficios de singletons: Ahorre memoria

 el código se muestra a continuación:

class Student(object):
    _instance=None  #定义一个类属性,是可以在类中进行调用的
    def __init__(self, name,age):
        self.name=name
        self.age=age
    def __new__(cls, *args, **kwargs):
        if cls._instance is None: #如果这个内存为空的话就进行空间分配
            print('进行空间分配')
            cls._instance=super().__new__(cls)
        return cls._instance
Jack=Student('Jack',18)
John=Student('John',19)
Dick=Student('Dick',18)
print(Jack is Dick is John) #输出:True
print(Jack.name,Jack.age)   #输出:Dick 18
print(John.name,John.age)   #输出:Dick 18
print(Dick.name,Dick.age)   #输出:Dick 18

Lo anterior es un modo singleton. Todos estos objetos instanciados ocupan la misma dirección de memoria, por lo que las direcciones de memoria son las mismas, pero cada vez que se crea un objeto instanciado, el objeto instanciado sobrescribirá un objeto y, finalmente, el espacio pertenece al último objeto instanciado, por lo que es la salida Dick 18

 

 Bueno, todo lo anterior es todo el contenido de este número Amigos, ¿han aprendido a asignar espacio y memoria a los objetos?

Comparte un fondo de pantalla todos los días:

Supongo que te gusta

Origin blog.csdn.net/m0_73633088/article/details/129347622
Recomendado
Clasificación