Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.1 Python 高级编程之面向对象编程 #8

Open
ShannonChenCHN opened this issue Jul 11, 2018 · 7 comments
Open

4.1 Python 高级编程之面向对象编程 #8

ShannonChenCHN opened this issue Jul 11, 2018 · 7 comments

Comments

@ShannonChenCHN
Copy link
Owner

ShannonChenCHN commented Jul 11, 2018

日期:2018.07.12 周四

  • 类和实例
  • 访问限制
  • 继承和多态
  • 获取对象信息
  • 实例属性和类属性

参考:

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 12, 2018

类和实例

定义类

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score

class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。

一些概念

  • 类和实例
    • 类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;
  • 属性
  • 方法
    • 方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;
    • 通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。
    • 跟 Objective-C 中的方法一样,Python 中方法的第一个参数默认是 self,不需要调用方传,不同的是 Objective-C 中的方法在定义时是看不到这个 self 参数的,不过在编译后的 runtime 代码中是有这个参数的
  • 初始化方法
    • 一般我们可以在 __init__ 方法中,把一些我们认为必须绑定的属性绑定到该类上
  • Python 中,我们可以给任何对象实例动态绑定任何属性和方法

和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同

@ShannonChenCHN
Copy link
Owner Author

访问限制

  • 私有属性
    • 如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
  • get 方法和 set 方法
  • 特殊变量
    • 在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 12, 2018

继承和多态

  • 继承
    • 继承可以把父类的所有功能(包括属性和方法)都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
  • 多态
    • 多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。
    • 计算机程序运行时,相同的消息可能会送给多个不同的类别之对象,而系统可依据对象所属类别,引发对应类别的方法,而有不同的行为。简单来说,所谓多态意指相同的消息给予不同的对象会引发不同的动作
class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('Dog is running...')

class Cat(Animal):
    def run(self):
        print('Cat is running...')

dog = Dog()
dog.run()

cat = Cat()
cat.run()

参考

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 12, 2018

静态语言 VS. 动态语言

举个🌰:

class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):

    def run(self):
        print('Dog is running...')

class Timer(object):
    def run(self):
        print('Start...')

def run_twice(animal):
    animal.run()

我们在上面定义了三个类,这三个类都实现了 run 方法,其中 Dog 类继承了 Animal 类。

  • 对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。
  • 对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了。
run_twice(Dog())
run_twice(Animal())
run_twice(Timer())

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 12, 2018

获取对象信息

class Animal(object):
    def __init__(self, name='Animal'):
        self.name = name

    def run(self):
        print('Animal is running...')


class Dog(Animal):
    pass

def func():
    pass

使用 type() 函数获取对象类型(相当于 Objective-C 中的 -class

通过 type() 函数可以查看以下几种数据的类型:

  • 对象
  • 函数

如果我们要在if语句中判断,就需要比较两个变量的type类型是否相同。
判断基本数据类型可以直接写intstr等,但如果要判断一个对象是否是函数,可以使用 types 模块中定义的常量。

示例代码:

import types

print(type(123), type(123) == int)
print(type(Animal()))
print(type(func), type(func) == types.FunctionType)
print(type(abs), type(abs) == types.BuiltinFunctionType)


lambdaType = lambda x : x + 1
print(type(lambdaType), type(lambdaType) == types.LambdaType)

gneratorType = (x for x in range(10))
print(type(gneratorType), type(gneratorType) == types.GeneratorType)

使用 isinstance() 函数获取对象是否是某个类的实例(相当于 Objective-C 中的 -isKindOfClass:

print(isinstance(Dog(), Animal))
print(isinstance(Dog(), Dog))

还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是list或者tuple:

print(isinstance([1, 2], (list, tuple)))

使用 dir() 函数获得一个对象的所有属性和方法

如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:

>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

除了 dir 函数之外,还有 hasattrsetattrgetattr 来访问/修改对象属性信息:

pig = Animal('pig')
print(dir(pig))
print(hasattr(pig, 'name'))
setattr(pig, 'name', 'pig')
print(getattr(pig, 'name'))

@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Jul 12, 2018

实例属性和类属性

实例属性

给实例绑定属性的方法是通过实例变量,或者通过self变量:

class Student(object):
    def __init__(self, name):
        self.name = name

s = Student('Bob')
s.score = 90

类属性

可以直接在class中定义属性,这种属性是类属性,归类所有:

class Student(object):
    name = 'Student'

当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。

s = Student()
print(s.name)
print(Student.name)

@ShannonChenCHN ShannonChenCHN changed the title 面向对象编程 4.1 Python 高级编程之面向对象编程 Jul 16, 2018
@ShannonChenCHN ShannonChenCHN changed the title 4.1 Python 高级编程之面向对象编程 4.1 Python 高级编程之面向对象编程基础 Jul 16, 2018
@ShannonChenCHN ShannonChenCHN changed the title 4.1 Python 高级编程之面向对象编程基础 4.1 Python 高级编程之面向对象编程 Jul 16, 2018
@ShannonChenCHN
Copy link
Owner Author

ShannonChenCHN commented Aug 27, 2018

super

简单理解, super 就是调用父类的方法。
单继承的情况下,super 的作用跟其他单继承语言差不多。

使用示例:

class C(B):
    def method(self, arg):
        super().method(arg)    # This does the same thing as:
                               # super(C, self).method(arg)

多继承

多继承情况下,调用 super 会按照 MRO(根据 C3 线性化算法实现的) 中的顺序依次执行父类的方法。
通过调用类的 mro() 方法可以获取 MRO 值。

class Base(object):
    def __init__(self):
        print("enter Base")
        print("leave Base")

class A(Base):
    def __init__(self):
        print("enter A")
        super().__init__()
        print("leave A")

class B(Base):
    def __init__(self):
        print("enter B")
        super().__init__()
        print("leave B")

class C(A, B):
    def __init__(self):
        print("enter C")
        super().__init__()
        print("leave C")

super 的本质

builtins.py 的代码片段:

class super(object):
    """
    super() -> same as super(__class__, <first argument>)
    super(type) -> unbound super object
    super(type, obj) -> bound super object; requires isinstance(obj, type)
    super(type, type2) -> bound super object; requires issubclass(type2, type)
    Typical use to call a cooperative superclass method:
    class C(B):
        def meth(self, arg):
            super().meth(arg)
    This works for class methods too:
    class C(B):
        @classmethod
        def cmeth(cls, arg):
            super().cmeth(arg)
    """

    def __init__(self, type1=None, type2=None): # known special case of super.__init__
        """
        super() -> same as super(__class__, <first argument>)
        super(type) -> unbound super object
        super(type, obj) -> bound super object; requires isinstance(obj, type)
        super(type, type2) -> bound super object; requires issubclass(type2, type)
        Typical use to call a cooperative superclass method:
        class C(B):
            def meth(self, arg):
                super().meth(arg)
        This works for class methods too:
        class C(B):
            @classmethod
            def cmeth(cls, arg):
                super().cmeth(arg)
        
        # (copied from class doc)
        """
        pass

从 Python 的源码中可以看出,super 本质上是一个类。

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant