python面向对象
面向对象的相关知识
面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
我们先搞清面向对象和现象过程的区别吧。
面向过程
做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如果出现情况B做什么处理。
如果问题规模小,可以步骤化,按部就班的处理。
面向对象
随着问题变得复杂,面向过程解决问题不再方便,人们将万事万物抽象为类,就是有共同特征的事物的集合。用计算机语言来描述,就是方法和属性的集合。
对象是类的具体对象,是一个实体。
面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
一些名词
方法:类中定义的函数。
实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
实例化:创建一个类的实例,类的具体对象。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
面向对象三要素
1.封装
组装:将数据和操作组装到一起
隐藏数据:对外只暴露一些接口,通过接口访问对象,库模块
2.继承
多复用,继承来的就不用自己写了
多继承少修改,使用继承来改变
3.多态
面向对象编程最灵活的地方,动态绑定
python类
定义类的两种方法:
第一种方法为通过传统的方法class定义类
第二种方法为通过type类实例化定义类
python class
class ClassName:
语句块
1.必须使用class关键字
2.类名必须用大驼峰命名3.
3.类定义完成后,就产生了一个类对象,绑定到了标识符ClassName上
class MyClass:
"""allocate_lock() -> lock object"""
x = "abc“
def foo(self) #类属性foo,也是方法
return "abc“
print(MyClass.x)
print(MyClass.foo)
print(MyClass.__doc__)
类对象及类属性
类对象,类的定义就会生成一个类对象
类属性,类定义中的变量和类中定义的方法都是类的属性
类变量,上例中x就是类MyClass的变量
foo是方法对象method,不是普通的函数对象function,他一般要求至少有一个参数,第一个参数可以是self(self 只是一个形参,惯用名称,可以更换),这个参数就留给对象自己,实例本身。
a= MyClass()#实例化
python__init__方法
MyClass()实际上调用的是__init__(self)方法,可以不定义,如果没有定义会在实例化后隐式调用。
作用:对实例进行初始化
class MyClass:
def __init__(self):
print(“test”)
print(MyClass)#不会调用
print(MyClass())#调用__init__
a = MyClass()#调用__init
python实例变量和类变量
class Person:
age = 3
def __init__(self,name):
self.name = name
#tom = Person("Tom",20)
tom = Person("Tom")
jerry = Person("Jerry")
print(tom.name,tom.age)
print(jerry.name,jerry.age)
print(Person.age)
#print(Person.name)
Person.age = 30
print(Person.age,tom.age,jerry.age)
实例变量是每一个实例自己的变量,是自己独有的,类变量是类的变量,是类的所有实例共享的属性和方法。
python类特殊属性
装饰类的方法
例子:给Person添加类name属性
类方法
class Person:
@classmethod
def class_method(cls):
print("class = {0.__name__} ({0})".format(cls))
cls.HEIGHT = 170
Person.class_method()
使用classmethod装饰
必须至少由一个参数,用来传入class本身,cls形参只要合法即可。
静态方法
class Person:
@staticmethod
def class_method(cls):
print("class = {0.__name__} ({0})".format(cls))
cls.HEIGHT = 170
Person.class_method()
使用static_method装饰
元类
元类是类的模板,是用来控制如何创建类的,正如类是创建对象的模板一样。
type()
class type(object):
def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
# (copied from class doc)
"""
pass
通过type(name,bases,dict)就可以创建出一个类,其中
name:相当于class name中name的一个标识,是一个类名的一个标识;
bases:相当于class name (A,B)中的类继承与谁,如此时类继承于A和B这两个类 ;
dict:相当于类属性,如类的方法和属性 。
元类创建__new__
在类的多继承过程中,可以采用一个类ModelMeta从type类继承过来,然后可以通过ModelMeta类实例化创建类。
class ModelMeta(type):
def __new__(cls, *args, **kwargs):
print("~~~~~~~~~~~~~~~~")
print("调用元类开始")
print(cls)
print(args)
print(kwargs)
print("~~~~~~~~~~~~~~~~~~~~~")
return super().__new__(cls,*args,**kwargs)
C = type('test',(),{'A':10})
A = ModelMeta('test1',(),{'A':10})
print(type(C))
print(C.__dict__)
print(type(A))
print(A.__dict__)
元类创建__new__和__init__冲突
class ModelMeta(type):
def __new__(cls, *args, **kwargs):
print("*********")
print("meta start")
print(cls)
print(args)
print(kwargs)
print("*********")
return super().__new__(cls,*args,**kwargs)
def __init__(self):
self.name = "tom"
C = type("test",(),{"A":10})
A = ModelMeta("test1",(),{"A":10})
# print(C.__name__)
# print(C.__dict__)
print(A.__name__)
print(A.__dict__
__new__在元类编程,类实例化类的时候,用new方法实例化一个类对象,而__init__普通类实例化对象初始化属性。
ModelMeta中如果不能直接从元类中继承,只能普通根类object以下的类中继承。
在元编程过程中,类只要从元编程构造时,都会调用new方法,定义继承时要明确指定从元类中继承。
普通继承的类是元类,new方法仅会继承,但不执行
继承通过metaclass=,叫元类继承,因此叫元编程,不仅仅会继承new方法,而且会执行new方法。
魔术
魔术:容器类操作
实现容器a[“a”],a[“a”]=12,
gititem:获取容器中的某个值
setitem:给容器设置某个值
missing:当容器中的key不存在时
dicta = {"a":1,"b":2,"c":3}
class B:
def __init__(self,dictobj):
self.d = dictobj
def __getitem__(self, item):
return self.d.get(item)
def __setitem__(self, key, value):
self.d[key]=value
b = B(dicta)
魔术:属性查找设置
getattr:查找属性时调用此方法
instance.dict instance.class.dict 继承的祖先类(直到object)的__dict__找不到调用__getattr__()
setattr:设置属性时调用此方法
class A:
def setattr(self,key,vaule):
self.dict[key] = value
魔术:描述器
get__类中调用别的类的对象,对外提供__get__方法,访问此类就会触发__get__方法。
set__当一个类用到了描述器,那么必然时类属性的某一值为描述器,但是实例再次设置同类一样的属性时,则触发描述器中set方法,类字典中加载此值,实例字典则不加载此值。
Python中,一个类实现了__get__、set__、delete__三个方法中的任何一个方法,就是描述器。 如果仅实现了__get__就是非数据描述符non-data descriptor 同时实现了__get__,__set__就是数据描述符data descriptor 如果一个类的类属性设置为描述器,那么它被称为owner属主。
描述器装饰器@staticmethod
class StaticMethod:
def __init__(self,fn):
self.fn = fn
def __get__(self, instance, owner):
return self.fn
class A:
def __init__(self,name):
self.name = name
@StaticMethod
def pint():
print("Test ok")
A.pint()
描述器装饰器@classmethod
import functools
class A:
def __init__(self,fn):
self.fn = fn
def __get__(self, instance, owner):
return functools.partial(self.fn,owner)
class B:
def __init__(self,b):
self.b = b
@A
def eat(cls,g): #eat = A(eat)= A.__init__(eat)===>eat(#此时eat函数已经将第一个参数固定未cls)
return g
print(B.eat("g"))