面向对象的介绍 类中常用内置函数__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'>]

  

 

 
 

 

原文地址:https://www.cnblogs.com/wakee/p/10825508.html