python3 面向对象编程,面向对象编程 python

  python3 面向对象编程,面向对象编程 python

  本文详细讲解Python的面向对象编程,通过示例代码详细介绍。对大家的学习或者工作都有一定的参考价值,有需要的朋友可以参考一下。

  00-1010 I、isinstance和issubclass II、反射(hasattr和getattr和setattr和delattr)1、反射在类2中的应用、反射在模块3中的应用、示例:基于反射机制的web帧路由模拟III、__getattr__、__setattr__和__delattr__和_ _ getattribute _ _ event _ _ getattribute _ IV、__setitem__和_ _ delitem _ _ V、__format__:自定义格式字符串VI、__format__str__和__repr__ str _ _: STR函数或打印函数触发器_ _ repr _ _: REPR函数或交互式解释器触发器XII。___模块_ _和_ _类_ _模拟十四。描述符(_ _ get _ _ and _ _ set _ _ and _ _ delete _ _)1。使用描述符2。类装饰器3360没有参数3。类装饰器3360具有参数4。描述符与类装饰符5结合使用。自定制@property6、自定制@classmethod7、自定制元类)1、类型实现2、自定义元类控件类3、自定义元类控件类的实例化4、练习:使用元类修改属性隐藏属性5、使用元类实现单件模式Python面向对象编程(1)

  Python面向对象编程(2)

  Python面向对象编程(3)

  

目录

  Type():子类实例不会被视为父类类型;Isinstance():子类实例被视为父类类型。Issubclass():确定它是否是它的子类。类Foo(对象):

  及格

  班级酒吧(Foo):

  及格

  print(type(Foo())==Foo)

  #真的

  print(type(Bar())==Foo)

  #错误

  # isinstance参数是对象和类。

  print(isinstance(Bar(),Foo))

  #真的

  print(issubclass(Bar,Foo))

  #真的

  print(issubclass(Foo,object))

  #真的

  

一、isinstance和issubclass

  

二、反射(hasattr和getattr和setattr和delattr)

  反射在类中的使用

  反射就是通过字符串来操作类或者对象的属性。反射本质就是在使用内置函数,其中反射有以下四个内置函数:

  

  • hasattr:判断一个方法是否存在与这个类中
  • getattr:根据字符串去获取obj对象里的对应的方法的内存地址,加"()"括号即可执行
  • setattr:通过setattr将外部的一个函数绑定到实例中
  • delattr:删除一个实例或者类中的方法

  

class People:

   country = China

   def __init__(self, name):

   self.name = name

   def eat(self):

   print(%s is eating % self.name)

  peo1 = People(nick)

  print(hasattr(peo1, eat)) # peo1.eat

  # True

  print(getattr(peo1, eat)) # peo1.eat

  # >

  print(getattr(peo1, xxxxx, None))

  # None

  setattr(peo1, age, 18) # peo1.age=18

  print(peo1.age)

  # 18

  print(peo1.__dict__)

  # {name: egon, age: 18}

  delattr(peo1, name) # del peo1.name

  print(peo1.__dict__)

  # {age: 18}

  

  

2、反射在模块中的使用

  动态导入一个模块__import__,并且动态输入函数名然后执行相应功能。

  注意:getattr,hasattr,setattr,delattr对模块的修改都在内存中进行,并不会影响文件中真实内容。

  

# dynamic.py

  imp = input("请输入模块:")

  commons = __import__(imp) # 等价于import imp

  # commons = __import__(imp, fromlist=True) # 模块名可能不是在本级目录中存放着,改用这种方式就能导入成功

  inp_func = input("请输入要执行的函数:")

  f = getattr(commons, inp_func, None) # 作用:从导入模块中找到你需要调用的函数inp_func,然后返回一个该函数的引用.没有找到就烦会None

  f() # 执行该函数

  r = hasattr(commons, age) # 判断某个函数或者变量是否存在

  print(r)

  setattr(commons, age, 18) # 给commons模块增加一个全局变量age = 18,创建成功返回none

  setattr(commons, age, lambda a: a + 1) # 给模块添加一个函数

  delattr(commons, age) # 删除模块中某个变量或者函数

  

  

3、实例:基于反射机制模拟web框架路由

  需求:比如我们输入<www.xxx.com/commons/f1> ,返回f1的结果。

  

# 动态导入模块,并执行其中函数

  url = input("url: ")

  target_host,target_module, target_func = url.split(/)

  m = __import__(aaa. + target_module, fromlist=True)

  inp = url.split("/")[-1] # 分割url,并取出url最后一个字符串

  if hasattr(m, inp): # 判断在commons模块中是否存在inp这个字符串

   inp= getattr(m, inp) # 获取inp的引用

   inp() # 执行

  else:

   print("404")

  

  

三、__getattr__、__setattr__和__delattr__和__getattribute__事件

  

  • __getattr__:只有在使用点调用属性且属性不存在的时候才会触发。比较有用
  • __delattr__:删除属性的时候会触发
  • __setattr__:添加/修改属性会触发它的执行
    当你自己写__getattr__、__delattr__、__setattr__方法,系统会调用你写的方法,如果没写,系统调用默认

  

class Foo:

   x = 1

   def __init__(self, y):

   self.y = y

   def __getattr__(self, item):

   print(----> from getattr:你找的属性不存在)

   def __setattr__(self, key, value):

   print(----> from setattr)

   # self.key = value # 这就无限递归了,你好好想想

   # self.__dict__[key] = value # 应该使用它

   def __delattr__(self, item):

   print(----> from delattr)

   # del self.item # 无限递归了

   self.__dict__.pop(item)

  f1 = Foo(10)

  # ----> from setattr

  print(f1.__dict__ ) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值。除非你直接操作属性字典,否则永远无法赋值

  # {}

  f1.z = 3

  # ----> from setattr

  print(f1.__dict__)

  # {}

  f1.__dict__[a] = 3 # 我们可以直接修改属性字典,来完成添加/修改属性的操作(不会触发__setattr__)

  del f1.a

  # ----> from delattr

  print(f1.__dict__)

  # {}

  

  

__getattribute__

  查找属性无论是否存在,都会执行。

  

class Foo:

   def __init__(self, x):

   self.x = x

   def __getattribute__(self, item):

   print(不管是否存在,我都会执行)

  f1 = Foo(10)

  f1.x

  # 不管是否存在,我都会执行

  f1.xxxxxx

  # 不管是否存在,我都会执行

  当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError

  

class Foo:

   def __init__(self, x):

   self.x = x

   def __getattr__(self, item):

   print(执行的是我)

   # return self.__dict__[item]

   def __getattribute__(self, item):

   print(不管是否存在,我都会执行)

   raise AttributeError(哈哈)

  f1 = Foo(10)

  f1.x

  # 不管是否存在,我都会执行

  # 执行的是我

  f1.xxxxxx

  # 不管是否存在,我都会执行

  # 执行的是我

  

  

四、__setitem__和__getitem和__delitem__

  

  • __setitem__:中括号赋值时触发
  • __getitem__:中括号取值时触发
  • __delitem__:中括号删除时触发
  • __delattr__:.删除时触发

  

class Foo:

   def __init__(self, name):

   self.name = name

   def __getitem__(self, item):

   print(getitem执行, self.__dict__[item])

   def __setitem__(self, key, value):

   print(setitem执行)

   self.__dict__[key] = value

   def __delitem__(self, key):

   print(del obj[key]时,delitem执行)

   self.__dict__.pop(key)

   def __delattr__(self, item):

   print(del obj.key时,delattr执行)

   self.__dict__.pop(item)

  f1 = Foo(sb)

  f1[age] = 18

  # setitem执行

  f1[age1] = 19

  # setitem执行

  f1[age]

  # getitem执行 18

  f1[name] = tank

  # setitem执行

  del f1.age1

  # del obj.key时,delattr执行

  del f1[age]

  # del obj[key]时,delitem执行

  print(f1.__dict__)

  # {name: tank}

  

  

五、__format__:自定制格式化字符串

  

date_dic = {

   ymd: {0.year}:{0.month}:{0.day},

   dmy: {0.day}/{0.month}/{0.year},

   mdy: {0.month}-{0.day}-{0.year},

  }

  class Date:

   def __init__(self, year, month, day):

   self.year = year

   self.month = month

   self.day = day

   def __format__(self, format_spec):

   # 默认打印ymd的{0.year}:{0.month}:{0.day}格式

   if not format_spec or format_spec not in date_dic:

   format_spec = ymd

   fmt = date_dic[format_spec]

   return fmt.format(self)

  d1 = Date(2016, 12, 29)

  print(format(d1))

  # 2016:12:29

  print({:mdy}.format(d1))

  # 12-29-2016

  

  

六、__del__:析构方法

  会在对象被删除之前自动触发

  

class People:

   def __init__(self, name, age):

   self.name = name

   self.age = age

   self.f = open(test.txt, w, encoding=utf-8)

   def __del__(self):

   print(run======>)

   # 做回收系统资源相关的事情

   self.f.close()

  obj = People(egon, 18)

  del obj # del obj会间接删除f的内存占用,但是还需要自定制__del__删除文件的系统占用

  # run=-====>

  

  

七、__slots__

  使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)。

  __slots__是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)

  字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__。

  

class Foo:

   __slots__ = x

  f1 = Foo()

  f1.x = 1

  f1.y = 2 # 报错

  print(f1.__slots__ ) # f1不再有__dict__

  当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。使用__slots__后不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。

  注意:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再支持一些普通类特性了,比如多继承。

  大多数情况下,你应该只在那些经常被使用到的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。

  

class Bar:

   __slots__ = [x, y]

  n = Bar()

  n.x, n.y = 1, 2

  n.z = 3 # 报错

  

  

八、__doc__:返回类的注释信息

  

class Foo:

   我是描述信息

   pass

  print(Foo.__doc__)

  # 我是描述信息

  该属性无法被继承

  

class Foo:

   我是描述信息

   pass

  class Bar(Foo):

   pass

  print(Bar.__doc__) # 该属性无法继承给子类

  # None

  

  

九、__call__:会在调用对象时自动触发。

  构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

  

class Foo:

   def __init__(self):

   print(__init__触发了)

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

   print(__call__触发了)

  obj = Foo() # 执行 __init__

  # __init__触发了

  obj() # 执行 __call__

  # __call__

  

  

十、__init__和__new__:类构造器

  __new__方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给__init__方法初始化。

  __new__方法(第一个执行)先于__init__方法执行:

  

class A:

   pass

  class B(A):

   def __new__(cls):

   print("__new__方法被执行")

   return super().__new__(cls)

   def __init__(self):

   print("__init__方法被执行")

  b = B()

  # __new__方法被执行

  # __init__方法被执行

  绝大多数情况下,我们都不需要自己重写__new__方法,但在当继承一个不可变的类型(例如str类,int类等)时,它的特性就尤显重要了。我们举下面这个例子:

  

# 1、使用init的情况:

  class CapStr1(str):

   def __init__(self, string):

   string = string.upper()

  a = CapStr1("I love China!")

  print(a)

  # I love China! 无变化 !!!!!!!

  # 2、使用__new__的情况

  class CapStr2(str):

   def __new__(cls, string):

   string = string.upper()

   return super().__new__(cls, string)

  a = CapStr2("I love China!")

  print(a)

  # I LOVE CHINA!

  

  

十一、__str__和__repr__

  

  

__str__:执行str函数或print函数触发

  

class Foo:

   def __init__(self, name, age):

   """对象实例化的时候自动触发"""

   self.name = name

   self.age = age

   def __str__(self):

   print(打印的时候自动触发,但是其实不需要print即可打印)

   return f{self.name}:{self.age} # 如果不返回字符串类型,则会报错

  obj = Foo(nick, 18)

  print(obj) # obj.__str__() # 打印的时候就是在打印返回值

  # 打印的时候自动触发,但是其实不需要print即可打印

  # nick:18

  

  

__repr__:执行repr函数或者交互式解释器触发

  

  • 如果__str__没有被定义,那么就会使用__repr__来代替输出。
  • 注意:这俩方法的返回值必须是字符串,否则抛出异常。

  

class School:

   def __init__(self, name, addr, type):

   self.name = name

   self.addr = addr

   self.type = type

   def __repr__(self):

   return School(%s,%s) % (self.name, self.addr)

   def __str__(self):

   return (%s,%s) % (self.name, self.addr)

  s1 = School(oldboy1, 北京, 私立)

  print(from repr: , repr(s1))

  # from repr: School(oldboy1,北京)

  print(from str: , str(s1))

  # from str: (oldboy1,北京)

  print(s1)

  # (oldboy1,北京)

  s1 # jupyter属于交互式

  # School(oldboy1,北京)

  

  

十二、__module__和__class__

  

  • __module__ 表示当前操作的对象在那个模块
  • __class__表示当前操作的对象的类是什么

  

# lib/aa.py

  class C:

   def __init__(self):

   self.name = SB

  # index.py

  from lib.aa import C

  obj = C()

  print(obj.__module__) # 输出 lib.aa,即:输出模块

  print(obj.__class__) # 输出 lib.aa.C,即:输出类

  

  

十三、实现文件上下文管理(__enter__和__exit__)

  with语句,即上下文管理协议,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。

  

  • 使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
  • 在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处。

  __exit__()中的三个参数分别代表异常类型,异常值和追溯信息。with语句中代码块出现异常,则with后的代码都无法执行。

  

class Open:

   def __init__(self, name):

   self.name = name

   def __enter__(self):

   print(出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量)

   def __exit__(self, exc_type, exc_val, exc_tb):

   print(with中代码块执行完毕时执行我啊)

   print(exc_type)

   print(exc_val)

   print(exc_tb)

  try:

   with Open(a.txt) as f:

   print(=====>执行代码块)

   raise AttributeError(***着火啦,救火啊***)

  except Exception as e:

   print(e)

  # 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量

  # =====>执行代码块

  # with中代码块执行完毕时执行我啊

  # <class AttributeError>

  # ***着火啦,救火啊***

  #

  # ***着火啦,救火啊***

  如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行。

  

class Open:

   def __init__(self, name):

   self.name = name

   def __enter__(self):

   print(出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量)

   def __exit__(self, exc_type, exc_val, exc_tb):

   print(with中代码块执行完毕时执行我啊)

   print(exc_type)

   print(exc_val)

   print(exc_tb)

   return True

  with Open(a.txt) as f:

   print(=====>执行代码块)

   raise AttributeError(***着火啦,救火啊***)

  print(0 * 100) # ------------------------------->会执行

  # 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量

  # =====>执行代码块

  # with中代码块执行完毕时执行我啊

  # <class AttributeError>

  # ***着火啦,救火啊***

  #

  # 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

  #

  

  

模拟open

  

class Open:

   def __init__(self, filepath, mode=r, encoding=utf-8):

   self.filepath = filepath

   self.mode = mode

   self.encoding = encoding

   def __enter__(self):

   # print(enter)

   self.f = open(self.filepath, mode=self.mode, encoding=self.encoding)

   return self.f

   def __exit__(self, exc_type, exc_val, exc_tb):

   # print(exit)

   self.f.close()

   return True

   def __getattr__(self, item):

   return getattr(self.f, item)

  with Open(a.txt, w) as f:

   print(f)

   f.write(aaaaaa)

   f.wasdf #抛出异常,交给__exit__处理

  # <_io.TextIOWrapper name=a.txt mode=w encoding=utf-8>

  

  

十四、描述符(__get__和__set__和__delete__)

  描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性。

  描述符是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件。

  描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议

  

  • __get__():调用一个属性时,触发
  • __set__():为一个属性赋值时,触发
  • __delete__():采用del删除属性时,触发

  描述符的作用是用来代理另外一个类的属性的。包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法

  

class Foo:

   def __get__(self, instance, owner):

   print(触发get)

   def __set__(self, instance, value):

   print(触发set)

   def __delete__(self, instance):

   print(触发delete)

  f1 = Foo()

  f1.name = nick

  f1.name

  del f1.name

  #无任何输出结果!!!

  必须把描述符定义成这个类的类属性,不能定义到构造函数中。

  

class ST:

   """描述符Str"""

   def __get__(self, instance, owner):

   print(Str调用)

   def __set__(self, instance, value):

   print(Str设置...)

   def __delete__(self, instance):

   print(Str删除...)

  class IN:

   """描述符Int"""

   def __get__(self, instance, owner):

   print(Int调用)

   def __set__(self, instance, value):

   print(Int设置...)

   def __delete__(self, instance):

   print(Int删除...)

  class People:

   name = ST()

   age = IN()

   def __init__(self, name, age): # name被ST类代理,age被IN类代理

   self.name = name

   self.age = age

  p1 = People(alex, 18)

  # Str设置...

  # Int设置...

  p1.name # Str调用

  p1.name = nick # Str设置...

  del p1.name # Str删除...

  p1.age # Int调用

  p1.age = 18 # Int设置...

  del p1.age # Int删除...

  print(p1.__dict__) # {}

  print(People.__dict__)

  # {__module__: __main__, name: <__main__.ST object at 0x0000000002167490>, age: <__main__.IN object at 0x000000000234A700>, __init__: , __dict__: <attribute __dict__ of People objects>, __weakref__: <attribute __weakref__ of People objects>, __doc__: None}

  print(type(p1) == People) # True

  print(type(p1).__dict__ == People.__dict__) # True

  

  

1、使用描述符

  众所周知,python是弱类型语言,即参数的赋值没有类型限制,下面我们通过描述符机制来实现类型限制功能。

  

class Typed:

   def __init__(self, name, expected_type):

   self.name = name

   self.expected_type = expected_type

   def __get__(self, instance, owner):

   print(get--->, instance, owner)

  if instance is None:

  return self

  return instance.__dict__[self.name]

   def __set__(self, instance, value):

   print(set--->, instance, value)

   if not isinstance(value, self.expected_type):

  raise TypeError(Expected %s % str(self.expected_type))

   instance.__dict__[self.name] = value

   def __delete__(self, instance):

   print(delete--->, instance)

   instance.__dict__.pop(self.name)

  class People:

   name = Typed(name, str)

   age = Typed(name, int)

   salary = Typed(name, float)

   def __init__(self, name, age, salary):

   self.name = name

   self.age = age

   self.salary = salary

  try:

   p1 = People(123, 18, 3333.3)

  except Exception as e:

   print(e)

  # set---> <__main__.People object at 0x1082c7908> 123

  # Expected <class str>

  try:

   p1 = People(nick, 18, 3333.3)

  except Exception as e:

   print(e)

  # set---> <__main__.People object at 0x1078dd438> nick

  # set---> <__main__.People object at 0x1078dd438> 18

  # Expected <class int>

  p1 = People(nick, 18, 3333.3)

  # set---> <__main__.People object at 0x1081b3da0> nick

  # set---> <__main__.People object at 0x1081b3da0> 18

  # set---> <__main__.People object at 0x1081b3da0> 3333.3

  

  

2、类的装饰器:无参

  

def decorate(cls):

   print(类的装饰器开始运行啦------>)

   return cls

  @decorate # 无参:People = decorate(People)

  class People:

   def __init__(self, name, age, salary):

   self.name = name

   self.age = age

   self.salary = salary

  p1 = People(nick, 18, 3333.3)

  # 类的装饰器开始运行啦------>

  

  

3、类的装饰器:有参

  

def typeassert(**kwargs):

   def decorate(cls):

   print(类的装饰器开始运行啦------>, kwargs)

   return cls

   return decorate

  @typeassert( name=str, age=int, salary=float) # 有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)

  class People:

   def __init__(self, name, age, salary):

   self.name = name

   self.age = age

   self.salary = salary

  p1 = People(nick, 18, 3333.3)

  # 类的装饰器开始运行啦------> {name: <class str>, age: <class int>, salary: <class float>}

  

  

4、描述符与类装饰器结合使用

  

class Typed:

   def __init__(self, name, expected_type):

   self.name = name

   self.expected_type = expected_type

   def __get__(self, instance, owner):

   print(get--->, instance, owner)

   if instance is None:

   return self

   return instance.__dict__[self.name]

   def __set__(self, instance, value):

   print(set--->, instance, value)

   if not isinstance(value, self.expected_type):

   raise TypeError(Expected %s % str(self.expected_type))

   instance.__dict__[self.name] = value

   def __delete__(self, instance):

   print(delete--->, instance)

   instance.__dict__.pop(self.name)

  def typeassert(**kwargs):

   def decorate(cls):

   print(类的装饰器开始运行啦------>, kwargs)

   for name, expected_type in kwargs.items():

   setattr(cls, name, Typed(name, expected_type))

   return cls

   return decorate

  @typeassert(name=str, age=int, salary=float) # 有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)

  class People:

   def __init__(self, name, age, salary):

   self.name = name

   self.age = age

   self.salary = salary

  print(People.__dict__)

  # 类的装饰器开始运行啦------> {name: <class str>, age: <class int>, salary: <class float>}

  # {__module__: __main__, __init__: , __dict__: <attribute __dict__ of People objects>, __weakref__: <attribute __weakref__ of People objects>, __doc__: None, name: <__main__.Typed object at 0x000000000238F8B0>, age: <__main__.Typed object at 0x000000000238FF40>, salary: <__main__.Typed object at 0x000000000238FFA0>}

  p1 = People(nick, 18, 3333.3)

  # set---> <__main__.People object at 0x0000000001E07490> nick

  # set---> <__main__.People object at 0x0000000001E07490> 18

  # set---> <__main__.People object at 0x0000000001E07490> 3333.3

  

  

5、利用描述符原理自定制@property

  实现延迟计算(本质就是把一个函数属性利用装饰器原理做成一个描述符:类的属性字典中函数名为key,value为描述符类产生的对象)

  

class Lazyproperty:

   def __init__(self, func):

   self.func = func

   def __get__(self, instance, owner):

   print(这是我们自己定制的静态属性,r1.area实际是要执行r1.area())

   if instance is None:

   return self

   else:

   print(--->)

   value = self.func(instance)

   setattr(instance, self.func.__name__, value) # 计算一次就缓存到实例的属性字典中

   return value

  class Room:

   def __init__(self, name, width, length):

   self.name = name

   self.width = width

   self.length = length

   @Lazyproperty # area=Lazyproperty(area) 相当于定义了一个类属性,即描述符

   def area(self):

   return self.width * self.length

  r1 = Room(alex, 1, 2)

  print(r1.area) # 先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法

  # 这是我们自己定制的静态属性,r1.area实际是要执行r1.area()

  # --->

  # 2

  print(r1.area) # 先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算

  # 2

  

  

6、自定制@classmethod

  

class ClassMethod:

   def __init__(self, func):

   self.func = func

   def __get__(self, instance, owner): # 类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,

   def feedback(*args, **kwargs):

   print(在这里可以加功能啊...)

   return self.func(owner, *args, **kwargs)

   return feedback

  class People:

   name = nick

   @ClassMethod # say_hi=ClassMethod(say_hi)

   def say_hi(cls, msg):

   print(你好啊,帅哥 %s %s % (cls.name, msg))

  People.say_hi(你是那偷心的贼)

  p1 = People()

  # 在这里可以加功能啊...

  # 你好啊,帅哥 nick 你是那偷心的贼

  p1.say_hi(你是那偷心的贼)

  # 在这里可以加功能啊...

  # 你好啊,帅哥 nick 你是那偷心的贼

  

  

7、自定制@staticmethod

  

class StaticMethod:

   def __init__(self, func):

   self.func = func

   def __get__(self, instance, owner): # 类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身

   def feedback(*args, **kwargs):

   print(在这里可以加功能啊...)

   return self.func(*args, **kwargs)

   return feedback

  class People:

   @StaticMethod # say_hi = StaticMethod(say_hi)

   def say_hi(x, y, z):

   print(------>, x, y, z)

  People.say_hi(1, 2, 3)

  # 在这里可以加功能啊...

  # ------> 1 2 3

  p1 = People()

  p1.say_hi(4, 5, 6)

  # 在这里可以加功能啊...

  # ------> 4 5 6

  

  

十五、元类(metaclass)

  元类:负责产生该对象的类称之为元类,即元类可以简称为类的类

  用class关键字创建一个类,用的默认的元类type,因此以前说不要用type作为类别判断

  

class People: # People=type(...)

   country = China

   def __init__(self, name, age):

   self.name = name

   self.age = age

   def eat(self):

   print(%s is eating % self.name)

  print(type(People))

  <class type>

  

  

1、type实现

  

  • 创建类的3个要素:类名,基类,类的名称空间
  • People = type(类名,基类,类的名称空间)

  

class_name = People # 类名

  class_bases = (object,) # 基类

  class_dic = {} # 类的名称空间

  class_body = """

  country=China

  def __init__(self,name,age):

   self.name=name

   self.age=age

  def eat(self):

   print(%s is eating %self.name)

  """

  exec(class_body, {}, class_dic, ) #执行class_body中的代码,然后把产生的名字丢入class_dic字典中

  print(class_name) # People

  print(class_bases) # (<class object>,)

  print(class_dic) # 类的名称空间

  # {country: China, __init__: , eat: }

  People1 = type(class_name, class_bases, class_dic)

  print(People1) # <class __main__.People>

  obj1 = People1(1, 2)

  obj1.eat() # 1 is eating

  

  

2、自定义元类控制类

  自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程。

  分析用class自定义类的运行原理(而非元类的的运行原理):

  

  • 拿到一个字符串格式的类名class_name='People'

      

  • 拿到一个类的基类们class_bases=(obejct,)

      

  • 执行类体代码,拿到一个类的名称空间class_dic={...}

      

  • 调用People=type(class_name,class_bases,class_dic)

      

  

class Mymeta(type): # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类

   def __init__(self, class_name, class_bases, class_dic):

   print(self:, self) # 现在是People

   print(class_name:, class_name)

   print(class_bases:, class_bases)

   print(class_dic:, class_dic)

   super(Mymeta, self).__init__(class_name, class_bases, class_dic) # 重用父类type的功能

  class People(object, metaclass=Mymeta): # People=Mymeta(类名,基类们,类的名称空间)

   country = China

   def __init__(self, name, age):

   self.name = name

   self.age = age

   def eat(self):

   print(%s is eating % self.name)

  # self: <class __main__.People>

  # class_name: People

  # class_bases: (<class object>,)

  # class_dic: {__module__: __main__, __qualname__: People, country: China, __init__: , eat: }

  应用:我们可以控制类必须有文档。

  

class Mymeta(type): # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类

   def __init__(self, class_name, class_bases, class_dic):

   if class_dic.get(__doc__) is None or len(

   class_dic.get(__doc__).strip()) == 0:

   raise TypeError(类中必须有文档注释,并且文档注释不能为空)

   if not class_name.istitle():

   raise TypeError(类名首字母必须大写)

   super(Mymeta, self).__init__(class_name, class_bases, class_dic) # 重用父类的功能

  try:

   class People(object, metaclass=Mymeta ): # People = Mymeta(People,(object,),{....})

   # """这是People类"""

   country = China

   def __init__(self, name, age):

   self.name = name

   self.age = age

   def eat(self):

   print(%s is eating % self.name)

  except Exception as e:

   print(e)

  # 类中必须有文档注释,并且文档注释不能为空

  

  

3、自定义元类控制类的实例化

  类的调用,即类实例化就是元类的调用过程,可以通过元类Mymeta的__call__方法控制。

  继承的查找顺序:子类->Class –>object–> Mymeta->type

  

class Mymeta(type):

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

   print(self) # self是People

   print(args) # args = (nick,)

   print(kwargs) # kwargs = {age:18}

   # return 123

   # 1. 先造出一个People的空对象,申请内存空间

   # __new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。

   obj = self.__new__(self) # 虽然和下面同样是People,但是People没有,找到的__new__是父类的

   # 2. 为该对空对象初始化独有的属性

   self.__init__(obj, *args, **kwargs)

   # 3. 返回一个初始化好的对象

   return obj

  class People(object, metaclass=Mymeta): # People = Mymeta(),People()则会触发__call__

   country = China

   def __init__(self, name, age):

   self.name = name

   self.age = age

   def eat(self):

   print(%s is eating % self.name)

  # 在调用Mymeta的__call__的时候,首先会找自己(如下函数)的,自己的没有才会找父类的

  # def __new__(cls, *args, **kwargs):

  # # print(cls) # cls是People

  # # cls.__new__(cls) # 错误,无限死循环,自己找自己的,会无限递归

  # obj = super(People, cls).__new__(cls) # 使用父类。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: