python--面向对象:类和对象命名空间
一、一个类可以定义两种属性:静态属性和动态属性
(一)对于不可变数据类型来说,类变量最好用类名操作,也可以用对象操作,但是只能查,不能改,对象改的都只是相当于在自己的命名空间里重新建立了一个
class Person: language='Chinese' #字符串是不可变数据类型 def __init__(self): #可以没有参数 pass
1.类操作(根据上面的例子)
查 print(Person.language) #Chinese 类操作 改 Person.language='English' #类操作更改类属性 print(Person.language) #English
2.对象操作类属性,不建议用,看一下详解‘坑’
查,是没有什么问题的,查的过程是对象buty现在自己的命名空间找,找不到从类的命名空间找,再找不到就报错,这里要谨记对象不能找全局作用域
buty=Person() #定义一个对象
mary=Person() print(buty.language) #Chinese #对象操作,但是不能更改类属性,只能查 print(mary.language) #Chinese 同上
改,不可以改类属性,原因如下:
buty.language='English'
print(Person.language) #Chinese
print(buty.language) #English 说明对象操作不能更改类属性,只能查, 这种操作只是在对象buty是内存空间添加了language='English’
(二)对于可变数据类型来说,类对象名的修改是共享的,重新赋值是独立的(但是通过对象对类名的操作都是在对象的命名空间里重新建立了一个,对类的静态属性没有任何影响)
class Person: language=['Chinese'] #列表是可变数据类型 def __init__(self): #可以没有参数 pass
1.类操作
查 print(Person.language) # ['Chinese'] 类操作 改 Person.language[0]='English' #列表通过索引修改,
Person.language.append('japanses') #通过append添加
print(Person.language) # ['English', 'japanses']
Person.language=['English'] #['English'] #虽然也是成功修改成了English,但是实质是内部的重新赋值,不会再打印‘japanses’
Person.__dict__['language']='English' # 报错,这种写法不能改变类属性,因为面向对象中的 dict 不支持项目分组 print(Person.language)
2.对象操作
#对象操作:修改类对象,对象操作查看类对象, buty=Person() #定义一个对象 mary=Person() buty.language [0]='English' # ['English'] #先通过对象操作修改类对象 print(buty.language) #['English'] #对象操作修改类对象,对于不同对象的操作查看的时候,结果是共享的 print(mary.language) #['English'] #虽然只是通过buty修改类对象,但是mary也会跟着修改langusage,会共享修改结果 # 对象操作:重新赋值类对象,对象操作查看类对象 buty.language=['English'] #对象操作重新赋值类对象 print(buty.language) #['English'] # print(mary.language) #['Chinese'] #通过buty对象操作重新赋值类对象,mary的language不会改变,因为重新赋值是独立的 print(Person.language) #['Chinese']
(三)练习题
创建一个类,每实例化一个对象就计数
最终所有的对象共享这个数据
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Person: count=0 count+=1 def __init__(self): pass join=Person() print(Person.count)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo: count = 0 def __init__(self): Foo.count += 1 f1 = Foo() print(f1.count)
(四)认识绑定方法:对象名.方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo: def func(self): #定义一个方法 pass f1=Foo() print(f1.func) # 绑定<bound method Foo.func of <__main__.Foo object at 0x01833BB0>> #对比打印 print(Foo.func) #<function Foo.func at 0x018721E0> print(f1) #<__main__.Foo object at 0x00713BB0> print(Foo) #<class '__main__.Foo'>
(五)总结:
# 类里的名字有 类变量(静态属性量)+ 方法名(动态属性) # 对象里的名字 对象属性 # 对象 —— > 类 # 对象找名字 : 先找自己的 找类的 再找不到就报错 # 对象修改静态属性的值 # 对于不可变数据类型来说,类变量最好用类名操作 # 对于可变数据类型来说,对象名的修改是共享的,重新赋值是独立的
二、组合 在一个类里面调用另一个类方法
from math import pi class Circle: def __init__(self,r): self.r = r def area(self): return self.r**2 * pi def perimeter(self): return 2*pi*self.r class Ring: def __init__(self,c_1,c_2): #ring = Ring(10,5)把10和5 传进去给c_1=10 c_2=5 self.c_1=Circle(c_1) #Circle(10) 在内部实例化外部一个类 # Circle(10)得到一个对象,进而self.c_1==Circle类的一个对象ring,进而self.c_1.area()是在调用Circle类的面积公式 self.c_2=Circle(c_2) #Circle(5) def area(self): #下面的调用ring.area(),意思是把ring传给self return self.c_1.area()-self.c_2.area() def perimeter(self): return self.c_1.perimeter() + self.c_2.perimeter() ring = Ring(10,5) print(ring.area()) #==print(Ring.area(ring)) print(ring.perimeter())
练习:运用组合:输出老师的生日
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Teacher: def __init__(self,name,birthday): self.name=name self.b_t=birthday class Birthday: def __init__(self,birthday): self.birthday=birthday b=Birthday('2015.2.4') t=Teacher('join',b) print(t.b_t.birthday) #2018
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Teacher: def __init__(self,name,birthday): self.name=name self.t_b=Birthday(birthday) class Birthday: def __init__(self,birthday): self.birthday=birthday t=Teacher('join',2018) print(t.t_b.birthday) #2018