面向对象

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






高阶函数
全部评论

相关推荐

03-03 23:12
已编辑
北京邮电大学 Java
书海为家:我来给一点点小建议,因为毕竟还在学校不像工作几年的老鸟有丰富的项目经验,面试官在面试在校生的时候更关注咱们同学的做事逻辑和思路,所以最好在简历中描述下自己做过项目的完整过程,比如需求怎么来的,你对需求的解读,你想到的解决办法,遇到困难如何找人求助,最终项目做成了什么程度,你从中收获了哪些技能,你有什么感悟。
你的简历改到第几版了
点赞 评论 收藏
分享
自从我室友在计算机导论课上听说了“刷&nbsp;LeetCode&nbsp;是进入大厂的敲门砖”,整个人就跟走火入魔了一样。他在宿舍门口贴了一张A4纸,上面写着:“正在&nbsp;DP,请勿打扰,否则&nbsp;Time&nbsp;Limit&nbsp;Exceeded。”日记本的扉页被他用黑色水笔加粗描了三遍:“Talk&nbsp;is&nbsp;cheap.&nbsp;Show&nbsp;me&nbsp;the&nbsp;code。”连宿舍聚餐,他都要给我们讲解:“今天的座位安排可以用回溯算法解决,但为了避免栈溢出,我建议用动态规划。来,这是状态转移方程:dp[i][j]&nbsp;代表第&nbsp;i&nbsp;个人坐在第&nbsp;j&nbsp;个位置的最优解。”我让他去楼下取个快递,他不直接去,非要在门口踱步,嘴里念念有词:“这是一个图的遍历问题。从宿舍楼(root)到驿站(target&nbsp;node),我应该用&nbsp;BFS&nbsp;还是&nbsp;DFS?嗯,求最短路径,还是广度优先好。”和同学约好出去开黑,他会提前发消息:“集合点&nbsp;(x,&nbsp;y),我们俩的路径有&nbsp;k&nbsp;个交点,为了最小化时间复杂度,应该在&nbsp;(x/2,&nbsp;y/2)&nbsp;处汇合。”有一次另一个室友低血糖犯了,让他帮忙找颗糖,他居然冷静地分析道:“别急,这是一个查找问题。零食箱是无序数组,暴力查找是&nbsp;O(n)。如果按甜度排序,我就可以用二分查找,时间复杂度降到&nbsp;O(log&nbsp;n)。”他做卫生也要讲究算法效率:“拖地是典型的岛屿问题,要先把连通的污渍区块都清理掉。倒垃圾可以用双指针法,一个指针从左往右,一个从右往左,能最快匹配垃圾分类。”现在我们宿舍的画风已经完全变了,大家不聊游戏和妹子,对话都是这样的:“你&nbsp;Two&nbsp;Sum&nbsp;刷了几遍了?”“别提了,昨天遇到一道&nbsp;Hard&nbsp;题,我连暴力解都想不出来,最后只能看题解。你呢?”“我动态规划还不行,总是找不到最优子结构。今天那道接雨水给我整麻了。”……LeetCode&nbsp;真的害了我室友!!!
老六f:编程嘉豪来了
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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