16-面向对象之语法(1)

1. 举例:

class People(self,name,age):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def run(self):
        print("I can run")
        
p1 = People("Tom", 22) //实例化,得到一个instance
# self的含义代表“当前这个对象,这个instance”,与当前这个class区分开

2. _init_() 和 _new_() 的功能与区分:

  • _new_() 是创建instance(叫对象或者实例都可以)
  • _init_() 是初始化上面创建好的instance

我个人觉得:init加上new,近似等价于java里面的构造方法,当实例化class得到了一个instance时,系统自动调用new和init

  • 定义class的fun时需要传入self参数,但是调用时系统自动传入self,这个参数无须用户处理:定义时要形参写self, 但是真正传实参时忽略它。
  • _str_() 的激发时机:当系统要print(某对象)时,会自动激发此函数
  • 以上三个魔术方法,都可以用户自定义或者不管(系统默认有)

3. 属性私有化:

__name,__run() 属性或者方法名前面两个下划线,即变成只有class内部能够访问的私有属性
(不是完全没办法class外部访问,只是建议私有属性和方法不要在class外部直接访问)

4. 继承:

class Student(People) #就是这样简单地继承了People
实现的效果:

  • Student这个class默认拥有People所有的公开属性及公开方法;
  • 私有属性和方法不能被继承;
  • 子类继承父类的公有属性的本质:子类默认继承了父类的_init_() ;所以如果子类重写了_init_(),子类就去调用自己的_init_(),就不一定会继承父类的所有公共属性。这一点切记!看透继承公共属性的本质!
  • 继承父类的公共方法的本质:也是默认继承了父类所有的公共方法。如果子类重写了这些方法,也是直接先去调用自己的方法。
  • 故而,一切继承行为的本质:有没有默认调用父类的某个方法,如果子类重写了,那就去调用自己的方法,那就不一定能得到父类所有的东西。

默认所有类都有一个基类:object(都是默认继承自object),默认继承objext的所有属性和方法。

重写:

  • 子类与父类的方法名相同,子类即重写了此方法,优先去调用自己的方法。
  • 子类重写了父类的方法之后,依旧希望调用父类的方法,有以下方案:
  • super().父类方法名(实参)
  • super(子类名,self).父类方法名(实参)
  • 父类名.父类方法名(self,实参)
class Animal(object):
    def __init__(self,name):
        self.name = name
        print("Animal init\n")
    
    
class Cat(Animal):
    def __init__(self):
        print("Cat init\n") #再执行自己的逻辑
        
        
class Dog(Animal):
    def __init__(self,color): #实例化对象需要传入color
        super().__init__("DogName") #调用父类的__init__(参数要根据父类的init形式写)
        print("Dog init\n")
        self.color = color
        
class Pig(Animal):
    def __init__(self): #实例化对象需要传入color
        super(Pig,self).__init__("PigName") #调用父类的__init__(参数要根据父类的init形式写)
        print("Pig init\n")
        
class Chiken(Animal):
    def __init__(self): #实例化对象需要传入color
        Animal.__init__(self,"PigName") #调用父类的__init__(参数要根据父类的init形式写)
        print("Chiken init\n")
        
        
c = Cat()#因为Cat的init重写了,根据重写的init的参数形式来构造实例
#print(c.name) #Cat 虽然继承了Animal,Animal有name,但是此处Cat无法获得name

d = Dog("black")

p = Pig()

c = Chiken()


#本文的__init__()可换成父类的任意公共方法
#而父类的公共属性的继承的本质:一定要记住:是由于继承父类的__init__()而得到的,
#没有继承父类的__init__()就无法继承父类的公共属性

5. 多继承:

  • class C(B,A):写在前面的父类优先级高(B比A高),当前这个class本身的优先级最高(C>B>A),这个class的实例优先级最低(C>B>A>The_instance_of_C)。__mro__是当前class的类级别的属性,标识了当前类体系里面优先级的高低。

6.多态:

  • 多态本意是:强类型语言中,某变量声明为A类型,使用时“看起来不是”A类型:看起来有多种形态。
  • python任何变量皆对象(包括函数都是instance, int 也是instance),所以多态无意义
  • python强调“鸭子类型”:只要具备相同的方法,每个对象都认为是“相似”的。

7.类属性与实例属性

  • 类属性属于class,它在内存中只有一个副本。可以被所有instance使用, 具体说即使没有instance,这个类属性依旧存在,它与instance无关!(与java的static变量相似)。

  • 实例属性:必须用self.attr标识,隶属于一个instance,与这个instance共存亡,与当前的class没有关系。

    class Person(object):
    name = "person" #公有的
    __passwd = 2018 #私有的

    def init(self,sex):
    self.sex = sex #self.sex是实例属性,必须用self标识:与对象共存亡

    print(Person.name,'\n')

    p1 = Person("female")
    print(p1.sex) #实例属性:生命周期与instance相关
    print(p1.name)
    print(Person.name,'\n') #类属性:生命周期与class相关

    p2 = Person("male")
    print(p2.sex)
    print(p2.name)
    print(Person.name,'\n')

8.类的静态方法与类方法:

1. 三个重要结论:

  • 类属性和类方法,都是属于class,所以能被子类继承。继承这个操作是class层次的行为
  • 类属性和类方法可以通过类的instance或者类名来调用
  • 类属性的修改和删除只能通过类名
    *类方法必定有个形参(cls) {类比普通方法必定有个self}
    *类方法使用@classmethod 标识

2. 静态方法(类方法中的特例):

  • @staticmethod标识,形参可以为空,但一旦传入多少形参,就要传入多少实参

    class A(object):
    name = "hao" #类属性

    def test_1(self): #普通方法
    print("A的普通方法 test_1")

    @classmethod #标识类方法的关键字,{类比java的注解}
    def test_2(cls): #cls,标识当前这个class
    print("A的类方法 test_2")

    @staticmethod #标识类的静态方法
    def test_3(): #形参可以为空,但是若写了就必须传入全部参数,因为这里没有self或者cls
    print("A的类方法静态方法 test_3")

    print(A.name)

    A.test_1() #普通方法不能通过类名调用

    A.test_2()
    A.test_3()
    print('\n')

    a = A()
    print(a.name)
    a.test_1()
    a.test_2()
    a.test_3()

3. 普通实例方法:

  • 必定有个形参self,实参却不用自己传入self(系统自动传入)
  • self引用的即可以是类属性,也可以是实例属性 (具体情况具体分析)
  • 而对于类方法,cls引用的一定是类属性和类方法;对于静态方法,需要用类名来引用类属性和类方法(也只能访问类属性和类方法)。

4. 再次回顾子类重写父类的方法,对于公共属性和公共方法的影响:

  • 如果没有重写行为,默认继承了父类所有的公共属性和公共方法。
  • 如果子类对_init_()执行重写,那么创建的对象优先执行子类重写后的_init_(), 所以有些父类的公共实例属性可能不能被继承到子类,但类属性不受影响,依旧可以继承下来,因为它不在__init__里面
  • 如果子类对哪个公共方法进行重写,那么子类的对象就首先只执行重写后的那个方法

9. _del_():类比java的析构方法

某对象最后一次被引用完毕,自动执行_del_(),系统回收这个对象的内存空间时

posted @ 2018-03-04 13:26  hzhang_NJU  阅读(123)  评论(0编辑  收藏  举报