从java面向对象去分析python面向对象

本文的前提是对java的面向对象语法和概念有一个基本的了解,试图从这里去学习理解python的面向对象。


一,用python去实现类

class Animal(object):
    
    kind = 2000
     
    def __init__(self, name):
        self.name = name
        
    def run(self):
        print('Animal is running...')

上面的语法表示:

  1. 创建Animal类 继承object类
  2. __init__是初始化的方法,相当于java中的构造方法
  3. 添加一个run方法

两点需要注意的地方:

  1. java中的this改用self代替,并且每个方法都要用self做为第一个参数,但是调用方法的时候可以省略self参数
  2. name是实例属性,kind是类属性

二,python可以动态的绑定属性和方法

animal = Animal('佩奇')
print(animal.name)

animal.age = 7
print(animal.age)

Output:
佩奇
7

虽然上面的Animal类的定义中,只指出了一个实例属性name,但是可以在创建对象对,直接添加一个age属性进去。这一点对于java这种静态语言是不可能的,如果学过js或者matlab估计会很容易理解吧。

甚至可以添加一个方法

def pao(self):
    print('Animal is pao...')
animal.pao = pao     #Animal.pao = pao

animal.pao(animal)    #animal.pao()

Output:
Animal is pao...

因为python的方法名可以理解成一个指向内存中方法的一个变量,所以原理上添加方法和添加属性是一样的。

如果这里调用的时候不想传参,需要把方法绑定到Animal类上 而不是对象上,如果就像绑定到对象上, 还不想传参,那么可以这样

from types import MethodType

def pao(self):
    print('Animal is pao...')
animal.pao = MethodType( pao, animal)

animal.pao()

Output:
Animal is pao...

三,访问权限控制

java中有访问修饰符,private,default,protected,public,每一个修饰符都有明确的可访问范围。

那么python如何进行这种控制?在属性名称前加上__即可,代码如下

class Animal(object):

    kind = 2000

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

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


animal = Animal('佩奇')
print(animal.__name)

Output:
AttributeError: 'Animal' object has no attribute '__name'

可以看到,再直接访问animal.name就会报错,说Animal类中没有name这个属性

原理非常简单,只是python解释器把__name变成了_Animal__name(不同的编译器会变成不同的名字),所以如果你一定要访问的话,没人拦得住你。

四,python多态和'鸭子类型'

多态的概念就不阐述了,先来看看代码

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

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

def AnimalRun(animal):
    animal.run()

dog = Dog()

AnimalRun(dog)

Output:
Dog is running

乍一看,这段代码很正常,AnimalRun方法接收一个Animal类的实例,然后就可以调用这个实例的run方法了,也就是和java的多态一样,针对接口或者父类编程即可满足开闭原则。

但是,仔细看就会发现问题,AnimalRun方法的参数你是没办法在函数定义中限制类型的,因为python是动态语言,你传什么参数,它就是什么类型,那么只要这个类型有run方法,代码可以运行。也就是动态语言所谓的'鸭子类型':一个事物,看起来像鸭子,走起来像鸭子,那它就是鸭子。

从这一点去理解动态语言和静态语言在多态上的差异比较好,那么如果想要限制animal只能是Animal类的实例呢? 在代码中做限制即可

def AnimalRun(animal):
    if isinstance(animal, Animal):
        animal.run()

五,python获取对象的信息

这个事儿如果放在java里,就有一个比较高大上的名字,叫'反射',当然反射还有其他的作用,比如动态创建对象。

python中用 hasattr(), getattr(), setattr() 三个来查询,获取,添加设置属性方法。

animal = Animal('佩奇')

print(hasattr(animal, 'name'))
print(hasattr(animal, 'run'))
print(getattr(animal, 'age', '没有age')) #没有age属性就返回 没有
setattr(animal, 'age', 7)
print(animal.age)


Output:
True
True
没有age
7

还可以用dir()来查询所有的属性方法

print(dir(animal))

Output:
['__class__', '__delattr__', '__dict__', '__dir__', ... , 'age', 'name', 'run']

经过这番对比分析,相信对python面向对象的了解,甚至对动态语言和静态语言面向对象的基本区别应该比较清楚了

展开阅读全文

没有更多推荐了,返回首页