171112 Learning Python Chapter 26 Class Coding Basics

来源:互联网 发布:linux 7 dns配置 编辑:程序博客网 时间:2024/06/05 15:56

类产生多个实例对象

  • 类对象提供默认行为,是实例对象的工厂。
  • 类对象来自于语句,实例来自于调用。
  • 模块只有一个副本会导入某一程序中,需要通过reload来更新模块对象。

类对象提供默认行为

  • class 语句创建类对象并将其赋值给变量:class语句一般是在其所在文件导入时才执行
  • class 语句内的赋值语句会创建类的属性:类的属性可由变量名点号运算获取 object.atrribute
  • 类属性提供对象的状态和行为:位于类中的函数def语句会生成方法

实例对象是具体的元素

  • 像函数那样调用类对象会创建新的实例对象:每次调用,内存开辟一个新的空间
  • 每个实例对象继承类的属性并获得自己的命名空间:一开始开辟的内存空间是空的,但是后来会继承并开辟属于自己的类的属性空间
  • 在方法def内对self属性做赋值运算会产生每个实例对象自己的属性:对self属性做赋值运算,会创建或修改实例内的数据,而非类的数据

第一个例子

  • Class开头一行会列出类的名称,后面接一个内嵌并缩进的主体
  • 嵌套的语句是def,定义类要实现导出的行为的函数
  • 在类嵌套的代码块中顶层的复制的任何变量,都会变成类的属性。
    这里写图片描述
class FirstClass:             # define a class object    def setdata(self,value):  # define class methods        self.data = value     # self is the instance    def display(self):        print(self.data)      # self.data:per instancex = FirstClass()y = FirstClass()x.setdata('King Arthur')y.setdata(3.1415926) 
x.display()  # make new instancesy.display()  # Each is a new namespace
King Arthur3.1415926
  • 程序可以取出、修改或创建其所引用的任何对象的属性。
x.data = "New Value"   # Can set/get attributesx.display( )           # Outside the class toox.anothername = 'spam' # Can set new attributes here too!
New Value

类通过继承进行定制

  • 超类列在类开头的括号中: Class Son(Father)
  • 类从其超类中继承属性
  • 实例会继承所有可读取类的属性:顺着搜索树向上爬
  • 每个object.attribute都会开启新的独立搜索
  • 逻辑(类内方法/函数)的修改是通过创建子类,而不是修改超类:在树中较低的子类中重新定义超类的变量名,子类就可取代并定制所继承的行为。

第二个例子

class SecondClass(FirstClass):    def display(self):        print('Current value = "%s"' % self.data )
z = SecondClass()z.setdata(42)z.display()
Current value = "42"

这里写图片描述

  • 子类继承父类并重新定义父类的方法→重载
  • 子类SecondClass的专有化完全是在FristClass外部完成的,故子类不会影响当前或未来的FirstClass对象
  • 类继承可以让我们像这样在外部组件内(也就是在子类内)进行修改,类所支持的扩展和重用通常比函数或模块更好。
x.display() # 子类SecondClass的专有化完全是在FristClass外部完成的,故子类不会影响当前或未来的FirstClass对象
New Value

类是模块内部的属性

  • 模板反应了整个文件
  • 类知识文件内的语句

  • 导入模块,从模块中引用类class

from keras.layers import Denseclass MyDense1(Dense):    def display(self):        print('Learning Python!')
import keras.layersclass MyDense2(Dense):    def display(self):        print('Learning Python!')
  • 一个模块可以定义多个类
# food.pyvar = 1def func():    ...class spam:    ...class ham:    ...class eggs:    ...
  • 模块名和类型相同
class person:    ...import persom      # Import modulex = person.person()  # class within module
  • 避免混淆,类名需要大写
import personx = person.Person()

类可以截取Python运算符

  • 以双下划线命名的方法(_X_)是特殊的例子:Python语言替每种运算和特殊命名的方法之间,定义了固定不变的映射关系。
  • 当实例出现在内置运算时,这类方法回自动调用__add__→+
  • 类可覆盖多数内置类型运算
  • 运算符覆盖方法没有默认值,而且也不需要
  • 运算符可让类与Python的对象模型相集成

  • 运算符重载一般给开发人员用,所以一般少用;除非”init方法”,也就是构造函数方法,它是用于初始化对象状态的。

第三个例子

class ThirdClass(SecondClass):     # Inherit from SecondClass    def __init__(self,value):      # On "ThirdClass(value)"        self.data = value    def __add__(self,other):       # On "self+other"        return ThirdClass(self.data+other) # 创建返回新对象,未修改    def __str__(self):             # On "print(self),"str()"        return '[ThirdClass:%s]' %self.data    def mul(self,other):           # In-place change:named        self.data *= other         # 修改了self对象的值
a = ThirdClass('abc')  # __init__ calleda.display()print(a)
Current value = "abc"[ThirdClass:abc]

这里写图片描述

b = a+'xyz'b.display()print(b)
Current value = "abcxyz"[ThirdClass:abcxyz]
a.mul(3)print(a)
[ThirdClass:abcabcabc]

为什么要使用运算符重载(详见29章)

几乎每个实际的类似乎都会出现一个重载方法:__init__构造函数。因为这可以让类立即在其新建的实例内添加属性。

世界上最简单的Python类

class rec:pass
rec.name = 'Bob'
rec.age = 40
help(rec)
Help on class rec in module __main__:class rec(builtins.object) |  Data descriptors defined here: |   |  __dict__ |      dictionary for instance variables (if defined) |   |  __weakref__ |      list of weak references to the object (if defined) |   |  ---------------------------------------------------------------------- |  Data and other attributes defined here: |   |  age = 40 |   |  name = 'Bob'
x = rec()y = rec()x.name, y.name  # name is stored on the class only
('Bob', 'Bob')

赋值操作为对象开辟了新的属性空间,不影响其他对象的继承搜索

x.name = 'Sue'  # But assignment changes x onlyrec.name, x.name, y.name
('Bob', 'Sue', 'Bob')

命名空间对象的属性通常都是以字典的形式实现的,__dict__属性是针对大多数基于类的对象的命名空间字典

rec.__dict__.keys()
dict_keys(['__module__', '__dict__', '__weakref__', '__doc__', 'name', 'age'])
print(list(x.__dict__.keys())) # x有自己的命名空间nameprint(list(y.__dict__.keys())) # y继承搜索rec命名空间中的name,本身不具有name命名空间
['name'][]
  • 每个实例都连接至其类以便于继承,通过__class__查看基于实例的父类
  • 类通过__bases__查看其父类
print(x.__class__)print(rec.__bases__)
<class '__main__.rec'>(<class 'object'>,)
  • 类外定义函数
  • 必须让隐含的实例参数明确化才行,否则,Python无法猜测简单函数是否最终会变成类的方法
def upperName(self):    return self.name.upper() ## still needs a self
upperName(x)
'SUE'
rec.method = upperNameprint(x.method())  # run method to process xprint(y.method())  # same, but pass y to selfprint(rec.method(x)) # Can call through instance or class
SUEBOBSUE

Python中的OOP其实就是在已连接命名空间对象内寻找属性而已

类与字典的关系

字典

rec = {}rec['name']='mel'rec['age']=45rec['job']='trainer/writer'print(rec['name'])
mel

class rec:passrec.name = 'mel'rec.age = 45rec.job = 'trainer/writer'print(rec.name)
mel

我们产生一个空类的实例来表示每条不同的记录

class rec:passpers1 = rec()       # an empty classpers1.name = 'mel'pers1.job = 'trainer'pers1.age = '40'pers2 = rec()       # an empty classpers2.name = 'vls'pers2.job = 'developer'pers1.name,pers2.name
('mel', 'vls')

最后,我们可能编写一个更完整的类来实现记录及其处理

class Person:    def __init__(self,name,job):        self.name = name        self.job = job    def info(self):        return (self.name,self.job)rec1 =  Person('mel','trainer')rec2 = Person('vsl','developer')rec1.job,rec2.info()
('trainer', ('vsl', 'developer'))
原创粉丝点击