Python 魔法函数 和 元类

Python Object 类 和 元类

魔法函数

一个类中的魔法函数继承自 object 类

在Python的类中存在一些特殊的方法,这些方法都是 __方法__ 格式,这种方法在内部均有特殊的含义,接下来我们来讲一些常见的特殊成员:

  • __init__,初始化方法

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


  obj = Foo("小三")
  • __new__,构造方法

  class Foo(object):
      def __init__(self, name):
          print("第二步:初始化对象,在空对象中创建数据")
          self.name = name

      def __new__(cls, *args, **kwargs):
          print("第一步:先创建空对象并返回")
          return object.__new__(cls)
          # return super().__new__(cls) # 官方文档 


  obj = Foo("小三")
  # 流程
  # __new__(cls, *args, **kwargs) 用于创建一个空对象 
  # __init__(self) 初始化对象, 在空对象中创建数据

  class A:
      def __init__(self, name, age):
          """ 
              接收 __new__() 的返回值,当作参数传递到 self 中。
              当 obj = A() 类被对象示例化时, 触发 __init__() 函数。
          """
          # print(self)
          print(self)
          print("init")
          print(name)
          print(age)

      def __new__(cls, *args, **kwargs):
          """ 
               当类加() 执行时,触发 __new__() 方法 
              cls:表示当前的类 例如 A();本质是将 A 作为参数,传给 cls。
              __new__ 函数的返回值是将 一个对象 作为 self 参数传入到 __init__(self) 函数中。
          """
          print(args)
          print(kwargs)
          print("new")
          print(cls.__name__)
          a = super().__new__(cls)
          print(a)
          return a


  # A("hello", age=10)
  # A.__new__(A, "hello", age=10)
  • __call__,括号执行

  class Foo(object):
      def __call__(self, *args, **kwargs):
          print("执行call方法")


  obj = Foo()
  obj()
  • __str__ 字符串方法

  class Foo(object):

      def __str__(self):
          return "哈哈哈哈"


  obj = Foo()
  data = str(obj)
  print(data)
  • __dict__ ,成员变量

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


  obj = Foo("小三",19)
  print(obj.__dict__)
  • __getitem____setitem____delitem__

  class Foo(object):

      def __getitem__(self, item):
          pass

      def __setitem__(self, key, value):
          pass

      def __delitem__(self, key):
          pass


  obj = Foo("小三", 19)

  obj["x1"]
  obj['x2'] = 123
  del obj['x3']
  • __enter____exit__

  class Foo(object):

      def __enter__(self):
          print("进入了")
          return 666

      def __exit__(self, exc_type, exc_val, exc_tb):
          print("出去了")


  obj = Foo()
  with obj as data:
      print(data)
  超前知识:数据连接,每次对远程的数据进行操作时候都必须经历。
  1.连接 = 连接数据库
  2.操作数据库
  3.关闭连接
  class SqlHelper(object):

      def __enter__(self):
          self.连接 = 连接数据库
          return 连接

      def __exit__(self, exc_type, exc_val, exc_tb):
          self.连接.关闭



  with SqlHelper() as 连接:
      连接.操作..


  with SqlHelper() as 连接:
      连接.操作...
  # 面试题(补充代码,实现如下功能)

  class Context:

      def do_something(self):
          print('内部执行')


  with Context() as ctx:
      print('内部执行')
      ctx.do_something()

上下文管理的语法。

  • __add__ 等。

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

      def __add__(self, other):
          return "{}-{}".format(self.name, other.name)


  v1 = Foo("alex")
  v2 = Foo("sb")

  # 对象+值,内部会去执行 对象.__add__方法,并将+后面的值当做参数传递过去。
  v3 = v1 + v2
  print(v3)
  • __iter__ 迭代器

    • 迭代器
# 迭代器类型的定义:
    1.当类中定义了 __iter__ 和 __next__ 两个方法。
    2.__iter__ 方法需要返回对象本身,即:self
    3. __next__ 方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常。
    官方文档:https://docs.python.org/3/library/stdtypes.html#iterator-types

# 创建 迭代器类型 :
    class IT(object):
        def __init__(self):
            self.counter = 0<pre><code>    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration()
        return self.counter</code></pre># 根据类实例化创建一个迭代器对象:
    obj1 = IT()<pre><code># v1 = obj1.__next__()
# v2 = obj1.__next__()
# v3 = obj1.__next__() # 抛出异常

v1 = next(obj1) # obj1.__next__()
print(v1)

v2 = next(obj1)
print(v2)

v3 = next(obj1)
print(v3)


obj2 = IT()
for item in obj2:  # 首先会执行迭代器对象的__iter__方法并获取返回值,一直去反复的执行 next(对象) 
    print(item)</code></pre>迭代器对象支持通过next取值,如果取值结束则自动抛出StopIteration。
for循环内部在循环时,先执行__iter__方法,获取一个迭代器对象,然后不断执行的next取值(有异常StopIteration则终止循环)。
  • 生成器
# 创建生成器函数
    def func():
        yield 1
        yield 2

# 创建生成器对象(内部是根据生成器类generator创建的对象),生成器类的内部也声明了:__iter__、__next__ 方法。
    obj1 = func()<pre><code>v1 = next(obj1)
print(v1)

v2 = next(obj1)
print(v2)

v3 = next(obj1)
print(v3)


obj2 = func()
for item in obj2:
    print(item)</code></pre>如果按照迭代器的规定来看,其实生成器类也是一种特殊的迭代器类(生成器也是一个中特殊的迭代器)。
  • 可迭代对象
# 如果一个类中有__iter__方法且返回一个迭代器对象 ;则我们称以这个类创建的对象为可迭代对象。

class Foo(object):<pre><code>def __iter__(self):
    return 迭代器对象(生成器对象)</code></pre>obj = Foo() # obj是 可迭代对象。

# 可迭代对象是可以使用for来进行循环,在循环的内部其实是先执行 __iter__ 方法,获取其迭代器对象,然后再在内部执行这个迭代器对象的next功能,逐步取值。
for item in obj:
    pass
class IT(object):
    def __init__(self):
        self.counter = 0<pre><code>def __iter__(self):
    return self

def __next__(self):
    self.counter += 1
    if self.counter == 3:
        raise StopIteration()
    return self.counter</code></pre>class Foo(object):
    def __iter__(self):
        return IT()


obj = Foo() # 可迭代对象


for item in obj: # 循环可迭代对象时,内部先执行obj.__iter__并获取迭代器对象;不断地执行迭代器对象的next方法。
    print(item)
# 基于可迭代对象&迭代器实现:自定义range
class IterRange(object):
    def __init__(self, num):
        self.num = num
        self.counter = -1<pre><code>def __iter__(self):
    return self

def __next__(self):
    self.counter += 1
    if self.counter == self.num:
        raise StopIteration()
    return self.counter</code></pre>class Xrange(object):
    def __init__(self, max_num):
        self.max_num = max_num<pre><code>def __iter__(self):
    return IterRange(self.max_num)</code></pre>obj = Xrange(100)

for item in obj:
    print(item)
class Foo(object):
    def __iter__(self):
        yield 1
        yield 2


obj = Foo()
for item in obj:
    print(item)
# 基于可迭代对象&生成器 实现:自定义range

class Xrange(object):
    def __init__(self, max_num):
        self.max_num = max_num<pre><code>def __iter__(self):
    counter = 0
    while counter < self.max_num:
        yield counter
        counter += 1</code></pre>obj = Xrange(100)
for item in obj:
    print(item)

常见的数据类型:

v1 = list([11,22,33,44])

v1是一个可迭代对象,因为在列表中声明了一个 __iter__ 方法并且返回一个迭代器对象。
from collections.abc import Iterator, Iterable

v1 = [11, 22, 33]
print( isinstance(v1, Iterator) )  # false,判断是否是迭代器;判断依据是__iter__ 和 __next__。
v2 = v1.__iter__()
print( isinstance(v2, Iterator) )  # True



v1 = [11, 22, 33]
print( isinstance(v1, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。

v2 = v1.__iter__()
print( isinstance(v2, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。

元类

  • 创建类的其他方法
class_name = "User"
class_base = (object, )
class_body = """
def __init__(self, name, age):
    self.name = name
    self.age = age

def func(self):
    print(self.name)
"""

class_dict = {}
exec(class_body, globals(), class_dict)
print(class_dict)


class MyType(type):

    def __init__(self, class_name, class_bases=None, class_dict=None):
        super(MyType, self).__init__(class_name, class_bases, class_dict)

    def __call__(self, *args, **kwargs):

        obj = self.__new__(self, *args, **kwargs)
        self.__init__(obj, *args, **kwargs)
        return obj


User = MyType(class_name, class_base, class_dict)
user_obj = User("hxc", 18)
print(user_obj.name)
  • 元类是 创建类的类, 所有类的元类都是 type

  • 人话:就是你创建一个类的时候,本质上是 type 帮你创建的这个类

class MyType(type):

    def __init__(self, class_name, class_bases=None, class_dict=None):
        super(MyType, self).__init__(class_name, class_bases, class_dict)  # 此处继承调用的是父类 type 中的 __init__ 方法

    def __call__(self, *args, **kwargs):             # 当你申请对象时 就会触发此函数 object = ClassName()
        obj = self.__new__(self, *args, **kwargs)    # 元类 type 中, 要求 __new__(self, *args, **kwargs) 是这种方式传参
        self.__init__(obj, *args, **kwargs)


class Foo(object):
    __metaclass__ = MyType  # Foo = MyType()

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

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)   # 父类创建的空对象 本身是一种数据结构,可以 对象.变量 = "value" 形式赋值


obj = Foo("hxc")  # obj = Foo("hxc") = MyType()("hxc")  此时触发 MyType 中的 __call__ 方法
print(obj.name)

# 代码执行顺序:
# 1 Foo("hxc")
# 2 __metaclass__ = MyType 相当于执行 Foo = MyType()
# 3 执行 MyType 中的 __init__ 函数 class_name:类名; class_bases:父类; class_dict: 名称空间
# 4 执行 MyType 中的 __call__ 函数 得到返回值 返回给对象 obj
posted @ 2021-09-28 13:24  隔江千万里  阅读(86)  评论(0)    收藏  举报