简明python_Day9_类与对象
2019.5.16 天气闷热是真的让人难受,明天出差后天才回来很可惜不能学习了,所以今天要好好完成。对了,忘说天气,今天真的超热,回到家都是汗,闷热没下起雨就很难受,回家简直获救。
(macbook回删字符是 fn+delete)
学习内容:面向对象编程(这个听起来就很核心),包含self,类变量和对象变量,类方法,装饰器(少量).
P.S. 今天内容好丰富,需要多看
一个类(Class)能够创建一种新的类型(Type),其中对象(Object)就是类的实例(Instance)。
#######################################################################################
围绕函数设计我们的程序,也就是那些能够处理数据的代码块。这被称作面向过程(Procedure-oriented)的编程方式。(嵌入式应该算这个,嗯)
当你需要编写一个大型程序或面对某一更适合此方法的问题时,你可以考虑使用面向对象式的编程技术。它组织起你的程序的方式,它将数据与功能进行组合,并将其包装在被称作“对象”的东西内。
针对静态编程语言程序员的提示请注意:即使是整数也会被视为对象( int 类的对象)。这不同于 C++ 与 Java(1.5版之前),在它们那儿整数是原始内置类型。
关于字段和方法的讨论:
对象可以使用属于它的普通变量来存储数据。这种从属于对象或类的变量叫作字段(Field)。只不过是绑定(Bound)到类与对象的命名空间(Namespace)的普通变量。
对象还可以使用属于类的函数来实现某些功能,这种函数叫作类的方法(Method)。
这两个术语很重要,它有助于我们区分函数与变量,哪些是独立的,哪些又是属于类或对象的。总之,字段与方法通称类的属性(Attribute)。字段有两种类型——它们属于某一类的各个实例或对象,或是从属于某一类本身。它们被分别称作实例变量(Instance Variables)与类变量(Class Variables)。
变量和方法都分是类的还是对象的。
参数 self:这个是为了让method显式,对__init__这种也有用
针对 C++/Java/C# 程序员的提示:Python 中的 self 相当于 C++ 中的 this 指针以及 Java 与 C# 中的 this 引用。
你一定会在想 Python 是如何给 self 赋值的,以及为什么你不必给它一个值。一个例子或许会让这些疑问得到解答。假设你有一个 MyClass 的类,这个类下有一个实例 myobject 。当你调用一个这个对象的方法,如 myobject.method(arg1, arg2) 时,Python 将会自动将其转换成 MyClass.method(myobject, arg1, arg2) ——这就是 self 的全部特殊之处所在。
这同时意味着,如果你有一个没有参数的方法,你依旧必须拥有一个参数—— self 。
创建一个类(名字单词首字母要大写):
通过 class 关键字可以创建一个类。这个类的字段与方法可以在缩进代码块中予以列出:
pass语句:是空语句,是为了保持程序结构的完整性。pass 不做任何事情,一般用做占位语句。
通过采用类的名称后跟一对括号的方法,给这个类创建一个对象。结果告诉我们我们在 Person 类的 __main__ 模块
中拥有了一个实例。要注意到在本例中还会打印出计算机内存中存储你的对象的地址。案例中给出的地址会与你在你的电脑上所能看见的地址不相同,因为 Python 会在它找到的任何空间来存储对象。
类和对象都有两个部分:功能部分(方法),数据部分(字段)
创建一个方法:(self仍然有,方法就是类里面的函数)
注意到 say_hi 这一方法不需要参数,但是依旧在函数定义中拥有 self 变量。
创建一个字段的方法:
__init__ 定义一个字段:可以理解为给类创造一个属性(如名字),在后面对象能使用(叫什么名,用来区分不同的对象)
__init__只在class中使用,不会显式地调用
要注意到尽管它们的名字都是“name”,但这是两个不相同的变量。虽说如此,但这并不会造成任何问题,因为 self.name 中的点号意味着这个叫作“name”的东西是某个叫作“self”的对象的一部分,而另一个 name 则是一个局部变量。
字段有两种类型——类变量和对象变量:
类变量(Class Variable)是共享的(Shared)——它们可以被属于该类的所有实例访问。该类变量只拥有一个副本,当任何一个对象对类变量作出改变时,发生的变动将在其它所有实例中都会得到体现。
对象变量(Object variable)由类的每一个独立的对象或实例所拥有。在这种情况下,每个对象都拥有属于它自己的字段的副本,也就是说,它们不会被共享,也不会以任何方式与其它不同实例中的相同名称的字段产生关联。
例子:
1)def和__init__、name这些上面都说了。
2)number属于 Robot 类,因此它是一个类变量。 name 变量属于一个对象(通过使用 self 分配),因此它是一个对象变量。因此,我们通过 Robot.number 而非 self.number (等价于:self.__class__.population)引用 number 类变量。
self.name:这种一看就是对象变量。体现对象属性。
3)类方法:baoshu 实际上是一个属于类而非属于对象的方法。这就意味着我们可以将它定义为一个classmethod(类方法) 或是一个 staticmethod(静态方法) ,这取决于我们是否需要知道这一方法属于哪个类。由于我们已经引用了一个类变量,因此我们使用 classmethod(类方法) 。
4)装饰器:标记类方法(@classmethod)。相当于调用一个包装器(Wrapper)函数的快捷方式(等价于:baoshu=classmethod(baoshu))
5)注意:python中所有的类成员都是公开的。但有一个例外:如果你使用数据成员并在其名字中使用双下划线作为前缀,形成诸如 __privatevar 这样的形式,Python 会使用名称调整(Namemangling)来使其有效地成为一个私有变量。但是它只是换了个名字,实际上没有真正的私有化支持(伪私有:收藏中有一文讲的好:https://www.cnblogs.com/randomlee/p/9026105.html)
#######################################################################################
继承:
目的是对代码的重用,所以继承可以理解为类之间实现类型与子类型关系的工具。
例如老师和学生两个类都有姓名、年龄和地址这些共同的属性,但老师有工资,学生有成绩、学费等属性。你可以为每一种类型创建两个独立的类,并对它们进行处理。但增添一条共有特征就意味着将其添加进两个独立的类。这很快就会使程序变得笨重。
更好的方法是创建一个公共类(也叫基类或超类(很容易打成鸡肋或超累。。)),然后让教师和学生从这个类中继承,它们将成为子类型(想继承就当儿子嘛~),然后就可以向子类型中添加某些该类独特的特征。
修改超类功能将自动反映在子类型中。子类型的改动不会影响到其他子类型。
这叫做多态性。
例子:
1)要想使用继承,在定义(子)类时我们需要在类后面跟一个包含超类名称的元组:class Teacher(SchoolMember)
2)然后,我们会注意到基类的 __init__ 方法是通过 self 变量被显式调用的,因此我们可以初始化对象的基类部分。下面这一点很重要,需要牢记——因为我们在 Teacher 和 Student 子类中定义了__init__ 方法,Python 不会自动调用基类 SchoolMember 的构造函数,你必须自己显式地调用它。
3)相反,如果我们没有在一个子类中定义一个 __init__ 方法,Python 将会自动调用超类的构造函数。就是说,子类没有__init__,会用超类的,那么你就没法加salary,marks这种字段。
4)我们可以通过在方法名前面加上基类名作为前缀,再传入 self 和其余变量,来调用基类的方法。
5)当我们使用 SchoolMember 类的 tell 方法时,我们可以将 Teacher 或Student 的实例看作 SchoolMember 的实例。
6)你会发现被调用的是子类型的 tell 方法,而不是 SchoolMember 的 tell 方法。理解这一问题的一种思路是 Python 总会从当前的实际类型中开始寻找方法,在本例中即是如此。如果它找不到对应的方法,它就会在该类所属的基本类中依顺序逐个寻找属于基本类的方法,这个基本类是在定义子类时后跟的元组指定的。
7)这里有一条有关术语的注释——如果继承元组(Inheritance Tuple)中有超过一个类,这种情况就会被称作多重继承(Multiple Inheritance)。
8)##我的理解是:超类向子类传递类字段和方法