目录python
类即类别、种类,是面向对象设计最重要的概念,对象是属性与方法的结合体,而类则是一系列对象类似的属性与方法的高度归纳.即类是把类似事物进行抽象,而对象的一个具体的实例.app
在Python里面,任何都是类,str等类型也是一种类.ssh
在程序代码里面,咱们必须对事物进行建模,抽象出它的属性(特征,好比美丑等等)与方法(动做等动态行为),而后才能创建一个类;有了一个类以后,咱们才能创建相关的对象,即实例函数
class Dog(object): ##经过class方法能够建立一个类 def __init__(self, name, speice, master, age): ##赋予该类属性 self.name = name self.speice = speice self.master = master self.age = age def dog_bark(self): ##赋予方法 print("%s正在汪汪汪....." %self.name) def eat_food(self): ##必须写self这种形参,关联类 print("%s正在吃饭"%self.name) dog_1 = Dog("旺财", "哈士奇", "Jack", 7) ##实例化一个对象出来 print(dog_1.name) dog_1.dog_bark() ##经过"."来调方法和属性 旺财 旺财正在汪汪汪..... print(dog_1.__dict__) ##能够打印出对象的属性字典,另外类里面并无方法,它须要到类里面调用 print(Dog.__dict__) ##打印Dog类的属性字典 {'name': '旺财', 'speice': '哈士奇', 'master': 'Jack', 'age': 7} {'__module__': '__main__', '__init__': <function Dog.__init__ at 0x0000027E895CCF28>, 'dog_bark': <function Dog.dog_bark at 0x0000027E895D6048>, 'eat_food': <function Dog.eat_food at 0x0000027E895D60D0>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None} dog_1.name = "二哈" print(dog_1.__dict__) ##能够这样修改属性值,而若是在类里面找不到就会向上找,但不会出类的范围; ##"__dict__"方法是调出对象的属性字典 {'name': '二哈', 'speice': '哈士奇', 'master': 'Jack', 'age': 7}
#python为类内置的特殊属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类全部父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中) ###__init__方法 # 一、该方法内能够有任意的python代码 # 二、必定不能有返回值 ##当咱们创建对象时,就会触发__init__方法
继承是一种建立新类的方式,新类能够继承一种基类(父类),在Python里面能够继承多个类;新建的类又叫作派生类或子类.在Python里面class创建的类,也继承于一个叫作“object”的基类.咱们可使用继承来减小重用性,使得代码量减小.工具
class Create(object): ##建立一个基类 def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): ##经过这个方式,继承基类 dog = Dog("二哈", "哈士奇", 5) dog.sleep() 二哈 is sleeping!
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看全部继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类;显式地声明继承object的类,以及该类的子类,都是新式类
在python3中,不管是否继承object,都默认继承object,即python3中全部类均为新式类this
然子类也能够添加本身新的属性或者在本身这里从新定义这些属性(不会影响到父类),须要注意的是,一旦从新定义了本身的属性且与父类重名,那么调用新增的属性时,就以本身为准了设计
class Create(object): def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): def __init__(self, name, master, age): ##覆盖了原来的 self.name = name self.master = master self.age = age def eat_food(self): print("%s的狗狗正在吃饭" %self.master) dog = Dog("金毛", "Hermaeus", 15) dog.eat_food() print(dog.master)
在一个类中以另一个类的对象做为数据属性,称为类的组合代理
class Hand(object): pass class Head(object): pass class Body(object): pass class People(object): def __init__(self): self.hand = Hand() ##即把其余类导入进来 self.head = Head() self.body = Body()
接口指的是本身提供给使用者来调用本身功能的方式\方法\入口code
接口提取了一群类共同的函数,能够把接口当作一个函数的集合;而后让子类去实现接口中的函数。orm
这么作的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么全部的这些类产生的对象在使用时,从用法上来讲都同样。
归一化的好处在于:
抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
import abc ##调用该方法实现抽象类 class All_file(metaclass=abc.ABCMeta): @abc.abstractmethod def read(self): pass @abc.abstractmethod def write(self): pass class Disk(All_file): def read(self): print('disk read') def write(self): print('disk write') class Cdrom(All_file): def read(self): print('cdrom read') def write(self): print('cdrom write') class Mem(All_file): def read(self): print('mem read') def write(self): print('mem write') m1=Mem() m1.read() m1.write() mem read mem write
当类是经典类时会遵循深度优先;是新类是会遵循广度优先
对于你定义的每个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的全部基类的线性顺序列表
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): pass print(F.__mro__)
那么就会产生一个和下列同样的MRO列表,查找的顺序是按着从左到右实现的,而子类会先于父类被检查;若是有多个父类会根据它们在列表中的顺序被检查;当存在两个合法的选择,选择第一个父类
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
class Create(object): def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): def __init__(self, name, speice, age, master): Create.__init__(self, name, speice, age) ##直接经过名字引用,须要self参数 self.master = master def eat_food(self): print("%s的狗狗正在吃饭" %self.master) dog = Dog("二哈", "哈士奇", 18, "Hermaeus") dog.sleep()
class Create(object): def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): def __init__(self, name, speice, age, master): super().__init__(name, speice, age) ##经过super()来调用,可是绝对不能有self self.master = master def eat_food(self): print("%s的狗狗正在吃饭" %self.master) dog = Dog("二哈", "哈士奇", 18, "Hermaeus") dog.sleep()
在面向对象方法中通常是这样表述多态性:向不一样的对象发送同一条消息,不一样的对象在接收时会产生不一样的行为(即方法)。也就是说,每一个对象能够用本身的方式去响应共同的消息。所谓消息,就是调用函数,不一样的行为就是指不一样的实现,即执行不一样的函数;分为静态多态和动态多态.
>>> class Cat(Animal): #属于动物的另一种形态:猫 ... def talk(self): ... print('say miao') ... >>> def func(animal): #对于使用者来讲,本身的代码根本无需改动 ... animal.talk() ... >>> cat1=Cat() #实例出一只猫 >>> func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能 say miao
#其实这仅仅这是一种变形操做且仅仅只在类定义阶段发生变形 #类中全部单下划线开头的名称如_x在约定上被认为是封装,让人们在使用的过程当中不要调用,可是实际上没有任何用 class A: _N=0 #约定不要使用 def __init__(self): self._X=10 def _foo(self): print('from A') def bar(self): self._foo() #这种,在外部是能够经过_x这个名字访问到
#其实这仅仅这是一种变形操做且仅仅只在类定义阶段发生变形 #类中全部双下划线开头的名称如__x都会在类定义时自动变造成:_类名__x的形式: class A: __N=0 #类的数据属性就应该是共享的,可是语法上是能够把类的数据属性设置成私有的如__N,会变形为_A__N def __init__(self): self.__X=10 #变形为self._A__X def __foo(self): #变形为_A__foo print('from A') def bar(self): self.__foo() #只有在类内部才能够经过__foo的形式访问到. #A._A__N是能够访问到的, #这种,在外部是没法经过__x这个名字访问到
封装的真谛在于明确地区份内外,封装的属性能够直接在内部使用,而不能被外部直接使用,然而定义属性的目的终归是要用,外部要想用类隐藏的属性,须要咱们为其开辟接口,让外部可以间接地用到咱们隐藏起来的属性
封装数据:将数据隐藏起来这不是目的.隐藏起来而后对外提供操做该数据的接口,而后咱们能够在接口附加上对该数据操做的限制,以此完成对数据属性操做的严格控制
封装方法:目的是隔离复杂度,让程序的一些细节不须要被使用者知道
在导入模块的过程当中,from module import *时不能被导入,可是你from module import _private_module依然是能够导入的
property是一种特殊的装饰器,使用它时会执行一段功能(函数)而后返回值
class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property def bmi(self): return self.weight / (self.height**2) p1=People('Hermaeus',60,1.7) print(p1.bmi)
将一个类的函数定义成特性之后,对象再去使用的时候obj.name,根本没法察觉本身的name是执行了一个函数而后计算出来的,这种特性的使用方式遵循了统一访问的原则
绑定到类的方法:用classmethod装饰器装饰的方法
为类量身定制,自动将类看成第一个参数传入(其实对象也可调用,但仍将类看成第一个参数传入)
绑定到对象的方法:没有被任何装饰器装饰的方法
为对象量身定制,自动将对象看成第一个参数传入(属于类的函数,类能够调用,可是必须按照函数的规则来,没有自动传值那么一说)
class Room(object): tag=1 def __init__(self,name,owner,width,length,heigh): self.name=name self.owner=owner self.width=width self.length=length self.heigh=heigh @classmethod def tell_info(cls,x): print(cls) print('-->',cls.tag,x) Room.tell_info(10) <class '__main__.Room'> --> 1 10
不与类或对象绑定,类和对象均可以调用,可是没有自动传值那么一说;就是一个普通工具而已
class Room(object): tag=1 def __init__(self,name,owner,width,length,heigh): self.name=name self.owner=owner self.width=width self.length=length self.heigh=heigh @staticmethod ##变成一个独立的方法 def get_area(x, y): res = x*y print("Area is %s" %res) Room.get_area(2, 3) Area is 6
isinstance(obj,cls)判断obj是不是类cls的对象
issubclass(sub,super)判断sub类是不是super类的派生类
############ class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) ############ class Func(object): pass class Func1(Func): pass print(issubclass(Func1, Func)) True True
经过字符串的形式操做对象相关的属性.Python中的一切事物都是对象(均可以使用反射)
class Dog(object): def __init__(self, name, master, species): self.name = name self.master = master self.species = species def dog_bark(self): print("%s is barking!" %self.name) def eat_food(self): print("%s is eating!" %self.name) dog = Dog("二哈", "Hermaeus", "哈士奇") #####hasattr(object, attr)######### ##判断在对象里是否有某属性 print(hasattr(dog, "name")) True #####getattr(object, name, default=None)######### ##获得对象里的某属性,若是没有返回default print(getattr(dog, "name")) print(getattr(dog, "afjaljf", "没有")) 二哈 没有 #####getattrsetattr(x, y, v)######### ##设置属性 setattr(dog, "hobby", "拆家") print(dog.__dict__) {'name': '二哈', 'master': 'Hermaeus', 'species': '哈士奇', 'hobby': '拆家'} #####delattr(x, y)######### ##删除某属性 delattr(dog, "name") print(dog.__dict__) {'master': 'Hermaeus', 'species': '哈士奇', 'hobby': '拆家'}
若是须要使用该方法的对象文件就是本身,那么能够调用sys模块里面的modules方法
import sys def func1(): print("From func1") def func2(): print("From func2") this_module = sys.modules[__name__] print(hasattr(this_module, "func1")) True
import importlib importlib.import_module("名字")
class Foo(object): x = 1 def __init__(self, y): self.y = y def __getattr__(self, item): print("From __getattr__") def __setattr__(self, key, value): print("From __getattr__") def __delattr__(self, item): print("From __delattr") ##__setattr__添加/修改属性会触发它的执行 ## 由于你重写了__setattr__,凡是赋值操做都会触发它的运行,那么根本没赋值,除非你直接操做属性字典,不然永远没法赋值 ##self.__dict__[key] = value ===> 会把值直接添加到对象的属性字典 ##__delattr__删除属性的时候会触发 ##self.__dict__.pop(item) ===> 直接删除对象字典里的值 ##__getattr__只有在使用点调用属性且属性不存在的时候才会触发
经过继承派生的手段,基于标准数据类型来定制咱们本身的数据类型,新增或者改写方法
class List(list): def append(self,p_object): if isinstance(p_object, int): raise TypeError("不支持int类型") #raise方法能够抛出错误 super().append(p_object) s1 = List(("a", 'b', 'c')) print(s1) s1.append(12) ##报错 ………………………………………………………………………………………… raise TypeError("不支持int类型") TypeError: 不支持int类型
受权是包装的一个特性, 包装一个类型一般是对已存在的类型的一些定制,这种作法能够新建,修改或删除原有产品的功能.其它的则保持原样。受权的过程,便是全部更新的功能都是由新类的某部分来处理,但已存在的功能就受权给对象的默认属性.而实现受权的关键点就是覆盖__getattr__方法
import time class HandleFile(object): def __init__(self, filename, mode, encoding = "UTF-8"): self.file = open(filename, mode) def write(self, context): t = time.strftime("%Y-%m-%d %T") self.file.write("%s %s" %(t, context)) def __getattr__(self, item): ##覆盖了原来的方法,使得没有的方法到open里面找 return getattr(self.file, item) f1 = HandleFile("b.txt", "w") f1.write("Hello, World!") f1.close()
当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程当中抛出异常AttributeError
class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print('执行的是我') def __getattribute__(self, item): print('不论是否存在,我都会执行') raise AttributeError('哈哈') ##会执行一次__getattr__ f1=Foo(10) f1.x f1.xxxxxx
描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
而其又被分为:
数据描述符:至少实现了__get__()和__set__()
非数据描述符:没有实现__set__()
class Str(object): def __get__(self): print("From __get__") def __set__(self, instance, value): print("From __set__") def __delete__(self, instance): print("From __delete__") class People(object): name = Str() ##在其余类里面被当作属性时,才有被调用,name被Str类代理了 def __init__(self, name): self.name = name p1 = People("qq") From __set__ ##触发了Str类里面的__set__
描述符自己应该定义成新式类,被代理的类也应该是新式类
必须把描述符定义成这个类的类属性,不能为定义到构造函数中
要严格遵循该优先级,优先级由高到底分别是
类属性
数据描述符
实例属性
非数据描述符
找不到的属性触发__getattr__()
一个静态属性property本质就是实现了get,set,delete三种方法
class Foo: @property def AAA(self): print('get的时候运行我啊') @AAA.setter def AAA(self,value): print('set的时候运行我啊') @AAA.deleter def AAA(self): print('delete的时候运行我啊') ##AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
__setitem__,__getitem__,__delitem__
class Foo(object): def __getitem__(self, key): print('__getitem__', key) def __setitem__(self, key, value): print('__setitem__', key, value) def __delitem__(self, key): print('__delitem__', key) obj = Foo() ##类字典的操做将触发这些 result = obj['k1'] # 自动触发执行 __getitem__ obj['k2'] = 'Hermaeus' # 自动触发执行 __setitem__ del obj['k1'] # 自动触发执行 __delitem__
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
若是__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,不然抛出异常
formated_time = { "YY":"{obj.year}-{obj.month}-{obj.date}", "MM":"{obj.year}/{obj.month}/{obj.date}", "DD": "{obj.year}:{obj.month}:{obj.date}" } class Time(object): def __init__(self, year, month, date): self.year = year self.month = month self.date = date def __str__(self): return "From __str__" def __repr__(self): return "From __repr__" def __format__(self, format_spec): if not format_spec or format_spec not in formated_time.keys(): format_spec = "DD" res_spec = formated_time[format_spec] return res_spec.format(obj = self) try_time = Time(2018, 5, 23) print(try_time) print(try_time.__format__("YY")) From __str__ 2018-5-23
__slots__是一个类变量,其中变量值能够是列表,元祖,或者可迭代对象,也能够是一个字符串(意味着全部实例只有一个数据属性);使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每一个实例的是独立的);字典会占用大量内存,若是你有一个属性不多的类,可是有不少实例,为了节省内存可使用__slots__取代实例的__dict__
class Foo(object): __slots__ = ["name", "age"] f1 = Foo() f1.name = "Hermaeus" f1.age = 19 print(f1.__dir__()) print(f1.__slots__) ##对象里面没有了__dict__,只有了__slots__,这样有利于减小内存负担 ['__module__', '__slots__', 'age', 'name', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__'] ['name', 'age']
##有了__next__和__iter__,即是一个迭代器了 class func(object): def __init__(self, x): self.x = x def __iter__(self): return self def __next__(self): self.x += 1 return self.x test_func = func(2) print(test_func.__next__()) print(test_func.__next__()) print(test_func.__next__()) print(test_func.__next__())
class Fib(object): def __init__(self): self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): self.a , self.b = self.b , self.a + self.b return self.a f1 = Fib() print(f1.__next__()) print(f1.__next__()) print(f1.__next__())
class Func(object): """ The Infomation of Func""" pass print(Func.__doc__) ##获取备注信息 from lib.aa import C obj = C() print obj.__module__ ##获得是那个模块里的 print obj.__class__ ##获得是那个类里的 The Infomation of Func lib.aa 即:输出模块 lib.aa.C 即:输出类
析构方法,当对象在内存中被释放时,自动触发执行
class Foo(object): def __del__(self): print("Over") f1 = Foo() ##不过怎么样,只要一释放内存,就会触发__del__
”with open(文件) as f“,又叫作上下文管理协议,为了让一个对象能使用with语句,必须在对象的类里面申明__enter和__exit__方法
class MyOpen(object): def __init__(self, filename, mode, encoding = "UTF-8"): self.filename = filename self.mode = mode self.encoding = encoding def __enter__(self): ##出现with,则触发__enter__,有返回值就赋予给as申明了的变量 self.f = open(self.filename, self.mode, encoding = self.encoding) return self.f def __exit__(self, exc_type, exc_val, exc_tb): ##with执行完以后,触发__exit__ self.f.close() ##exc_type ==>异常类型 exc_val ==>异常值 exc_tb ==>追溯信息 return True def __getattr__(self, item): ##避免找不到指定方法而触发默认的__getattr__ return self, item with MyOpen("b.txt", "r") as f: print(f.read())
在对象后面加括号执行
class Foo(object): def __call__(self, *args, **kwargs): print("Come from __call__") f1 = Foo() ##不能直接Foo(),不会执行 f1() Come from __call__
在Python里面一切皆对象,那么类调用的类咱们就叫作元类,那么默认的元类是type
class Foo(object): pass print(type(Foo))
能够直接使用type创建新类
##type(name, bases, dict) -> a new type def __init__(self, name, age): self.name = name self.age = age Foo = type("Foo", (object,), {"x":11, "__init__":__init__}) f1 = Foo("Hermaeus", 19) print(f1.__dict__) {'name': 'Hermaeus', 'age': 19}
本身创建元类
class MyType(type): def __init__(cls, x, y, z): print("Runing....") def __call__(self, *args, **kwargs): obj = self.__new__(self) ##创建一个空的对象 self.__init__(obj, *args, **kwargs) ##从新使用type return obj class Foo(metaclass=MyType): ## "metaclass="指定元类 def __init__(self, name): self.name = name f1 = Foo("Hermaeus") print(f1.name) Runing.... Hermaeus