python面向对象编程(6)

如果有其他语言(比如java)的面向对象编程经验,这一部分就很容易理解了。

面向对象编程三大特点:封装、继承、多态。
封装的直接体现就是类class,隐藏对象的属性和实现细节,对外仅提供接口。
继承就是子类继承父类,同时拥有了父类所有属性。
多态就是方法参数为父类,调用该方法时,可以传递子类和父类对象实例,然后在代码执行时,动态执行子类 or 父类中的方法。

object是所有类的父类,当父类是object的时候,可省略。下面定义一个Person类,object表示被继承的类,__init__是类不能少的初始化的方法。

class Person(object):

    # 第一个参数永远都是self,指向创建的实例本身,创建实例的时候,self参数不需要传递,其他参数必须匹配。
    # 类内部的变量一般私有化,避免外部直接访问,可以提供get set方法让外部调用。
    # 变量前加_,就变成私有变量,但外部还是可以通过实例._name引用。按照规定,别这么干。
    # 变量前加__(双下划线),就变成私有变量,外部无法通过实例.__name获取值。
    # python解释器会把__name变更为_Person__name,不同解释器变更后的变量名可能不同,所以别这么干。
    # 外部通过实例.__name = 'xx'赋值后,并没有更改内部__name的值,因为内部的变量名已经变更了,可以通过get_name方法检验。
    # 变量名类似__xxx__的是特殊变量,可以直接引用
    def __init__(self, name, age):
        self.__name = name
        self._age = age

    def do(self):
        print('%s is %d years old.' % (self.__name, self._age))

    def get_name(self):
        return self.__name

    def set_name(self, name):
        if isinstance(name, str):
            self.__name = name
        else:
            raise ValueError('bad name')


p = Person('tom', 18)
p.do() --> 结果: tom is 18 years old.
print(p._Person__name) --> 结果: tom
p.__name = 'new'
print(p.__name) --> 结果: new
print(p.get_name()) --> 结果: tom

# 定义子类,继承Person类
class Student(Person):
    def do(self):
        print('Student do run...')


s = Student('lily', 20)
s.do() --> 结果:Student do run...

print(isinstance(s, Student)) --> 结果:True
print(isinstance(s, Person)) --> 结果:True

python是动态语言,有“鸭子类型”(外表像鸭子,走起来像鸭子),不需要严格的继承体系,对象只需要看起来像即可。

比如参数person对象不一定要继承Person,只需要该对象有对应的方法即可。

# 多态示例
def duo_tai(person):
    person.do()


duo_tai(Person('lilei', 20)) --> 结果: lilei is 18 years old. 动态执行Person中的do方法
duo_tai(Student('lilei', 20)) --> 结果:Student do run...动态执行Student中的do方法

# 鸭子类型示例,不继承Person,但是也有do方法,所以可以调用duo_tai方法
class Other(object):

    def do(self):
        print('other is run...')


duo_tai(Other()) --> 结果:other is run...

type(obj)可以获取obj的类型,但是都可以用isinstance(obj, type)代替。

import types

print(type(123)) --> 结果:int
# 判断函数类型
print(isinstance(duo_tai, types.FunctionType))
print(isinstance(abs, types.BuiltinFunctionType))
print(isinstance(lambda x: x, types.LambdaType))
print(isinstance((x for x in range(10)), types.GeneratorType))
# 还可以检测对象类型是type中的哪一个
print(isinstance([1, 2, 3], (list, tuple, int)))

类似__xxx__的属性和方法都是有特殊用途的,比如执行len()函数,都会自动去调用对象内部的len()方法

print(len('ABC')) #其实调用的是'ABC'.__len__()方法
print('ABC'.__len__())

反射特性

# 获取变量
print(getattr(p, '_sex', 'female'))
if hasattr(p, '_sex'):
    print('_sex', p._sex)
else:
    setattr(p, '_sex', 'male')

print('_sex', p._sex)

# 获取方法
func = getattr(p, 'do')
func()

类属性和实例属性

class Teacher:
    name = 'FUCK'


t = Teacher()
print(Teacher.name) --> 结果:'FUCK'
# 实例属性未定义,将去寻找类属性,所以要避免实例属性和类属性重名
print(t.name) --> 结果:'FUCK'
t.name = 'FUCK TOO'
# 变更实例属性,类属性不变
print(Teacher.name) --> 结果:'FUCK'
# 实例属性已定义,不去寻找类属性,即实例属性优先级高于类属性
print(t.name) --> 结果:'FUCK TOO'
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

相关阅读更多精彩内容

友情链接更多精彩内容