zoukankan      html  css  js  c++  java
  • 面向对象的介绍 类中常用内置函数__init__ __new__ __call__ __str__ __del__ 类属性的查找顺序

    1.1 面向对象和面向过程的介绍和对比

    面向对象:Object Oriented Programming,简称OOP,是一种程序设计思想,它将对象作为程序的基本单元 能指挥某某完成其能完成的功能

    面向过程:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。

    面向对象和面向过程的优缺点

    面向过程:

    优点:复杂问题简单化(一步一步解决),流程化

    缺点:机械化 扩展性差 如若修改 牵一发动全身

    面向对象:

    优点:提高了扩展性 复用性 可维护性提高

    缺点:程序复杂程度变高了 无法预知完成的结果

    适用场景:

    面向过程:适合扩展性低的程序 著名的例子有Linux內核,git,以及Apache HTTP Server等

    面向对象:适合扩展性高的程序 适合需求经常修改增加的程序

    1.2 类和面向对象的关系

    对象:属性和方法的结合体

    类:一系列的相同属性和相同方法的集合体

    注意: 在面向过程中 是先产生类 然后再去产生对象的

    1.3 面向对象编程的思考过程

    如果遇到面向对象的问题,首先想到的需要哪些对象,这些对象具备哪些属性和技能,再根据这些属性和技能去创建类,最后在创建对象出来
    

      

    1.4 创建类和对象

    类有两种作用:属性引用和实例化

    在python中 定义类通过class关键字 后面跟类名 类名实例化就是创建类的对象 也就是类名加()

     
    class Person:		# 创建类
    	pass
    
    p1 = Person()			# 创建对象  

     

    1.41 -1 对象的属性操作 (类名.属性)

     s1这个对象目前没有属性和方法 要为其添加属性可以在创建对象后使用点语法(变量名加 . )比如为`p1对象添加name属性

     p1.name = 'tom'
    

    同样通过点语法来获取对象的属性值

    print(p1.name)
    #输出 tom
    

     

    1.5 类中的常用内置函数(重点!)

    __init__():类的初始化 为对象的属性设置初始值

    为什么需要: 在类的实例中(也就是对象中),一些属性是必须存在的,就可以使用初始化函数来完成,比如student对象必须有name属性,因为它是标识学生的不同的

    魔法方法 __xx__()的统称为魔法方法

     

    案例:

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

    注意: __init__函数要求第一个参数必须是self,该参数表示需要被初始化的对象本身,这样就可以将name属性绑定到对象上 

    在创建对象时Student("jack")会申请新的内存空间用于保存对象数据,接着自动调init函数

     

    小结

    • __init__函数用于为对象属性设置初始值

    • 在创建对象时 会自动调用__init__函数

    • 自动传入对象本身进去

     

    __new__()  创建一个类对象

     

    `__new__`方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给`__init__`方法初始化,这一下子就看出了谁是老子谁是小子的关系。
    
    所以,`__new__`方法(第一个执行)先于`__init__`方法执行:
    

      

    class A:
        pass
    
    class B(A):
    
        def __init__(self):
            print("__init__方法被执行")
    
        def __new__(cls, *args, **kwargs):
            print("__new__方法被执行")
            return super().__new__(cls)
    
    b = B()
    '''
    __new__方法被执行
    __init__方法被执行
    '''
    

      

    小结

    1.new的功能是在生成对象之前所做的动作,接受的参数是cls 类

    2.init是在对象生成之后完善对象的属性 它接受的是self 对象

    3.对象生成是在new 里面  return (返回一个对象)

    代码实现上面三句话

    new的功能是在生成对象之前所做的动作.

    class  User:
        def __new__(cls, *args, **kwargs):
            print("new")
    
        def __init__(self,name):
            self.name=name
            print("init")
    
    print(type(User("body")))

    结果:

    new
    <class 'NoneType'>   # 
    

    虽然我们用 User(“body”))实例化了但是打印结果为none type ,根本不是一个对象. 原因是我们在 new 没有返回任何对象. 故称为在实例化对象之前的动作. 对象生成是在 new 里面 return (返回一个对象) 

    我们在 new 返回一个对象,并打印对象type 是不是咱们预期的结果

    class  User:
        def __new__(cls, *args, **kwargs):
            print("new")
            return super().__new__(cls)
        
    print(type(User("body")))
    
    pass
    

     

    打印结果;

    new
    <class '__main__.User'>
    

     

    我们调用了 父类的返回对象的方法return. 正如咱们所料 真的可以生成了对象.

    有了对象以后 init 该干活了.

     

    __init__是在对象生成之后完善对象的属性

    class  User:
        def __new__(cls, *args, **kwargs):
            print("new")
            return super().__new__(cls)
    
        def __init__(self,name):
            self.name=name
            print("init")
    
    print(type(User("body")))
    
    pass
    

     

    打印结果

    new
    init
    <class '__main__.User'>
    

      

     

     

    __call____() 用来控制对象的创建过程 (重点)

    总结

    • 元类中的__ call__()方法会在调用类时执行,

    • 可以用于控制对象的创建过程

    __call__()方法能够让类的实例对象,像函数一样被调用;

    class A(object):
        def __call__(self, x):
            print('__call__ called, print x: ', x)
    
    
    a = A()
    a('123')
    # __call__ called, print x:  123
    

      

    看a('123')这是函数的调用方法,这里a实际上是类对象A的实例对象,实例对象能像函数一样传参并被调用,就是__call__()方法的功能;

     

    接下来用一段简单的代码,来总体感受一下三个方法的用法和区别:

    class A(object):
        def __init__(self, x):
            print ('x in __init__', x)
        def __new__(cls, y):
            print ('y in __new__', y)
            return super(A, cls).__new__(cls)
        def __call__(self, z):
            print( 'z in __call__', z)
    
    A('123')('abc')
    '''
    y in __new__ 123
    x in __init__ 123
    z in __call__ abc
    '''
    

      

     

    其他案例

    class MyMeta(type):
    
        # 获得某个类的实例
        def __call__(self, *args, **kwargs):
            print("call")
            # return super().__call__(*args,**kwargs)
            new_args = []
            for i in args:
                if isinstance(i,str):
                    # 如果是字符串的话就返回大写
                    new_args.append(i.upper())
                else:
                    new_args.append(i)
            return super().__call__(*new_args,**kwargs)
    
    
    
    # 注意注意注意:  __new__  __init__ 是创建类对象时还会执行
    # __call__ 类对象要产生实例时执行
    
    class Student(metaclass=MyMeta):
        def __init__(self,name,gender,age):
            self.name = name
            self.gender = gender
            self.age = age
    
    s = Student("jack","woman",18)
    print(s.name) # JACK
    print(s.age)  # 18
    print(s.gender) # WOMAN
    
    
    class Person(metaclass=MyMeta):
        def __init__(self,name,gender):
            self.name = name
            self.gender = gender
    
    p = Person("rose","man")  #
    print(p.name)  # ROSE
    
    '''
    call
    JACK
    18
    WOMAN
    call
    ROSE
    '''
    

      

     

    __str__() 返回对象类型和地址 字符串形式

    class Person:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        # 将对象转换为字符串时执行
        def __str__(self):
            print("str run")
            return "my name is %s , age is %s" % (self.name,self.age)
    
    
    p = Person("rose",20)
    print(p) #在打印前都会现将要打印的内容转为字符串  通过调用__str__函数
    
    '''
    str run
    my name is rose , age is 20
    '''
    

      

    小结

    • __str__该方法在object中有定义 默认行为 返回对象类型以及地址 <main.Person object at 0x0000016F450C7390>

    • 在将对象转为字符串时执行,返回值是字符串

    • 当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据

     

     

    __del__() (不常用)

    """
    __del__
    当对象被删除前会自动调用 该方法
    声明时候会删除对象?
        1.程序运行结束 解释器退出 将自动删除所有数据
        2.手动调用del 时也会删除对象
    
    注意:该函数不是用来删除对象的
    
    使用场景
    当你的对象在创建时,开启了不属于解释器的资源 例如打开了一个文件
    必须保证当对象被删除时 同时关闭额外的资源  如文件
    
    
    也称之为析构函数  构造 的反义词
        构造 指的是从无到有
        析构 值从有到无
        简单的说就对象所有数据全部删除
    
    
    总结:__del__该函数 用于 在对象删除前做一些清理操作
    """
    # 假设要求每一个person对象都要绑定一个文件
    class Person:
        def __init__(self,name,path,mode="rt",encoding="utf-8"):
            self.name = name
            self.file = open(path,mode,encoding=encoding)
    
    
    
        # 读取数据的方法
        def read_data(self):
            return self.file.read()
    
    
        def __del__(self):
            print("del run!")
            self.file.close()
    

      

     

    1.6 类属性的查找顺序

    对象---子类>--->父类--->父类的父类.....object. object是所有的类的基类
    子类有多个父类时,运用mro列表展示的顺序来查找
    

     

    #A没有继承B,但是A内super会基于C.mro()继续往后找
    class A:
        def test(self):
            super().test()
    class B:
        def test(self):
            print('from B')
    class C(A,B):
        pass
    
    c=C()
    c.test() #打印结果:from B
    
    
    print(C.mro())
    #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
    

      

     

     
     

     

  • 相关阅读:
    cocos2D-X 4.0 build
    Boost Download
    史上最全的CSS hack
    web前端js中ES6的规范写法
    爬虫最终杀手锏 --- PhantomJS 详解(附案例)
    移动端300ms延迟的解决方法
    js动态生成html元素并为元素追加属性
    css中border-sizing属性详解和应用
    纯CSS实现Tab切换
    阻止移动端浏览器点击图片会预览的几种方法
  • 原文地址:https://www.cnblogs.com/wakee/p/10825508.html
Copyright © 2011-2022 走看看