python 面向对象

Prerequisite

如题所示,面向对象
参考文章:廖雪峰

基础面向对象

访问限制

  • 实例的变量名如果以 __ 开头,就变成了一个私有变量,只有内部可以访问
  • 如果以一个下划线开头的实例变量名,比如 _name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”
  • 类似 __xxx__ 的属性和方法在 Python 中都是有特殊用途的,比如 __len__ 方法返回长度,如果你调用 len() 函数试图获取一个对象的长度,实际上,在 len() 函数内部,它自动去调用该对象的 __len__() 方法
# 所以,下面的代码是等价的
len('ABC')
# 3
'ABC'.__len__()
# 3
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))

student = Student("tuan", "666")

# 报错,访问不了私有变量
print(student.__name)
print(student.__score)

student.print_score()
# tuan: 666

如果突然运行外部获取私有变量,可以设置 get_name 函数
如果要更改里面的私有变量,不妨设置 set_name 函数

def get_name(self):
    return self.__name

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

鸭子类型

简单的说,就是无论是不是源自同一个父类或者祖父类等,只有它们有相同的函数,那么就是鸭子类型

class Animal(object):   #编写Animal类
    def run(self):
        print("Animal is running...")

class Dog(Animal):  #Dog类继承Amimal类,没有run方法
    pass

class Cat(Animal):  #Cat类继承Animal类,有自己的run方法
    def run(self):
        print('Cat is running...')
    pass

class Car(object):  #Car类不继承,有自己的run方法
    def run(self):
        print('Car is running...')

class Stone(object):  #Stone类不继承,也没有run方法
    pass

def run_twice(animal):
    animal.run()
    animal.run()
    print('\n')

run_twice(Animal())
run_twice(Dog())
run_twice(Cat())
run_twice(Car())
run_twice(Stone())

"""
Animal is running...
Animal is running...


Animal is running...
Animal is running...


Cat is running...
Cat is running...


Car is running...
Car is running...

# Stone 类就报错了,因为他没有 run 函数
Traceback (most recent call last):
  File "C:\Users\WPS\Desktop\Temporary\test.py", line 29, in <module>
    run_twice(Stone())
  File "C:\Users\WPS\Desktop\Temporary\test.py", line 21, in run_twice
    animal.run()
AttributeError: 'Stone' object has no attribute 'run'
"""

实例属性和类属性

实例属性大于类属性,直接举例

class Student(object):
    name = 'Bob'

# 类属性
student = Student()
print(student.name)
# Bob

# 添加实例属性
student.name = 'Alice'
print(student.name)
# Alice

# 删除实例属性
del student.name
print(student.name)
# Bob

高级面向对象

限制实例属性使用 slots

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

s = Student() # 创建新的实例
s.name = 'Michael' # 绑定属性'name'
s.age = 25 # 绑定属性'age'

s.score = 99 # 绑定属性'score'
# 失败,因为 score 没有被放到__slots__中


class GraduateStudent(Student):
    pass

g = GraduateStudent()
g.score = 9999
# 成功,因为__slots__对继承的子类是不起作用的
# 但是如果子类也使用__slots__,那么__slots__不仅对自己起作用,也会继承父类的__slots__

直接调用/修改类属性和只读使用 @property

class Student(object):

    @property # 调用属性
    def birth(self):
        return self._birth

    @birth.setter # 修改属性
    def birth(self, value):
        self._birth = value

    @property # 只读
    def age(self):
        return 2015 - self._birth

student = Student()
student.birth = 2002 # 修改
print(student.birth) # 调用
print(student.age) # 只读

多继承

原理很简单,就是一个类继承一个主类,再添加额外的功能(额外的类),其实一般的设计思路就是如此

class Animal(object):
    pass

# 大类:
class Mammal(Animal):
    pass

class Bird(Animal):
    pass

# 各种动物:
class Dog(Mammal):
    pass

class Bat(Mammal):
    pass

class Parrot(Bird):
    pass

class Ostrich(Bird):
    pass

# 额外的功能
class Runnable(object):
    def run(self):
        print('Running...')

class Flyable(object):
    def fly(self):
        print('Flying...')

# 多继承
class Dog(Mammal, Runnable):
    pass

class Bat(Mammal, Flyable):
    pass

定制类

这些功能在廖雪峰这篇文章里面,我基本用不到,了解一下即可

  • 调用函数名字(strrepr
  • 类使用 for 循环(iternextgetitem
  • 调用不存在的属性(getattr
  • 链式调用 API(getattr
  • 调用实例自身(call

使用枚举类

以星期的枚举类举例:

from enum import Enum, unique

@unique
class Weekday(Enum):
    Sun = 0 # Sun的value被设定为0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

使用案例

>>> day1 = Weekday.Mon
>>> print(day1)
Weekday.Mon
>>> print(Weekday.Tue)
Weekday.Tue
>>> print(Weekday['Tue'])
Weekday.Tue
>>> print(Weekday.Tue.value)
2
>>> print(day1 == Weekday.Mon)
True
>>> print(day1 == Weekday.Tue)
False
>>> print(Weekday(1))
Weekday.Mon
>>> print(day1 == Weekday(1))
True
>>> Weekday(7)
Traceback (most recent call last):
  ...
ValueError: 7 is not a valid Weekday
>>> for name, member in Weekday.__members__.items():
...     print(name, '=>', member)
...
Sun => Weekday.Sun
Mon => Weekday.Mon
Tue => Weekday.Tue
Wed => Weekday.Wed
Thu => Weekday.Thu
Fri => Weekday.Fri
Sat => Weekday.Sat

使用元类

看不懂,略(●'◡'●)

posted @ 2022-07-27 11:15  筱团  阅读(26)  评论(0编辑  收藏  举报