1面向过程编程
固定的目的 固定的结果
从头到尾把要执行的步骤堆积出来就好了
2面向对象编程
有一个抽象的过程
上帝视角:结果不能预测
第一步 认识类
类的定义
class 类名:
静态属性 = '值'
def 方法(self):
pass
#类:静态属性 动态属性
#类可以调用静态属性
#类可以查看动态属性 却必须要带上具体的对象参数才能调用动态属性
1 class Person: 2 rol = '人' #数据属性、静态属性、类属性 3 country = '中国' 4 def __init__(self,name,age,life_value): #初始化方法 5 # self.__dict__['name'] = name 6 self.name = name #属性、对象属性 7 self.theage = age 8 self.life_value = life_value 9 self.aggr = 200 10 def attack(self): #函数属性、动态属性、方法 11 #self只是一个形式参数,可以叫其他名字,但正常没人会这样 12 #self是水性杨花,那个对象调这个方法,self就是那个对象 13 print('attack方法被%s执行了'%self.name)
对象
对象可以有自己的对象属性,可以调用类的方法
对象 = 类名() 实例化
对象.静态属性 ----------------- 获取类的静态属性
对象.属性 ----------------------------- 说的是__init__的里面属性
self.name = name #属性、对象属性
self.theage = age
self.life_value = life_value
对象.方法 #可以调用不能执行 必须加括号才能执行
对象.方法() 这种形式的本质是 类.方法(对象)
对象.方法() 仅仅是 简写
1 class Dog: 2 def __init__(self,name,type): 3 self.name = name 4 self.dog_type = type 5 self.life_value = 2000 6 7 def bite(self,name): 8 print('%s咬了%s'%(self.name,name)) 9 10 旺财 = Dog('旺财','土狗') 11 #使用init去进行属性的初识化 12 #1.规范所有的对象都拥有一些基础的属性 13 #2.方便
第二部 认识对象 对象是基于类实例化出来的。是有血有肉有属性的
类加上括号的过程: 我们把类加上加上括号产生对象叫做实例化
1.先创建了一个对象 self = {}
2.才执行初始化方法__init__,同时把创建的对象扔到了__init__参数里
#类有属于自己的命名空间
#对象也是
#类不可以调用对象的属性
#对象在寻找属性的时候,是先找自己名称空间的,找不到就找类名称空间里的.
类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象实例化后相同的功能,但是绑定到不同的对象就是不同的绑定方法
强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)
属性修改
一说静态说行就是类属性
对于任何数据类型(列表,字符串,数字)的静态属性:他的修改操作尽量用类名
尤其是对于不可变数据类型:修改必须用类名
类和对象都可以使用--- 名称.属性=变量 的方式修改自己的属性
对象还可使用 点__dict__['name']='sobey' 来修改属性 但是 类不可以
第三部分继承与派生
什么是继承
继承指的是类与类之间的关系,是一种什么是什么的关系,功能之一就是用来解决代码重用问题
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
继承
子类继承父类的方法和属性
class A: tag="123" __name="xiaoming" def foo(self): print(self.__name) class B(A): def ppp(self): print("b") b=B() b.foo() print(b.tag,"123123123")
多继承
1 class Water1: #定义父类 2 pass 3 4 class Water2: #定义父类 5 pass 6 7 class coke( Water1): #单继承,基类是ParentClass1,派生类是SubClass 8 pass 9 10 class feta(Water1,Water2): #python支持多继承,用逗号分隔开多个继承的类 11 pass
coke.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.coke'>,) feta.__bases__ (<class '__main__.Water1'>, <class '__main__.Water2'>)
经典类和新式类
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。 他提供了双下方法
经典类和新式类的区别 1、关于基类 : 新式类默认继承object 2、关于在子类中执行父类的方法:新式类有super,经典类只能用指名道姓 3、关于多继承:新式类 广度优先(mro),经典类:深度优先 在py3没有经典类;在py2里经典类和新式类共存 关于继承: 子类继承父类 子类的对象调用方法,优先在子类中找,如果子类中有,就执行子类中的 如果子类中没有,就执行父类的 多个父类以广度优先为准 关注self到底是哪个类的实例化
派生
子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
super()方法
super代表的是父类 使用super比指名道姓的好处是 不用再后面的方法内传入self
1 class A: 2 3 def foo: print("A") 4 5 class B(A): 6 7 def foo(self) : 8 9 super().foo 对象内部调用 super方法一 10 11 super(B,self).foo 对象内部调用 super方法二 12 13 print("B") 14 15 b=B() 16 super(B,b).foo 外部调用super方法
第四部分 组合
#组合 —— 面向对象的一种功能
#什么有什么的关系
组合的本质是实例化一个对象,然后将对象作为另外一个对象的属性添加进去
1 #组合例二: 2 #人狗大战 3 #人 4 #武器:伤害、属性 5 class Weapon: 6 def __init__(self,aggr,name,money): 7 self.aggr = aggr 8 self.name = name 9 self.money = money 10 11 def kill(self,dog_obj): 12 print('%s武器暴击%s,伤害%s'%(self.name,dog_obj.name,self.aggr)) 13 dog_obj.life_value -= self.aggr 14 15 class Dog: 16 def __init__(self, name, type, aggr): 17 self.name = name 18 self.dog_type = type 19 self.aggr = aggr 20 self.life_value = 2000 21 22 def bite(self, person_obj): # self==egg,person_obj=alex 23 # 属性的变化 24 print('%s咬了%s' % (self.name, person_obj.name)) 25 person_obj.life_value -= self.aggr 26 27 class Person: 28 rol = '人' # 数据属性、静态属性、类属性 29 country = '中国' 30 31 def __init__(self, name, age, life_value): # 初始化方法 32 self.name = name # 属性、对象属性 33 self.theage = age 34 self.life_value = life_value 35 self.aggr = 1 36 37 def attack(self, dog_obj): # 函数属性、动态属性、方法 38 print('%s攻击了%s' % (self.name, dog_obj.name)) 39 dog_obj.life_value -= self.aggr 40 41 alex = Person('alex', 38, 500) 42 egg = Dog('egon', '二哈', 20) 43 alex.money = 2000 44 knife = Weapon(200,'杀猪刀',1900) 45 if alex.money > knife.money: 46 alex.money -= knife.money 47 alex.weapon = knife 48 49 print(egg.life_value) 50 alex.weapon.kill(egg) 51 print(egg.life_value)
面向对象的进阶
多态
对象在接受数据的时候会忽略 数据类型
封装
封装就是把属性和方法 放入一个容器里装起来
私有属性 私有方法
class A: __NAME="xiaoming" 私有属性 def foo(self): print(self.__name)
def __foo2(self): 这个是私有方法
print("2222")
A.__NAME 是调不到的
私有属性和私有方法无法直接在类外调用 但是类的内部可以调用
为什么私有方法无法在这调用呢?
因为在本质是私有方法存在{'_A__NAME':'xiaoming'} __dict__中的key 不是__NAME而在类中调用__NAME的时候 自动给你转换成了_A__NAME
如果你实在想在外部查看私有属性是可以的 _类名__名字
a=A()
a.foo()
print(b._A__name,'zhoushuo')
A._A__NAME 是可以调到的 #不合法
私有属性和方法不能被继承
静态属性的修改,和查看
我们知道 我们有一种 _类名__属性名 的方式是可以查看和修改静态属性的 但这不是一种合规的操作.
我理解的继承 是可以把父类的 属性名 和属性方法 实例化的时候 放入自己的__dict__内
所以我们要从类的内部修改,和查看,这可以通过定义内部方法的方式实现
1 class A: 2 def __init__(self,name): 3 self.__name=name 4 @property 5 def name(self): 6 return self.__name 7 @name.setter 8 def name(self,new_name): 9 self.__name=new_name 10 a=A("alex") 11 print(a.name) 12 a.name="alex_sb"
目的:希望属性不能从外部修改所以设置了私有属性
又希望可以从外部能查看 所以设置同名的方法(函数)并使用@property.
@property 装饰器的作用是把类的方法伪装成属性,调用的时候不用加()
@方法名.setter 提供一种方法可以在设置方法的时候触发函数
a.name="alex_sb" 这样我就可以通过给name赋值操作来从类的内部修改__name.
@name.setter 使用的时候需要 三红一致
那这么做的意义是什么呢?
我们知道 如果我们需要修改类的静态属性 仅仅需要.name="123" 就可以修改.
那么这样我们有没有方法给这种修改增加更多的逻辑,通过 @name.setter我们可以给修改添加跟多的逻辑.
类中的装饰器
issubclass(子类,父类)
isinstance(对象,类名) 判断对象是不是这个类的实例化对象
反射
我认为反射的本质是根据字符串从名称空间中拿到对应名称的地址
使用的是跟用对象取属性一样
getattr(对象,属性名/方法)
hasattr(对象,属性名/方法) hasattr() 函数用于判断对象是否包含对应的属性。
setattr(对象,“对象属性名”,“对象属性值”) 可以给对象添加属性 方法
delattr(对象,“方法属性名”,方法)
不过添加方法在调用的时候会报错 没有传入self
双下方法
__call__ 对象加()后就会执行__call__方法
__new__ 构造方法 捏小人方法
创建对象 __new__方法需要return的是一个对象(当然这个对象,可以是任意的对象,不过通常是return父类__new__方法创建的对象.你也可以return一个其他对象,那么接下来执行__init__的时候就执行的是该对象的__init__方法)
单例模式.单例模式是无论怎么实例化,实例化出来的对象都是一个.
实现的原理就是
class Singleton(object): _instance = None def __new__(cls, *args, **kw): if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kw) return cls._instance
object=super(Singleton, cls) 等于基类
作用 依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
首先我们来看一下第一个功能,具体我们可以用int来作为一个例子: 假如我们需要一个永远都是正数的整数类型,通过集成int,我们可能会写出这样的代码。 class PositiveInteger(int): 我曹,还可以继承一个int类,继承整数类 def __init__(self, value): super(PositiveInteger, self).__init__(self, abs(value)) i = PositiveInteger(-3) print i class PositiveInteger(int): def __init__(self, value): super(PositiveInteger, self).__init__(self, abs(value)) i = PositiveInteger(-3) print i 但运行后会发现,结果根本不是我们想的那样,我们任然得到了-3。这是因为对于int这种 不可变的对象,我们只有重载它的__new__方法才能起到自定义的作用。 这是修改后的代码: ------------------------------------------------------------------- class PositiveInteger(int): def __new__(cls, value): return super(PositiveInteger, cls).__new__(cls, abs(value)) i = PositiveInteger(-3) print i class PositiveInteger(int): def __new__(cls, value): return super(PositiveInteger, cls).__new__(cls, abs(value)) i = PositiveInteger(-3) print i 通过重载__new__方法,我们实现了需要的功能。 重构了对象
__init__ 初始化方法 穿衣服方法 给对象添加属性
__str__ "%s" %s 黏贴
__reper__ "%r" %r 会显示拼进来的东西真实的样子
__len__ len()
__hash__
__eq__ 执行 == 的时候是执行eq方法