运行结果如下:
xue@xue-MacBookAir:~/python_learn$ python3 static_method.py {'__init__': <function Dog.__init__ at 0x7f05cadd5730>, 'eat': <function Dog.eat at 0x7f05cadd57b8>, '__str__': <function Dog.__str__ at 0x7f05cadd58c8>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': 'this is a class: Dog (描述信息)', '__module__': '__main__', '__call__': <function Dog.__call__ at 0x7f05cadd5840>, '__dict__': <attribute '__dict__' of 'Dog' objects>} {'name': 'bob'} hellloBob this is a class: Dog (描述信息) hello () {} _ _ getitem _ _ 、_ _ setitem _ _ 、_ _ delitem _ _ : 用于索引操作 class Foo(object): def __init__(self): self.data = {} def __getitem__(self, key): print('__getitem__', key) return self.data.get(key) def __setitem__(self, key, value): print('__setitem__', key, value) self.data[key] = value def __delitem__(self, key): print('__delitem__', key) obj = Foo() obj['name'] = 'xue' # 调setitem print(obj.data) print(obj['name']) # 调getitem del obj['name'] # 调delitem _ new _ 和 _ metaclass _ class Foo(object): def __init__(self,name): self.name = name f = Foo("severen")上述代码中,f 是通过 Foo 类实例化的对象,其实,不仅 f 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:f对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建的。
print(type(f)) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建 print(type(Foo)) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
在这里补充一下类的创建方式其实有两种,如下
# 第1种方式 class Foo(object): def func(self): print('hello severen') # ---------------------------------- # 第2种方式 def func(self): print("hello world") def __init__(self, name): self.name = name print("---") Foo = type("Foo", (object,), {"func": func, '__init__': __init__}) f = Foo('Bob') f.func()到这里,我们知道了类默认是由 type 类实例化产生,那么type类对象又是由谁来创建产生的呢?type类中如何实现的创建类?类又是如何创建对象? 答:类中有一个属性 _ metaclass_,其用来表示该类由 谁 来实例化创建,所以,我们可以为 _ metaclass_ 设置一个type类的派生类,从而查看 类 创建的过程。
# Author: Mr.XUe # 2019.10.30 class MyType(type): def __init__(self, what, base=None, dict=None): print("--MyType init--") super(MyType, self).__init__(what, base, dict) def __call__(self, *argv, **kwargv): print("--MyType call--") obj = self.__new__(self, *argv, **kwargv) # obj.data = {'name': 111} self.__init__(obj) class Foo(object): __metaclass__ = MyType def __init__(self, name): self.name = name def __new__(cls, *argv, *kwargv): # 这一块可以添加自己的小功能 return object.__new__(cls, argv, kwargv) # 继承父类的__new__方法 obj = Foo("bob")metaclass参考文章:https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python
好处:简化导入自定义模块的导入步骤 举例:在A目录下有lib文件夹和dong态导入模块.py文件,在lib文件夹下又有__init__.py和aa.py两个文件,init.py文件没有内容,aa.py的代码如下:
# Author: Mr.Xue # 2019.10.31 # aa.py class C(object): def __init__(self): self.name = 'xue'现在我们的需求是dong态导入模块.py文件需要去导入aa.py文件。 逻辑分析:按照正常的逻辑,我们首先需要去获取到dong态导入模块.py文件的父目录,在通过父目录我们可以找到lib,最后通过lib才可以找到aa.py,程序代码如下:
# Author: Mr.Xue # 2019.10.31 # dong态导入模块.py #!usr/bin/python3 import os,sys # __file__: 当前文件 # os.path.abspath: 获取当前文件的绝对路径 # os.path.dirname: 获取上一级的路径 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # BASE_DIR现在A所在的绝对路径 sys.path.append(BASE_DIR) # 将该路径写入环境 from lib import aa # 导入aa.py文件 print(aa.C().name) # 打印C类的对象属性name上面这一种导入的方式写起来就比较繁琐复杂,现在我们来看看动态导入模块的写法,代码如下:
# Author: Mr.Xue # 2019.10.29 # dong态导入模块.py # ------解释器自己内部使用的 #lib = __import__("lib.aa") #print(lib) #print(lib.aa.C().name) # -------官方建议使用的 import importlib # 导入importlib库 aa = importlib.import_module("lib.aa") # 导入aa.py文件 #print(aa) # 打印aa的内存地址 print(aa.C().name) # 打印C类的对象属性name是不是很简单,短短的三行代码就完成了,逻辑上也很简单。两种方式的运行结果都是一样的,如下所示:
xue@xue-MacBookAir:~/python_learn/A$ python3 dong态导入模块.py xue使用断言可以创建更稳定、品质更好且不易于出错的代码。当需要在一个值为FALSE时中断当前操作的话,可以使用断言 看一个简单的例子:
# Author: Mr.Xue # 2019.10.31 class A(object): def __init__(self, name): self.name = name a = A("xue") # 判断name属性的值是不是str类型的,如果是,执行下一步,否则,阻断在这里 assert type(a.name) is str print(a.name)上面的条件成立,所以会打印name的值,“xue”;否则,阻塞