面向对象

9、面向对象
类和实例
访问限制
# -*- coding: utf-8 -*-
import sys
'''
class Student(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def print_score(self):
        print('%s: %s' % (self.name, self.age))

    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'
'''
class Student(object):
    #如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,
    # 实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
    def __init__(self, name, score):
        self.__name = name
        self.__score = score
    #如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法:
    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'
    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score
    #如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法
    def set__score(self,score):
        if 0 <= score <= 100:
            self.__score = score
        else:
            raise ValueError('bad score')

lisa = Student('Lisa', 99)
bart = Student('Bart', 59)
#不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量:
print(lisa._Student__name)

class StudentPlus(object):
    def __init__(self, name, gender):
        self.__name = name
        self.__gender = gender
    #外部访问返回gender
    def get_gender(self):
        return self.__gender
    #外部修改gender
    def set_gender(self,gender):
       self.__gender = gender
bart = StudentPlus('Bart', 'male')
if bart.get_gender() != 'male':
    print('测试失败1!')
else:
    bart.set_gender('female')
    if bart.get_gender() != 'female':
        print('测试失败2!')
    else:
        print('测试成功!')


继承多态

# -*- coding: utf-8 -*-
import sys


'''
你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。

多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:

对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

对扩展开放:允许新增Animal子类;

对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
'''
#父类
#当我们定义一个class的时候,我们实际上就定义了一种数据类型。
# 我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:
class Animal(object):
    def run(self):
        print('Animal is running...')
#子类
#当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),
#在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态
class Dog(Animal):
    def run(self):
        print('Dog is running...')

    def eat(self):
        print('Eating meat...')

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

class Tortoise(Animal):
    def run(self):
        print('Tortoise is running slowly...')
#对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

#对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:
class Timer(object):
    def run(self):
        print('Start...')
#子类实例化

dog = Dog()
cat = Cat()

#这个函数接受一个Animal类型的变量:
def run_twice(animal):
    animal.run()
    animal.run()



#在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类
print(isinstance(3, list))
print(run_twice(Animal()))
print(run_twice(Tortoise()))
print(run_twice(dog))

print(dog.run())
print(cat.run())
#继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。

#动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。
#1、获取对象信息

#用type判断
print(type(8))
#isinstance还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是list或者tuple
print(isinstance([1, 2, 3], (list, tuple)))
#dir 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:
print(dir('ABC'))
# 类似__xxx__的属性和方法在Python中都是有特殊用途的,比如__len__方法返回长度
print('abc'.__len__())
# 我们自己写的类,如果也想用len(myObj)的话,就自己写一个__len__()方法:
class MyDog(object):
    def __len__(self):
        return 100
dog = MyDog()
print(len(dog))
# 剩下的都是普通属性或方法,比如lower()返回小写的字符串:
print('ER'.lower())
#仅仅把属性和方法列出来是不够的,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:
class MyObject(object):
    def __init__(self):
        self.x=10
    def power(self):
        return self.x*self.x

obj=MyObject()
#设置对象属性
hasattr(obj, 'x') # 有属性'x'吗?
hasattr(obj,'y')
setattr(obj,'y',19) # 设置一个属性y
getattr(obj,'y') # 获取属性y
print(obj.y) # 获取属性y内容
#如果试图获取不存在的属性,会抛出AttributeError的错误:


#也可以获得对象的方法:
print(hasattr(obj, 'power'))# 有属性'power'吗?
print(getattr(obj, 'power')) # 获取属性'power'

# 2、实例属性和类属性
class Student(object):
    name = 'Student'
s = Student() # 创建实例s
print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性

print(Student.name) # 打印类的name属性

s.name = 'Michael' # 给实例绑定name属性
print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性

print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问

del s.name # 如果删除实例的name属性
print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了







#3、__slots

# 如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。
# 为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
#使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:
#除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
class GraduateStudent(Student):
    pass
g = GraduateStudent()
g.score = 9999
s = Student() # 创建新的实例
s.name = 'Michael' # 绑定属性'name'
s.age = 25 # 绑定属性'age'
#x3=s.score = 99 # 绑定属性'score'

#多态
class A:
    def say(self):
        print('A')
class B:
    def say(self):
        print('B')
def say(obj):
    obj.say()

def say(obj):
    obj.say()

a=B()
print(say(a))

# 4\@property






高阶函数
全部评论

相关推荐

程序员花海:实习和校招简历正确格式应该是教育背景+实习+项目经历+个人评价 其中项目经历注意要体现业务 实习经历里面的业务更是要自圆其说 简历模板尽可能保持干净整洁 不要太花哨的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务