# setattr 动态添加或者修改属性
attr_dict = {'iq': '150', 'eq': '150', 'color': 'yellow'}
t = (1,2,3)
t = 1,2
print(attr_dict.items())
# for循环遍历字典
for key,value in attr_dict.items():
# key是属性名 value是属性值
# setattr,可以将一个字符串的属性名 添加到对象的属性中
# p1.key = value 这种方式无法添加 相当于写了 p1.'iq' = '150'
setattr(p1, key, value)
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例self,并且,调用 时,不用传递该参数。除此之外,类的方法和普通函数,没有区别。类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同:
访问限制
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
,在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name
和get_score
这样的方法:
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
self.__score = score
错误写法
>>> bart = Student('Bart Simpson', 59)
>>> bart.get_name()
'Bart Simpson'
>>> bart.__name = 'New Name' # 设置__name变量!
>>> bart.__name
'New Name'
>>> bart.get_name() # get_name()内部返回self.__name
'Bart Simpson'
表面上看,外部代码“成功”地设置了
__name
变量,但实际上这个
__name
变量和class内部的
__name
变量
不是一个变量!内部的
__name
变量已经被Python解释器自动改成了
_Student__name
,而外部代码给
bart
新增了一个
__name
变量
动态语言的继承
静态语言 vs 动态语言
对于静态语言(例如Java)来说,如果需要传入Animal
类型,则传入的对象必须是Animal
类型或者它的子类,否则,将无法调用run()
方法。
对于Python这样的动态语言来说,则不一定需要传入Animal
类型。我们只需要保证传入的对象有一个run()
方法就可以了:
class Timer(object):
def run(self):
print('Start...')
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
Python的“file-like object“就是一种鸭子类型。对真正的文件对象,它有一个read()
方法,返回其内容。但是,许多对象,只要有read()
方法,都被视为“file-like object“。许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()
方法的对象。
类中方法
类似__xxx__
的属性和方法在Python中都是有特殊用途的,比如__len__
方法返回长度。在Python中,如果你调用len()
函数试图获取一个对象的长度,实际上,在len()
函数内部,它自动去调用该对象的__len__()
方法
>>> class MyDog(object):
... def __len__(self):
... return 100
...
>>> dog = MyDog()
>>> len(dog)
100
配合
getattr()
、
setattr()
以及
hasattr()
,我们可以直接操作一个对象的状态:
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
>>> hasattr(obj, 'power') # 有属性'power'吗?
True
>>> getattr(obj, 'power') # 获取属性'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
>>> fn # fn指向obj.power
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn() # 调用fn()与调用obj.power()是一样的
81
类属性和实例属性
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
AAA
(
)
:
aaa
=
10
# 情形1
obj1
=
AAA
(
)
obj2
=
AAA
(
)
print
obj1
.
aaa
,
obj2
.
aaa
,
AAA
.
aaa
# 情形2
obj1
.
aaa
+=
2
print
obj1
.
aaa
,
obj2
.
aaa
,
AAA
.
aaa
# 情形3
AAA
.
aaa
+=
3
print
obj1
.
aaa
,
obj2
.
aaa
,
AAA
.
aaa
|
情形1的结果是:10 10 10
;
情形2的结果是:12 10 10
;
情形3的结果是:12 13 13
;
1. Python中属性的获取是按照从下到上的顺序来查找属性;
2. Python中的类和实例是两个完全独立的对象;
3. Python中的属性设置是针对对象本身进行的
class Student(object):
count = 0
def __init__(self, name):
Student.count=Student.count+1
self.name = name
//类中属性赋值也需加类名
# setattr 动态添加或者修改属性
attr_dict = {'iq': '150', 'eq': '150', 'color': 'yellow'}
t = (1,2,3)
t = 1,2
print(attr_dict.items())
# for循环遍历字典
for key,value in attr_dict.items():
# key是属性名 value是属性值
# setattr,可以将一个字符串的属性名 添加到对象的属性中
# p1.key = value 这种方式无法添加 相当于写了 p1.'iq' = '150'
setattr(p1, key, value)
delatter动态删除属性同理
类方法和实例方法
pass
class Student(object):
pass
s = Student()
s.name = 'Michael' # 动态给实例绑定一个属性
print(s.name)
def set_age(self, age): # 定义一个函数作为实例方法
self.age = age
from types import MethodType
s.set_age=MethodType(set_age,s)# 给实例绑定一个方法
s.set_age(25)
print(s.age)
s1=Student()
Student.set_age=set_age # 给类绑定一个方法
s2=Student()
s2.set_age(11)
s1.set_age(11)
print(s2.age,s1.age) #给class绑定方法后,所有实例均可调用:
为了达到限制的目的,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'
使用
__slots__
要注意,
__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的: