Python面向对象编程。Obeject-Oriented Programing (OOP)


本文主要参考 廖雪峰python教程.

Obeject-Oriented Programing (OOP)

类和实例

创建类和实例

面向对象最重要的概念就是类(Class)和实例(Instance)。类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”。每个对象都拥有相同的方法,但各自的数据可能不同。

下面举了一个创建类和实例的例子。

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

class Student(object):
    pass

bart = Student()

print(bart)
print(Student)
<__main__.Student object at 0x7f7830a62280>
<class '__main__.Student'>

__init__方法

下面创建了一个带有初始化实例函数的类。

由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把namescore
等属性绑上去。

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score
        
bart = Student('Bart Simpson', 59)
print(bart.name)
print(bart.score)

#  在__init__ 方法中 self. 之后才是变量的名字。而不是 __init__(self,name,score)中的 name 和 score。
#  如下例子所示,将输入的name,score 传递给变量 A,B。然后从外部调用变量 A,B。

class Student(object):

    def __init__(self, name, score):
        self.A = name
        self.B = score
        
bart = Student('Bart Simpson', 59)
print(bart.A)
print(bart.B)
Bart Simpson
59
Bart Simpson
59

数据封装

面向对象编程的一个重要特点就是数据封装。在上面的Student类中,每个实例就拥有各自的name和score这些数据。我们可以通过函数来访问这些数据。

class Student(object):

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

    def print_score(self):
        print('%s: %s' % (self.name, self.score))
        
    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'
        
bart = Student('Bart Simpson', 59)

print(bart.print_score)
print(bart.get_grade)
print(bart.print_score())
print(bart.get_grade())
<bound method Student.print_score of <__main__.Student object at 0x7f7830a6b670>>
<bound method Student.get_grade of <__main__.Student object at 0x7f7830a6b670>>
Bart Simpson: 59
None
C

访问限制

在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据。

从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的name、score属性。

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,实例的变量名如果以__开头,就变成了一个私有变量(private)。私有变量只有内部可以访问,外部不能访问。

但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法。如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法。因为在方法中,可以对参数做检查,避免传入无效的参数。

class Student(object):

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

    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))
        
    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score
    
    def set_score(self, score):
        self.__score = score
    
    def set_score(self, score):
        if 0 <= score <= 100:
            self.__score = score
        else:
            raise ValueError('bad score')

bart = Student('Bart Simpson', 59)
print(bart.get_name)
print(bart.get_score)
print(bart.get_name())
print(bart.get_score())

#  需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量。
#  特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
<bound method Student.get_name of <__main__.Student object at 0x7f7830a62070>>
<bound method Student.get_score of <__main__.Student object at 0x7f7830a62070>>
Bart Simpson
59

继承和多态

OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承。新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。子类会自动继承父类的全部功能。如下面例子所示,Dog和Cat作为Animal的子类,什么事也没干,就自动拥有了run()方法。

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

class dog(Animal):
    pass

class cat(Animal):
    pass

dog = dog()
cat = cat()

print(dog.run())
print(cat.run())

在定义自类时,还可以重写父类里的方法。使子类的方法更精确。当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run()。在代码运行的时候,总是会调用子类的run()。我们就获得了继承的另一个好处:多态。

继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object。

class Animal(object):
    def run(self):
        print('Animal is running...')
        
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')
    def eat(self):
        print('Eating fish')
        
class tortoise(Animal):
    def run(self):
        print('tortoise is running slowly')
    def eat(self):
        print('Eating small shrimp')

dog1 = dog()
cat1 = cat()
tot = tortoise()     

dog1.run()
dog1.eat()

cat1.run()
cat1.eat()

tot.run()
tot.eat()

Dog is running
Eating meat
Cat is running
Eating fish
tortoise is running slowly
Eating small shrimp

要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。

a = list() # a是list类型
b = Animal() # b 是Animal类型
c = dog() # c 是 dog类型

# 判断一个变量是否是某个类型可以用isinstance()判断

print(isinstance(a, list)) 
print(isinstance(b, Animal)) 
print(isinstance(c, dog)) 
print(isinstance(c, Animal))
True
True
True
True

获取对象信息

使用type()函数。 type()函数返回数据类型为class类型。

print(type(123))
print(type(abs))

print(type(123)==type(456))
print(type(123)==int)
print(type('abc')==type('123'))
print(type('abc')==str)
print(type('abc')==type(123))

# 判断一个对象是否是函数,可以使用types模块中定义的常量
import types

def fn():
    psss
    
print(type(fn)==types.FunctionType)
print(type(abs)==types.BuiltinFunctionType)
print(type(lambda x: x)==types.LambdaType)
print(type((x for x in range(10)))==types.GeneratorType)

# 使用 isinstance()
# 对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。

sunyu = Animal()
dawei = dog()
kunge = cat()

print(isinstance(sunyu, Animal))
print(isinstance(dawei, dog))
print(isinstance(kunge, cat))

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

print(dir('ABC'))
<class 'int'>
<class 'builtin_function_or_method'>
True
True
True
True
False
True
True
True
True
True
True
True
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

实例属性和类属性

由于Python是动态语言,根据类创建的实例可以任意绑定属性。

class Student(object):
    name = 'Student'
    def _init_(self,name):
        self.name = name
        
# 上面Student Class里 name 是类的属性归Student类所有。类的所有实例都可以访问到

s1 = Student()
s2 = Student()
s2.name = 'Bob'
s3 = Student()
s3.name = 'Michael'

print(s1.name) 
print(Student.name)   
print(s2.name)  # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
print(s3.name)  # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Student
Student
Bob
Michael
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值