2.2 python面向对象
2.2.1 创建类
类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
方法:类中定义的函数。
类的构造方法__init__():类有一个名为 init() 的特殊方法(构造方法),该方法在类实例化时会自动调用。
实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
实例化:创建一个类的实例,类的具体对象。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
# 定义类
class MyClass(object):
def __init__(self, name):
self.name = name
def __new__(self, *args, **kwargs):
return object.__new__(self)
# 根据类创建对象
# 1 执⾏类的new⽅法,创建空对象 【构造⽅法】 {}
# 2 执⾏类的init⽅法,初始化对象 【初始化⽅法】{name:"lLiverpool"}
obj = MyClass("liverpool")
对象是基础类创建的,是先运行了类的new方法,创建了空对象,然后在调用类的构造方法,初始哈创建的空对象。类是由type创建。下面介绍创建类的第二种方式。
# 传统⽅式创建类
class MyClass1(object):
v1 = 123
def func(self):
return 666
# ⾮传统⽅式创建类
# - 创建类型
# - 类名
# - 继承类
# - 成员
Myclass2 = type("MyClass2", (object,), {"v1": 123, "func": lambda self: 666})
# ⾮传统⽅式创建对象
obj = Myclass2()
# ⾮传统⽅式调⽤v1的变量
print(obj.v1)
2.2.2 面向对象的特性
2.2.2.1 多态
多态 一般 是通过继承和方法重写 实现 , 多个子类 继承 同一个父类 ,这些子类对象重写父类的 方法 , 实现不同的逻辑 ,
为父类类型变量赋值不同的类对象 , 当调用被重写的父类方法时 , 执行不同的逻辑 , 此时就实现了多态 ;
子类重写父类的方法 , 这意味着子类可以定义与父类相同名称的方法 , 但实现方式可以不同 ;
当通过子类对象调用该方法时 , 将执行子类的方法 , 而不是父类的方法 ;
这种行为使得子类可以对相同的消息做出不同的响应 , 实现了多态 ;
举例如下:
class Animal:
name = "Animal"
age = 0
def make_sound(self):
print("动物发音")
class Dog(Animal):
def make_sound(self):
super().make_sound() # super().父类方法表示 调用父类的所定义的方法:super.__init__() 表示调用父类的初始化方法
print("汪汪")
class Cat(Animal):
def make_sound(self):
print("喵喵")
animal = Animal()
animal.make_sound() # 动物发音
dog = Dog()
dog.make_sound() # 汪汪
cat = Cat()
cat.make_sound() # 喵喵
2.2.2.2 抽象类
抽象类:父类只定义空方法 , 方法体是 pass , 没有具体实现 ;父类只定义有哪些方法子类负责实现具体的方法逻辑这种 父类 , 就是 " 抽象类 " ;方法体为空 , 也就是 pass 的方法 , 称为 " 抽象方法 " ;有 " 抽象方法 " 的类 , 称为 抽象类 ;
class Animal(object): # 抽象类
def __init__(self):
self.age = 1 # 可以存在属性
def make_sound(self): # 抽象方法
pass
class Dog(Animal):
def make_sound(self):
print("汪汪")
class Cat(Animal):
def make_sound(self):
print("喵喵")
dog = Dog()
dog.make_sound()
cat = Cat()
cat.make_sound()
这种抽象方法的实现有它的弊端,如果你写一个类继承抽象类,但是忘记实现抽象方法,异常只有在你真正使用所定义的抽象函数才会抛出来,还有一种方式可以让错误更早的触发,使用Python提供的abc
模块,对象被初始化之后就可以抛出异常。只有强制定义抽象方法后才会取消异常。
import abc
class Animal(object): # 抽象类
def __init__(self):
self.age = 1
@abc.abstractmethod
def make_sound(self): # 抽象方法
raise NotImplementedError
class Dog(Animal):
def make_sound(self):
print("汪汪")
2.2.2.3 静态方法
静态方法:通过类名. 调用静态方法不需要创建对象,就可以直接调用。
# 静态方法
class Cat(object):
# 不访问实例属性/类属性
# 静态方法不需要传递第一个参数self
@staticmethod
def call():
print('喵喵~')
# 通过类名. 调用静态方法
# 不需要创建对象,就可以直接调用
Cat.call()
2.2.2.4 私有属性和私有方法
私有属性和私有方法:Python中并没有有效限制访问任何实例变量或方法的机制,但是Python规定了使用单/双下划线为变量/方法的名称前缀,以模拟受保护和专用访问说明符的行为。默认情况下,Python类中所有成员都是公共的,可以从类环境之外访问任何成员
# 私有属性和私有方法
class Car(object):
def __init__(self, age, color, brand="奥迪"): # 构造方法
self.__brand = brand # 私有属性 外部不能调用 只能在类中使用
self.age = age # 实例属性
self.color = color # 实例属性
def __voice(self): # 私有方法 只能在类中使用
print(number"车的年龄{self.age}")
car = Car(9, "red")
2.2.2.5 类属性和类方法
类属性和类方法:类也是一个特殊的对象,类对象在内存中只有一份,通过他可以创建出很多个对象实例,除了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法,这就是所谓的就是的类属性和类方法。
类属性:就是给类对象定义的属性。类属性不会用于记录具体的对象特征。使用赋值语句在class关键字下方就可以定义类属性。类属性也可以直接在外面调用。
class Tool(object):
# 1.使用赋值语句定义类属性,记录所有的工具数量
count = 0
def __init__(self, name):
self.name = name
# 让类属性的值 +1
Tool.count += 1
# 创建工具对象(对象在创建的时候,会自动调用初始化方法)
tool1 = Tool('斧头')
tool2 = Tool('榔头')
tool3 = Tool('水桶')
print(Tool.count) # 输出3 可以直接调用类的属性(类似于静态属性)
class Toy(object):
# 使用赋值语句定义类属性,记录所有玩具的数量
count = 0
@classmethod # 定义于类方法
def show_toy_count(cls):
# 在类方法的内部,可以直接访问类属性或调用类方法
print('玩具对象的数量 %d' % cls.count)
def __init__(self, name):
self.name = name
Toy.count += 1
# 创建玩具对象
toy1 = Toy('乐高')
toy2 = Toy('玩具车')
# 调用类方法
Toy.show_toy_count() # 可以类似于静态方法的调用
2.2.2.6 单例
单例:
单例是一种设计模式,应用该模式的类只会生成一个实例。
单例模式保证了在程序的不同位置都可以且仅可以取到同一个对象实例。
如果实例不存在,会创建一个实例;如果已存在就会返回这个实例。因为单例是一个类,所以你也可以为其提供相应的操作方法,以便于对这个实例进行管理。
用new方法新建单例:
# 返回单例
class MyInstance(object):
instance = None
def __new__(cls, *args, **kwargs):
# 第一个参数cls:哪一个类调用就传递哪一个类
# 第二个参数*args:多值的元组参数
# 第三个参数**kwargs:多值的字典参数
# 1.创建对象的时候,new方法会被自动调用
# print '创建对象,分配空间' # 重写了父类的方法
# 2.为对象分配空间
# 注意:__new__方法是一个静态方法,在调用的时候,第一个参数为cls
if cls.instance is None:
# 调用父类的方法,为第一个对象分配空间
cls.instance = object.__new__(cls)
# 3.返回对象的引用
return cls.instance
def __init__(self):
print('初始化播放器')
# 创建播放器对象
MyInstance1 = MyInstance()
print(MyInstance1)
MyInstance2 = MyInstance()
print(MyInstance2) # 返回都是返回的同一个的对象地址
使用迭代器构建单例:
# 使用迭代器构建单例
def Singleton(cls):
_instance = {}
def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return _singleton
@Singleton
class Cls(object):
def __init__(self):
pass
cls1 = Cls()
cls2 = Cls()
print(id(cls1) == id(cls2))
2.2.3 元类的定义
Python中一切皆为对象,我们所定义的类也是type
类所实例的一个对象。type为对象的顶点,所有对象都创建自type,包括其本身;object为类继承的顶点,所有类都继承自object,包括其本身。type是object的类型,同时,object又是type的超类
类本身不过是一个名为type类的实例。用户自定义类,只不过是type类的__call__
运算符的重载。当我们定义一个类的语句结束时,真正发生的情况,是 Python 调用 type
的__call__
运算符。
自定义类的时候会执行这个代码:
class = type(classname, superclasses, attributedict) # 就是type 的__call__运算符重载
Python 调用 type
的__call__
运算符,又会调用以下两个代码
type.__new__(typeclass, classname, superclasses, attributedict)
type.__init__(class, classname, superclasses, attributedict)
class type(name, bases, dict)参数详解:
1、使用1个参数,返回对象的类型。
- 就像
object.__class__
。2、使用3个参数,返回一个新类型对象。本质上,这是类声明的一种动态形式。
- 参数name是一个字符串,表示类名称,并记录为
__name__
属性;- 参数bases是一个元组,一个个记下基础类,并记录为
__bases__
属性;- 参数dict是一个字典,包含类本体的命名空间并被赋值到标准字典。并记录为
__dict__
属性。
metaclass
是type的子类,通过替换type的__call__
运算符重载机制,一旦把一个类型MyClass的 metaclass
设置成MyMeta,MyClass就不再由原生的type创建,而是会调用MyMeta 的__call__
运算符重载。
class = type(classname, superclasses, attributedict)
# 变为了
class = MyMeta(classname, superclasses, attributedict)
举例代码如下:
class MyType(type):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
print("this is my type init")
def __new__(cls, *args, **kwargs):
new_cls = super().__new__(cls, *args, **kwargs)
print("this is my type new")
return new_cls
def __call__(self, *args, **kwargs):
print("this is my type call")
# 调⽤⾃⼰的那个类 __new__ ⽅法去创建对象
empty_object = self.__new__(self)
# 调⽤你⾃⼰的__init__ ⽅法取初始化
self.__init__(empty_object, *args, **kwargs)
return empty_object
class Foo(object, metaclass=MyType):
def __init__(self, name):
self.name = name
print("this is Fool init")
def __new__(self, *args, **kwargs):
print("this is Foo new!")
return object.__new__(self)
def __call__(self, * args, ** kwargs):
print("this is Foo call!")
v1 = Foo("Liverpool")
v1() # 调用的是v1中的__call__方法
'''输出如下:
this is my type new
this is my type init
this is my type call
this is Foo new!
this is Fool init
this is Foo call!
'''
对上述代码进行分析:首先Foo("Liverpool")
,调用是MyType
这个所自定义的元类,但是这个MyType
是由于type
这个原始类所继承定义的,所以需要调用type
这个类所定义的__call__
函数,但是MyType
这个所自定义的元类已经重载了type
类所定义的__new__
方法和__init__
方法,所以先调用MyType
这两个方法所创造出MyType
这个元类对象,然后在执行MyType
所定义的__call__
函数,用来生成Foo
这个类,所定义的初始化方法都是来自Foo
类自己所重载的__new__
方法和__init__
方法。
v1()
:表示执行的是v1这个对象实例的__call__
方法,也就是Foo
所定义的__call__
方法。
2.2.4 元类的应用
首先我们要明确一点,类都是由元类创建的,并且元类都是由type
创建的,但是为了区分可以把类说成由metaclass
这个关键字所对应的的元类创建的。如果某一个类是继承某个类,父类是由metaclass
创建的,那么该类就是由metaclass
所定义的 元类来创建的。
from wtforms import Form
from wtforms.fields import simple
class LoginForm(Form):
name = simple.StringField(label='⽤户名', render_kw={'class': 'form-control'})
pwd = simple.PasswordField(label='密码', render_kw={'class': 'form-control'})
form = LoginForm()
print(form.name) # 类变量
print(form.pwd) # 类变量
首先form
这个实例对象,是由LoginForm
这个类所创建的,LoginForm
这个类是继承来自Form
这个类,所以接下来我们分析Form
的源代码如下:
class Form(BaseForm, metaclass=FormMeta):
pass
可以比较明确的看出,Form
这个类是由BaseForm
这个类继承而来,FormMeta
这个元类创建的,继续分析FormMeta
这个元类
class FormMeta(type):
def __init__(cls, name, bases, attrs):
type.__init__(cls, name, bases, attrs)
cls._unbound_fields = None
cls._wtforms_meta = None
def __call__(cls, *args, **kwargs):
if cls._unbound_fields is None:
fields = []
for name in dir(cls):
if not name.startswith("_"):
unbound_field = getattr(cls, name)
if hasattr(unbound_field, "_formfield"):
fields.append((name, unbound_field))
# We keep the name as the second element of the sort
# to ensure a stable sort.
fields.sort(key=lambda x: (x[1].creation_counter, x[0]))
cls._unbound_fields = fields
# Create a subclass of the 'class Meta' using all the ancestors.
if cls._wtforms_meta is None:
bases = []
for mro_class in cls.__mro__:
if "Meta" in mro_class.__dict__:
bases.append(mro_class.Meta)
cls._wtforms_meta = type("Meta", tuple(bases), {})
return type.__call__(cls, *args, **kwargs)
可以看出FormMeta
是个由type创建的元类。
所以分析上述代码可以得出:LoginForm
其实是由FormMeta
创建的。创建LoginForm
类时,会执⾏FormMeta
的__new__
和__init__
(是执行了type
元类的__call__
方法,调用FormMeta
重载的__new__
和__init__
方法),内部在类中添加了两个类变量 _unbound_fields
和_wtforms_meta
;form = LoginForm()
会调用LoginForm
类去创建对象。会调用FormMeta.__call___
⽅法 。会调用LoginForm
中的__new__
方法去创建对象,__init__
去初始化对象。
2.2.5 用元类定义单例模式
class SingletonType(type):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
cls.instance = None
def __call__(cls, *args, **kwargs):
# 1判断是否有对象, 有不创建,没有才创建
if not cls.instance:
cls.instance = cls.__new__(cls)
# 2 调用自己的类进行初始化
cls.__init__(cls.instance, *args, **kwargs)
return cls.instance
class Singleton(object, metaclass=SingletonType):
pass
class Foo(Singleton):
pass
v1 = Foo()
v2 = Foo()
print(v1)
print(v2)