zoukankan      html  css  js  c++  java
  • 003_python对象

    day11 - day 13

        面向对象程序设计有三大特征:封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)

          封装(Encapsulation):类包含了数据和方法,将数据和方法放在一个类中就构成了封装

          继承(Inheritance):python支持多继续

          多态(Polymorphism):指一类事物有多种形态,比如动物类,可以有猫,狗,猪等等。(一个抽象类有多个子类,因而多态的概念依赖于继承)

    1. 类:抽象描述一类事物,是这一类事物共有的特征;对象:具体存在的事物,可以有很多个同类的事物;

    2.  class 类名():一般类名是大驼峰命名规则;类中的self代表对象本身,即是当前实例化对象;

    3. 类中的__init__(self,参数)方法

            1> 魔法方法,在实例化对象的同时,自动调用,做初始化的动作;

            2> 因为实例化的同时自动调用了这个方法,故实例化时就要传递这个方法的参数过来:实例名=类名(__init__方法的参数);

            3> 因为实例化的同时自动调用了这个方法,故实例化对象就拥有了__init__()定义的属性;

            4> 实例对象想使用一般的类方法的属性时,是实例化对象需要先调用该方法,之后才会拥有这个方法中的属性;

     1 class Person:
     2 
     3     id = '001'
     4 
     5     def __init__(self,name,sex,city,age=18):  # 实例化的同时,自动被调用,故实例化后,实例对象也就拥有了这些属性
     6         self.my_name = name
     7         self.my_sex = sex
     8         self.my_city = city
     9         self.my_age = age
    10 
    11     def set_info(self,work,salary): # 实例对象想拥有这个方法中的属性时,实例对象必须先调用这个方法,才能拥有这些属性
    12         self.my_work = work
    13         self.salary = salary
    14 
    15     def eat(self,food=None):
    16         print("我喜欢吃{}".format(food))
    17 
    18     def study(self,kill):
    19         print(f"我学习了{kill}。")
    20 
    21 
    22 ran = Person('ran','','中国')
    23 print(ran.my_name)
    24 # print(ran.my_work)  # 报错 AttributeError: 'Person' object has no attribute 'my_work'
    25 
    26 ran.set_info('测试','1W')  # 实例对象调用类方法
    27 print(ran.my_work)
    魔术方法

    4. 某个实例对象修改了类属性时,只影响它自己,其他实例对象调用该类属性时仍为原值;

    5.一般不建议在类的方法中,动态的增加属性,因为只有这个方法被调用后,这个属性才会存在,其它情况下去引用就会报错,规范的做法是在__init__()方法中定义属性;

     1 # 抽象描述 - 定义
     2 class Person:
     3 
     4     id = '001'
     5 
     6     def __init__(self,name,sex,city,age=18):
     7         self.my_name = name  # 给对象添加my_name属性,并给它赋值。
     8         self.my_sex = sex
     9         self.my_city = city
    10         self.my_age = age
    11 
    12     # 实例化对象的时候,对象是谁,self就是谁
    13     # 在定义类的时候,并不知道对象是谁,用self来统一表示对象
    14     def eat(self,food=None):
    15         print("我喜欢吃{}".format(food))
    16 
    17     def study(self,kill):
    18         print(f"我学习了{kill}。")
    19 
    20     def cooking(self,**menu):
    21         print(f"我会做{menu}。")
    22 
    23 
    24     def find_another_friend(self,has_friend,food=None):
    25         """
    26         年龄 > 18 ,以及 没有对象的,就找对象。否则就不找。
    27         :param has_friend: True或者False.True表示有对象。False表示没有对象
    28         :return:
    29         """
    30         if self.my_age >= 18 and has_friend is False:
    31             print("{} 需要找对象".format(self.my_name))
    32             # 告诉别人我喜欢吃什么
    33             self.eat(food)
    34             # 不建议。动态添加的属性,只有在调用此方法之后才会有。其它情况下如何去引用就会报错。
    35             # self.is_dog = True  # 在方法内部,给对象动态添加属性
    36 
    37         else:
    38             print("没有资格找对象。")
    39 
    40     def play(self,game):
    41         print(f"我会做{game}运动。")
    42 
    43 
    44 ran = Person('ran','','中国')  # 实例化:对象名 = 类名(),此处self指代的是ran
    45 ran.eat("臭豆腐")  # 实例调用类方法: 对象名.方法名()
    46 print(ran.id)   # 实例调用类属性
    47 print(ran.my_name)  # 实例调用实例属性
    48 ran.id = '001_ran'  # 实例修改类属性,但是只影响自己,不会影响其他对象的这个值
    49 print(f'ran修改了实类属性id的值:{ran.id}')
    50 
    51 
    52 bql = Person("冰淇淋", "", "新加坡")
    53 bql.find_another_friend(False,"榴莲")
    54 print(f'bql的类属性id值没有受影响:{bql.id}')
    类实例化

    6. 某个实例对象给自己增加了实例属性,则该属性仅是该实例拥有,其他实例对象无法使用;

     1 class Person:
     2 
     3     id = '001'
     4 
     5     def __init__(self,name,sex,city,age=18):
     6         self.my_name = name  # 给对象添加my_name属性,并给它赋值。
     7         self.my_sex = sex
     8         self.my_city = city
     9         self.my_age = age
    10 
    11     # 实例化对象的时候,对象是谁,self就是谁
    12     # 在定义类的时候,并不知道对象是谁,用self来统一表示对象
    13     def eat(self,food=None):
    14         print("我喜欢吃{}".format(food))
    15 
    16 ran = Person('ran','','中国')
    17 ran.height = 1.80
    18 print(f'ran的身高:{ran.height}')
    19 
    20 bql = Person("冰淇淋", "", "新加坡")
    21 print(f'bql的身高:{bql.height}')   # 报错,因为仅ran实例对象有这个属性height
    实例属性

     7. 实例属性:只有对象可以访问,类中定义是self.属性 = value,访问是 对象名.属性;

          类属性:类和实例都可以访问,类中定义是 属性 = value,访问是 类名.属性 或 对象名.属性;

          对象访问属性时,如果自己有就访问自己的,自己没有时,才会去访问类的;如果都没有,则会报错;

    8. 类属性怎么修改? 使用类方法装饰器 @classmethod,cls代表当前类,与实例方法的区别:

         1> 实例方法一般用 self 代表实例对象,一般是给实例对象调用的;

          2> 类方法@classmethod:一般用 cls 代表当前类,类和对象都可以调用,不过一般是类去调用;

          3> 静态方法@staticmethod:没有类方法或实例方法一样必传的self或cls,它就是普通的函数,只是定义在类里面,类和对象都可以调用;

     1 import random
     2 
     3 class Person:
     4 
     5     color = "黄种人"  # 类属性 = 值
     6 
     7     def __init__(self,name,sex,age,color):
     8         self.name = name
     9         self.sex = sex
    10         self.age = age
    11         self.color = color  # 对象的color属性
    12 
    13     @classmethod   # 类方法装饰器
    14     def update_class_color(cls):
    15         cls.color = "全世界的人"  # 修改了类属性color
    16         print(f'类的color为:{cls.color}')
    17 
    18     def study(self, kill):  # 实例方法
    19         print(f"我学习了{kill}。")
    20 
    21     def update_color(self):
    22         self.color = '中国人'
    23         print(f'对象的color为:{self.color}')
    24 
    25     @staticmethod
    26     def get_weather():
    27         weather = ["晴天", "小雪", "阴天", "小雨", "雷阵雨", "起风"]
    28         index = random.randint(0, len(weather) - 1)
    29         return weather[index]
    30 
    31 print(f'类的color:{Person.color}')
    32 Person.update_class_color()  # 类名.类方法()
    33 
    34 wh = Person('whm','',20,'黑皮肤')
    35 print(f'实例方法的color为:{wh.color}')
    36 
    37 print(Person.get_weather())  # 类调用静态方法
    38 print(wh.get_weather())   # 实例对象调用静态方法
    类方法_静态方法

    9. 私有化:

          1>  _属性/_方法:约定俗成的,通过一个下划线开头,意思就是别访问我,我是私有化,但实际是可以通过 对象. _属性/_方法 的方式访问,全靠自觉;

           2> __属性/__方法:深度私有化,不可以访问(通f过 对象.__属性/__方法 的方式访问不到),但是在类的内部是可以访问的,

                                           所有如果类内部定义了访问私有  属性的方法,可以通过调用这个方法,从而得到私有属性的值;

          3> _和__私有化方式不仅仅是在类属性和类方法中,同样在模块(.py)当中也同理, 模块内私有,仅想在模块内使用,其它模块导的时候,

               表示这些不想被外部访问;

     1 _hello = "world"   # 模块私有
     2 
     3 def __hello():  # 模块私有
     4     print("我不想其它的模块访问")
     5     
     6 class Person:
     7 
     8     __flag = True  # 深度私有属性
     9 
    10     def __init__(self, name, sex, city, age=18):
    11         self.my_name = name  # 给对象添加name属性,并给它赋值。
    12         self.my_sex = sex
    13         self.my_city = city
    14         self.my_age = age
    15         self.color = "中国人"  # 对象的color属性
    16         self._private_money = 2000
    17         self.__spri_money = 4000
    18 
    19     # 如果类内部定义了访问私有属性的方法,可以通过调用这个方法,从而得到私有属性的值
    20     def get_spri_money(self):
    21         print(self.__spri_money)  # 类内部可以访问
    22 
    23 
    24 wh = Person('whm','','中国')
    25 print(f'浅度私有:{wh._private_money}')  # 可以访问到
    26 print(f'深度私有:{wh.__spri_money}')  # 报错:AttributeError: 'Person' object has no attribute '__spri_money'
    私有化

    10. 什么情况下使用私有化?

           一般是实现大功能时,对外只需要知道该整体大功能,而对于里面的小功能方法对于使用来说不重要,不需要使用,此时这些小功能的方法就可以私有化;

    11. python模块中的 __all__ ,该变量的值是一个列表,存储的是当前模块A中一些成员,如属性,方法或者类的名称

           1> 当该模块A被其他模块B以 from 模块A import * 形式导入时,模块B只能使用__all__列表中指定的成员,未指定的成员是无法导入的;

           2> 若没有定义__all__,则会导入模块A内的所有公有属性,方法和类;

     moduleA.py模块代码如下:

     1 import random
     2 
     3 __all__ = ['say']
     4 
     5 def say():
     6     print("人生苦短,我学Python!")
     7 def CLanguage():
     8     print("C语言中文网:http://c.biancheng.net")
     9 def disPython():
    10     print("Python教程:http://c.biancheng.net/python")
    moduleA.py

    moduleB.py模块代码如下:

     1 import examp.moduleA as ma # 此时__all__不起作业
     2 ma.say()
     3 ma.CLanguage()
     4 ma.disPython()
     5 
     6 from examp import moduleA  # 此时__all__不起作业
     7 moduleA.say()
     8 moduleA.CLanguage()
     9 moduleA.disPython()
    10 
    11 from examp.moduleA import *  # 此时__all__起作业
    12 say()
    13 # CLanguage() # 报错 NameError,因为__all__未指定该方法,故这个方法在此不能被调用到
    14 # disPython() # 报错 NameError,因为__all__未指定该方法,故这个方法在此不能被调用到
    moduleB.py

    12.  继承:子类继承父类,就拥有了父类所有的属性和方法,除了私有化的;

          1> object是所有类的基类,python3默认所有类都会继承object;

          2> _属性/_方法: 子类可以继承,但是建议一般子类不调用;

          3> __属性/__方法:深度私有化,子类不可以继承;

          4> python可以多继承,语法 class 子类(父类1,父类2...);

          5> 子类想在父类的功能或属性以外,子类可以增加自己特色的属性和方法;

    13. 重写:子类在内部定义了一个与父类中同名的方法,即为重写;

            场景:子类想在父类原有功能的基础上,去优化或改变父类的方法,

           1> 不动父类的功能,只是增加一些额外的功能,即子类可以部分重写父类方法;

                 a> 在子类内部的与父类同名方法的内部,想调用父类同名的方法,直接使用self.同名方法()会报 递归错误,因为self代表的是子类;

                 b> 在子类内部的与父类同名方法的内部,想调用父类同名的方法,使用 super() 超类,super代表父类;

     1 class Father:
     2     def __init__(self,name,age):
     3         self.name = name
     4         self.age = age
     5 
     6     def ear_money(self,work):
     7         print(f"{self.name}通过{work}来挣钱。")
     8 
     9     def hobby(self,favirate):
    10         print("{} 的爱好是 {}".format(self.name,favirate))
    11 
    12 class Son(Father):
    13 
    14     def study(self,content): # 在父类的功能或属性外,添加属性子类自己的特色方法
    15         print("{}通过学习{}来提升自己。".format(self.name,content))
    16 
    17 
    18     def ear_money(self,work):  # 部分重写
    19         # 此时实例对象调用了自己的ear_money()方法,而不会调用父类的该方法。
    20         # 会报错 递归错误:RecursionError: maximum recursion depth exceeded
    21         # self.ear_money(work)
    22 
    23         # 在与父类同名方法内,想调用父类该同步方法
    24         super().ear_money(work) # 超类,super代表父类
    25         print(f'{self.name}通过投资理财再赚了2000块。')
    26 
    27 
    28 whm = Son('whm',20)
    29 whm.ear_money('python')  # 用的父类方法
    部分重写_超类

           2> 推翻父类的功能,重新写一遍,即子类可以完全重写父类方法,不用父类的代码;

                a> 子类完全重写父类同名方法时,方法的参数可以不一样,方法可以被正常调用;

                b> 但是不符合python的编码规范,会有提示: Signature of method 'Son.ear_money()' does not match signature of base method in class 'Father' ;

     1 class Father:
     2     def __init__(self,name,age):
     3         self.name = name
     4         self.age = age
     5 
     6     def ear_money(self,work):
     7         print(f"{self.name}通过{work}来挣钱。")
     8 
     9     def hobby(self,favirate):
    10         print("{} 的爱好是 {}".format(self.name,favirate))
    11 
    12 class Son(Father):
    13 
    14     def study(self,content): # 在父类的功能或属性外,添加属性子类自己的特色方法
    15         print("{}通过学习{}来提升自己。".format(self.name,content))
    16 
    17 
    18     def ear_money(self,work1,work2): # 完全重写
    19         # 虽然与父类同名,但是我要完全重写,不用父类的代码
    20         print(f'{self.name}通过{work1}和{work2}来赚米米。。')
    21 
    22 whm = Son('whm',20)
    23 
    24 whm.ear_money('搬砖','写作')
    完全重写_不规范

               c> 所以一般子类在重写父类方法时,规范的做法是参数保持一致;

     1 class Father:
     2     def __init__(self,name,age):
     3         self.name = name
     4         self.age = age
     5 
     6     def ear_money(self,work):
     7         print(f"{self.name}通过{work}来挣钱。")
     8 
     9     def hobby(self,favirate):
    10         print("{} 的爱好是 {}".format(self.name,favirate))
    11 
    12 class Son(Father):
    13 
    14     def study(self,content): # 在父类的功能或属性外,添加属性子类自己的特色方法
    15         print("{}通过学习{}来提升自己。".format(self.name,content))
    16 
    17     def ear_money(self,work): # 完全重写,符合规范
    18         # 虽然与父类同名,但是我要完全重写,不用父类的代码
    19         print(f'{self.name}通过{work}来赚米米,还帮助了更多人。')
    20 
    21 whm = Son('whm',20)
    22 whm.ear_money('开公司')  #用的子类完全重写的方法
    完全重写_规范

           3> 总结:子类调用方法时,自己有该方法时就调用用自己的,否则就会使用父类的该方法;

    14. 重载:python没有重载,因为重载的场景是 参数个数不一样时 或 参数类型不一样时,需要重载,但是对于python本来就支持不定长参数,而python传参时没有限制类型;

    15. isinstance(实例名,类名):判断某个对象,是否为类的实例

    16. 多态:一类事物有多种形态,如excel和word文档,都是文件,python是一门动态强数据性的语言,天生支持多态;

            1> 函数(obj:类型):如 函数(obj: int) 代表调用这个函数时,指示参入int类型的参数,但是不是说只能传入int,其他类型也是可以的;

            2> python不会限制传给函数参数的数据类型,不像其他语言都是申明定义好了具体的数据类型;

            3> 鸭子类型:不管是什么类对象,只要会叫,就认为是鸭子在叫,这种就叫鸭子类型

     1 class People:
     2     def run(self):
     3         print("人类在跑")
     4 
     5 class Dog(People):
     6     def run(self):
     7         print("狗在跑")
     8 
     9 class Cat(People):
    10     def run(self):
    11         print("猫在跑")
    12 
    13 class Car:
    14     def run(self):
    15         print("车在跑")
    16 
    17 # python: 函数参数不做类型限制,这里只是指示参入People类一样的数据类型,但不是说只能是这个类,只要对象有run方法的,就可以传入正常使用
    18 def who_can_run(obj: People):  # 鸭子类型:不管是什么类对象,只要会叫,就认为是鸭子在叫,这种就叫鸭子类型
    19     obj.run()
    20 
    21 # python 没有多态 、 处处皆多态 -- 鸭子类型(自行了解)
    22 mycar = Car()
    23 who_can_run(mycar)
    24 
    25 mycat = Cat()
    多态

    17.  python自省是获取对象的能力,而反射是操纵对象的能力;

           反射机制,利用字符串的形式在模块或对象中操作(查找/获取/删除/添加)成员,即在类定义之外,查找/获取/添加/删除属性,这些属性是在代码执行过程当中,动态操作属性;

          1> hasattr(类/对象, 属性):类/对象 是否有某个属性

          2> setattr(类/对象, 属性, 值):给类/对象 设置某个属性(有则修改,无则添加)

          3> getattr(类/对象, 属性):获取类/对象 某个属性的值,若类/对象没有该属性时,直接获取会报错 AttributeError

          4> delattr(类/对象, 属性):删除类/对象 某个属性

        PS:Python中使用delattr()和setattr()实现反射,而其他方法则属于自省

     1 class Person:
     2 
     3     def __init__(self, name, sex):
     4         self.my_name = name
     5         self.my_sex = sex
     6         self.color = "中国人"
     7 
     8     def update_color(self):
     9         self.color = "中国汉族"
    10         print("对象的color为:{}".format(self.color))
    11 
    12 xj = Person("小简", "")
    13 
    14 # # 获取对象的hobby属性
    15 # value = getattr(xj,"hobby")
    16 # print("之前:", value)  # 报错:AttributeError
    17 
    18 # 如果对象xj没有hobby属性,就给它添加一个
    19 if not hasattr(xj, "hobby"):
    20     setattr(xj,"hobby","听歌")
    21 
    22 # 获取对象的hobby属性
    23 value = getattr(xj,"hobby")
    24 print("之后:", value)
    25 
    26 # 删除hobby属性
    27 delattr(xj, "hobby")
    28 
    29 # # 获取对象的hobby属性
    30 # value = getattr(xj,"hobby")
    31 # print("删了之后:", value)  # 报错: AttributeError,因为上面删除了该属性
    动态操作属性
  • 相关阅读:
    学点 C 语言(39): 函数 使用函数的代价与内联函数(inline)
    学点 C 语言(35): 函数 递归
    学点 C 语言(34): 函数 关于变量(auto、static、register、extern、volatile、restrict)
    学点 C 语言(37): 函数 常量(const)参数
    带进度的文件复制 回复 "冷风无泪" 的问题
    如何把一个程序中 Edit 中的文本赋给另一个程序的 Edit ? 回复 "Disk_" 的问题
    学点 C 语言(32): 函数 返回值
    博客园电子期刊2011年12月刊发布啦
    上周热点回顾(12.261.1)
    上周热点回顾(1.21.8)
  • 原文地址:https://www.cnblogs.com/quiet-sun/p/14340709.html
Copyright © 2011-2022 走看看