面向对象编程
1.基本理论
(1)什么是对象
python中,万物皆对象。包括int等基本类型,都是对象。对象有属性和方法。属性就是描述这是什么,方法就是在说,这个对象能干什么。前者静态特征,后者为动态特征。
(2)面向过程和面向对象
面向过程关注解决问题的步骤;
而面向对象关注哪个对象能解决这个问题;
如现在需要完成“洗碗”这个操作,面向对象的思想就是,找一个能完成这任务的对象,让它去做:
即,面向对象是在分配任务。将一个任务分配给各种对象去做,自己只做调度的事情。(“瞎指挥”的角色,包工头啥的)。
(3)两者对比
面向对象是面向过程的封装。基本的解决问题的步骤还是面向过程的思想。
因此,面向过程编程时,最重要的是“分解步骤”,即将一个任务分解成具体的小步骤。
而面向对象编程时,最重要的是“按照功能对象进行划分”,确定对象的职责,确定对象的属性和方法。
如何过渡到面向对象的编程思想?
最关键一步是分离功能模块。将一些功能划分到某个对象中,根据这个对象的行为,抽象出类(设计类)
(4)类
类中的特征是抽象表示,对象的特征是实例化的抽象的特征。比如“年龄”是抽象概念符号,而“22岁”是具体的特征。
类,就是将一系列特征相似的东西,抽象出一个特征的集合。那么类的设计过程,就是分类的过程!
二、Python中的实践
1.创建类
这是不继承任何类的类:
class A:
pass
如下代码中:
2.打印类和类的属性的快捷键
快捷键就是A.pri
+tab
:
class A:
pass
a = A()
print(A)
print(a)
这两个print函数都是由快捷键打出的。输出为:
打印一个类的属性也可以用这种方法:(即先用)
打印id(Object)
也可以用这快捷键!应该是什么的都可以!
可以打印一个对象的类:
a.__class__
3.对象和类的引用关系
类也是一个对象,存储于某个内存块中。其引用为类名字,其有一个地址。下面代码中输出为相同的类地址:
class Money:
pass
one = Money()
print(id(one.__class__))
print(id(Money))
类和对象的引用关系为:
4.对象的属性
可以动态添加属性。
class Money:
pass
one = Money()
one.age = 18
one.height = 180
#__dict__保存了非默认的属性键值对
print(one.__dict__)
输出为:
给对象添加一个属性,等价于先创建一个对象,然后再将对象的某个属性指向新创建的对象。比如上面的代码中,是创建了18和180这两个对象后,再让对象的属性指向它们:
这也正是“Python中万物皆对象”的写照。Python中,就连一个int都是对象,何况其他内容?创建完对象,不管是怎么找到这个对象,都是铜鼓引用的方式。而引用的方式,就是刚下小节中所述的内容:
5.Python中的引用
每个引用都是一个地址。即,每个符号(变量)就等同于一个地址。(联想编译链接那里,每个符号都被翻译成汇编的一个地址了)。Python中如果改变某个指针的指向,等价于改变这个符号的值(即改变了地址)。
原本为a=0x99999
若执行a = Money()
,则结果可能为a=0x88888
。数据都是瞎编的,只是示意用。
6.对象的__dict__
这个dict指向的内容,就是对象的属性指向的对象:
class C:
pass
obj = C()
#只给__dict__添加键值对,发现对象的属性也添加了
obj.__dict__={'age':12}
print(obj.age)
结果为:
但是,类的字典属性不能这么修改,对象可以。
7.slots
java中,对象的属性不可以随意添加。而Python中可以。有时在Python中也需要限制对象的属性的添加,这就用到了这个。
8.方法的划分
根据方法接受的第一个参数划分为示例方法和类方法。前者第一个参数是self,后者是cls。而静态方法第一个参数啥也不默认接收。
写类方法用到了装饰器@classmethod.静态方法用@staticmethod修饰。
9.方法存储位置
这可以和对象的__dict__这一节联系起来:对象和类的属性,就是存储在__dict__中的。
方法体都存在类对象中:
如
class Person:
def age(self):
pass
p=Person()
每个方法也都是一个对象。
10.实例方法
其第一个参数是一个实例
如
a=Money() a.show()
其中show()
方法接受的实例就是a
。
11.用类调用实例方法
最普通的调用实例的方法就是用实例调用:
class Person:
def eat(self, food):
print(self, food)
p=Person()
p.eat()
但是由于方法作为一个对象,存储于类对象中,因此也可以用类名.方法名找到这个方法对应的对象:
用Person类直接访问方法时,这方法就和普通方法没什么区别,需要传两个参数,分别是self和food。这时self是显式传给方法的。
12.类方法的调用
用@classmethod修饰。下面是这个文档:
class classmethod(object):
"""
classmethod(function) -> method
Convert a function to be a class method.
#接受一个类作为默认隐式参数,就像实例方法一样。这里类比很恰当。
A class method receives the class as implicit first argument,
just like an instance method receives the instance.
To declare a class method, use this idiom:
class C:
@classmethod
def f(cls, arg1, arg2, ...):
...
#既可以用类名.方法名调用,也可以用实例.方法名调用。不同点在于,
#若用实例调用则会忽略这个实例。
#若是子类调用,则传入的类是子类
It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()). The instance is ignored except for its class.
If a class method is called for a derived class, the derived class
object is passed as the implied first argument.
#声明这是不同于java的静态方法
Class methods are different than C++ or Java static methods.
If you want those, see the staticmethod builtin.
"""
13.类方法和实例方法
l=[1,2,4,3]
#有几种方法都可以对这个列表排序
#1.用类方法。那就需要再传入一个实例作为self参数。
list.sort(l)
#2.内置方法
sorted(l)
#3.用实例方法。这么说,实例方法就是作用于对象的一个方法,这方法就可能对实例进行任何操作。
#可能变化其中数据,可能根据其中数据变化其他数据。跟对象的主动被动没啥关系
l.sort()
14.静态方法
不需要实例也不需要类作为默认参数的方法。
这是文档:
class staticmethod(object):
"""
staticmethod(function) -> method
Convert a function to be a static method.
#即,不需要任何隐式参数作为第一个参数
A static method does not receive an implicit first argument.
To declare a static method, use this idiom:
class C:
@staticmethod
def f(arg1, arg2, ...):
...
It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()). The instance is ignored except for its class.
Static methods in Python are similar to those found in Java or C++.
For a more advanced concept, see the classmethod builtin.
"""
15.元类
每个实例都是由类创建的,但是类也是个实例,类也是由一个类创建的,这个类就是type
在创建类时,可以指明__metaclass__参数,指明本类的元类是谁。(没懂,元类和有啥区别)
16.type类
type是一个类,而不是一个方法。
第一个作用是判断一个对象的类,另一个作用是创建一个类:
class type(object):
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
#这种方式就是创建一个类
type(name, bases, dict) -> a new type
"""
17.写注释
敲"""直接就出来文档那些参数啥的了:
help(Person)可以生成文档。
18.生成文档
用这个pydoc模块
19.下划线
后面的下划线不表示访问权限,只是为了区分。如:class_变量,因为不能和class重名,因此加一个下划线。
__init__中,表示系统内置
单下划线代表“private”。
20. @property——设置只读属性
作用是“将一个属性的操作方法(如增删改查),关联到一个属性上”:
Property attribute翻译成属性特性。
property属性是面向对象的基本概念,提供了对私有字段的访问封装,在C#中以get和set访问器方法实现对可读可写属性的操作,提供了安全和灵活的数据访问封装。
def __init__(self, fget=None, fset=None, fdel=None, doc=None): # known special case of property.__init__
"""
Property attribute.
#fget就是获取属性值的方法
fget
function to be used for getting an attribute value
fset
function to be used for setting an attribute value
fdel
function to be used for del'ing an attribute
doc
docstring
#就是用来设置属性x的操作方法的
Typical use is to define a managed attribute x:
#这个例子很形象
class C(object):
def getx(self): return self._x
def setx(self, value): self._x = value
def delx(self): del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
#用装饰器简化上述操作
Decorators make defining new properties or modifying existing ones easy:
class C(object):
@property
def x(self):
"I am the 'x' property."
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
# (copied from class doc)
"""
pass
21.__setattr__()方法
下面例子中,重写了Person的__setattr__方法,使得其没有把对象的属性存到字典中。因此这个属性根本就没添加。
22.常用内置设置的属性
23.对象的默认内置方法作用
字典索引方式的实现:
24.切片
下例中,key是slice类型的对象,其有start等三个属性
25.上下文环境布尔值
可以指定if 某个对象时,返回True还是False
26.迭代器
能被next()函数调用的,是可迭代对象。这是实现了__next__()函数的类。