欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Python学习】python学习手册--第三十章 类的设计

程序员文章站 2022-07-15 16:50:32
...

Python和OOP

Python的OOP实现可以概括为三个概念,如下所示:

  • 继承
    继承时基于Python中的类树上的属性查找的(在X.name表达式中)
  • 多态
    函数的执行效果取决于传入参数的类型。
  • 封装
    方法和运算符实现实例的各个行为,隐藏数据是默认的惯例

OOP:

  • 继承:”是一个”关系:在使用继承和编写实例对象时,我们需要在现实情况中的符合“是”逻辑。比如编写公司职员对象,TL、主管、程序员是公司职工,那么它们都可以继承职工这个类。小明是程序员,那么创建小明这个对象时,就用程序员类来创建这个实例。
  • 组合(或称“聚合”):“有一个”关系,创建一个公司类,那么类中拥有职业,就可以用组合关系,即类中嵌套类,在构建实例的init函数中,就创建相关的嵌套类实例对象。这种类就是容器和控制器,它可以调用嵌套类的方法。
  • 委托(delegation),通常就是指控制器对象内嵌其他对象,而把运算请求传给那些对象。编程时,控制器对象就像是委托人,处理传输进去的运算请求。在Python中,委托通常是以__getattr__钩子方法实现的。

在Python中,通常情况下,单个的下划线开头的变量名当作为类的内部属性,这是一个非正式惯例。这种命名方法并不能像其它OOP语言一样给属性一个私有属性,不能阻止外部对该属性的读取,而是让程序员知道这个是内部属性。这样的属性名称在Python内部会自动扩展,属性名称之前会出现类名:

>>> class Callclass:                     
...   __X=3
... 
>>> lxm=Callclass()
>>> dir(lxm)
['_Callclass__X', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> 

__X属性自动扩展成为_Callclass__X,这种自动扩展只发生在类的内部,包括方法名和属性名。这种机制就可以使一些类在使用多个父类的同名属性时得到了有效区分。

方法是对象

之前介绍过__call__函数,它可以使类看上去像是方法的调用。

  • 无绑定类方法对象,即无self。通过对类进行点号运算从而取类的属性,会传回一个无绑定方法对象,调用该方法时,必须将一个实例作为第一个参数传入方法。
  • 绑定实例方法对象,相应的,通过实例调用方法时,会自动将方法和实例对象打包,就不用再明文将对象作为第一个参数传递了。

在Python3.0中,无绑定方法是函数,在3.0中,类的方法可以不将实例作为第一个参数传入,将类的方法当成简单的函数来使用。此时只能通过类名来调用,如果使用实例名,那么将会传入两个参数,从而引发错误。

>>> class c1:
...     def __init__(self):
...         self.x='c1'
...     def get(message):
...         print(message)
... 
>>> c1.get("hello")
hello
>>> lxm=c1()
>>> lxm.get("Hello")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: get() takes 1 positional argument but 2 were given
>>> 

还可以再实验一下,通过实例来调用方法,可以看到方法中获得的参数:

>>> class c2:
...     def __init__(self):
...         self.x='c1'
...     def get(*message):
...         print(message)
... 
>>> lxm2=c2()
>>> lxm2.get("Hello world")          #传入了两个参数,第一个都是实例本身,第二个才是我们看到的字符串
(<__main__.c2 object at 0x7f482b753f98>, 'Hello world')
>>> 

混合类是指在定义个类时,有一个以上的超类。在混合类中定义一个其他不同类都需要的方法,然后通过超类继承来取得相关方法的实现。