对象:
属性是累的不是对象的,类的继承、封装、多态,类的__init__()方法,toString方法
对象:
对象常用的2个方面,可以对对象做什么,2怎么描述对象
类:
描述对象用类,特征又叫属性,attribute
类名=模块名+类名
方法:
方法就是对对象的操作
属性的本质是包含在对象中的变量
方法就是包含在对象中的函数
点记法
属性不属于类,属于各个对象
对象=属性+方法
属性;
属性是对象的,不是类的,所以属性一般都放在__init__()中
给对象绑定属性的2中方法:
生成对象前,在__init__()构造方法中定义,所有实例都绑定方法,可以给class绑定方法
生成对象后,可以给对象自由的绑定属性,给实例绑定一个方法
方法:
方法,方法的第一个参数永远是self,它指向对象本身,调用方法时,不用传self,仅传参数,self和对象自动绑定的
动态绑定方法:
>>> def set_age(self, age): # 定义一个函数作为实例方法
... self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s, Student) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25
点记法调用属性和方法
继承;
子类即是子类也是父类---多态
有了继承才能有多态
多重继承:
class Bat(Mammal, Flyable):
pass
通过多重继承,一个子类就可以同时获得多个父类的所有功能。
type()
获取对象类型
>>> type('str')
<type 'str'>
判断对象是不是某种类型
>>> import types
>>> type('abc')==types.StringType
最后注意到有一种类型就叫TypeType,所有类型本身的类型就是TypeType
type()函数既可以返回一个对象的类型,又可以创建出新的类型
通过type()函数创建的类和直接写class是完全一样的,
因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。
type()动态创建类
python文件名小写
>>> def fn(self, name='world'): # 先定义函数
... print('Hello, %s.' % name)
...
>>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
>>> h = Hello()
>>> h.hello()
Hello, world.
>>> print(type(Hello))
<type 'type'>
>>> print(type(h))
<class '__main__.Hello'>
要创建一个class对象,type()函数依次传入3个参数:
1. class的名称;
2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3. class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。
正常情况下,我们都用class Xxx...来定义类,但是,type()函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类
isinstance()
对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。
换句话说,isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上
>>> isinstance('a', (str, unicode))
True
使用dir():反射
如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:
仅仅把属性和方法列出来是不够的,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:
对单个属性的增删改查 对单个属性的增删查改
getattr(),setattr(),hasattr():方法和变量都是对象的属性,
hasattr(obj, 'x')# 有属性'x'吗?
hasattr(obj, 'power') # 有属性'power'吗?
setattr(obj, 'y', 19)设置一个属性'y'
getattr(obj, 'y')# 获取属性'y'
getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
如上我们可以对任意一个Python对象进行剖析,拿到他的内部数据
__slots__:
目的:
限制对象新增属性
使用方式:
在类中定义一个特殊变量__slots__
使用__slots__
但是,如果我们想要限制class的属性怎么办?比如,只允许对Student实例添加name和age属性。
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class能添加的属性:
>>> class Student(object):
... __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
...
然后,我们试试:
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
由于'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。
使用__slots__要注意,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的:
>>> class GraduateStudent(Student):
... pass
...
>>> g = GraduateStudent()
>>> g.score = 9999
除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。
@property
为什么要用@property
动态的绑定属性,如果我们把属性直接暴露出去,虽然写起来简单,但是,没办法检查参数,导致可以把成绩随便改
怎么用@property
Python中没有static的概念,只要是属性和方法都可以通过名字来调用
定制类:
__str__,执行print语句时调用,显示信息
__repr__,直接执行"引用s"时调用,显示信息
__iter__
目的:如果一个类想作用于for...in循环,就必须实现一个__iter__()方法,该方法返回一个迭代对象,
然后,python的for循环就会不断的调用该迭代对象的next()方法拿到循环的下一个值,知道遇到StopIteration错误是退出循环
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def next(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration();
return self.a # 返回下一个值
__getitem__
Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第5个元素:
__getattr__
没有找到score这个attribute。
要避免这个错误,除了可以加上一个score属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性。
注意,只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。这是因为我们定义的__getattr__默认返回就是None
metaclass
---> 为什么要使用metaclass
--->怎么使用metaclass
控制类的创建行为是什么意思,就是对类添加方法
metaclass就是类的模板
编写程序的时候,千万不要把实例属性和类属性使用相同的名字,为什么
因为,取实例名字的时候,优先取实例属性名字,没有实例属性名字,就会去类的属性名字
__init__方法就是构造方法,
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
我们自己写的类,如果也想用len(myObj)的话,就自己写一个__len__()方法:
>>> class MyObject(object):
... def __len__(self):
... return 100
...
>>> obj = MyObject()
>>> len(obj)
100
装饰器可以给函数动态的加上功能,也可以给类的方法动态的加上功能
@property装饰器就是负责把一个方法变成属性调用
对get方法直接加上@property就可以了,@property本身又创建了另一个装饰器@get方法的名字.setter负责把setter方法变成属性值,于是,我们就拥有一个可控的属性操作