python的学习之旅---面向对象


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)
View Code

面向对象的进阶

多态

对象在接受数据的时候会忽略 数据类型

封装

封装就是把属性和方法 放入一个容器里装起来

私有属性 私有方法

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方法

优质内容筛选与推荐>>
1、【python】-迭代器,生成器
2、没有比笑着活过,更通达更通透的活法了
3、跟着"脑袋"学做编译器
4、自定义日历
5、Spring 梳理 - JavaConfig实战(spring MVC)-原创


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn