注意点
对象的__dict__是可以赋值修改的,但类的__dict__不能修改,是只读的
对象和类的__dict__有各自的存储空间类的属性可以被各个对象共享
上一节的补充点:
- 可以通过__slots__限定对象可添加的属性
class Person:
__slots__=['age']
pass
p=Person()
p.age=1 #可以
p.num=2 #报错
方法相关的知识点
方法的概念和作用
- 封装一系列的行为和动作
- 和函数很类似,但是有所区别:调用方式
- 调用方式:p.eat()
要调用对象
方法的划分
- 方法的第一个参数必须是要接收的数据类型
- 实例方法:需要传入实例;self
- 类方法:需要传入类;cls
- 静态方法:没有限制
class Person:
def eat2(self):
print('this is实例方法')
@classmethod
def leifangfa(cls):
print('this is类方法')
@staticmethod
def jingtaifangfa():
print('this is 静态方法')
#调用:
p=Person()
p.eat2()
Person.leifangfa()
Person.jingtaifangfa()
方法的存储
- 方法都存储类的__dict__里面,不存储在对象里面
实例方法
class Person:
def eat(self,food):
print('eating',food)
p=Peason()
p.eat('potato')
- 标准调用:利用实例(即对象)去调用,不需要自己传递第一个参数self
- 其他调用(基本不用):1使用类调用2间接调用
类方法
class Person:
@classmethod
def leifangfa(cls,a):
print('这是一个类方法',cls,a)
Person.leifangfa(123)
#这是一个类方法 <class '__main__.Person> 123
p=Person()
p.leifangfa(666)
#这是一个类方法 <class '__main__.Person> 666
#这告诉我们:可以用实例调用类方法,但是实例会被忽略
func=Person.leifangfa
func(111)
#这是一个类方法 <class '__main__.Person> 111
#装饰器的作用:保证这个函数原本不改变的情况下,给这个函数增加一些功能
class A(Person):
pass
A.leifangfa(0)
#这是一个类方法 <class '__main__.Person> 0
静态方法
class Person:
@staticmethod
def jingtai():
print('这是一个静态方法')
Person.jingtai()
#这是一个静态方法
p=Person()
p.jingtai()
#这是一个静态方法
func=Person.jingtai
func()
#这是一个静态方法
- 可以通过类调用,也可以用实例调用
补充内容
1、访问权限问题
- 在实例方法里面可以找到类属性、实例属性
- 在类方法里面只可以找到类属性,不能找到实例属性
- 在静态方法里面不能找到类属性也不能找到实例属性
但是可以通过索引类去获取 - cls表示默认传入的是类,self表示默认传入实例
2、类的补充内容
元类
- 创建类对象的类
- 元类可以创建新的类
- 对象10的类是int,int的类是type
对象"abc"的类是str,str的类是type
type就是元类
用元类创建类对象
#type(类名,tuple,dict)
def run:
print("run")
xxx=type("Dog",(),{"count":0,"run":run})
# 得到一个叫xxx的类
# 它有类属性count=0,类方法run
p=xxx()
p.run()
#run
print(p.count) #0
类的描述
- 类本身的功能、类属性、类方法等
- 写在前面用"""引起来
类的描述的获取
- 1.用help(Person)获得所有的描述
- 2.使用内置模块pydoc
类的属性分类
- 保证数据安全性
- 通过下划线完成伪私有效果
- 公有属性
_保护属性
__私有属性
1.公有属性
class Animal:
x=10
def test(self):
print(Animal.x)
print(self.x)
pass
class Dog(Animal):
def test2(self):
print(Dog.x)
print(self.x)
pass
#测试代码
a=Animal()
a.test()
#可以得到10,即在类的内部可以访问到这个公有属性
d=Dog()
d.test2()
#可以得到10,即在类的外部可以访问到这个公有属性
print(Animal.x)
print(Dog.x)
print(a.x)
print(d.x)
#这样也都可以访问到x
- 跨模块访问公有属性
# file1.py
a=666
# file2.py
import file1
print(file1.a) #666
# file3.py
from file1 import *
print(a) #666
以上3段代码告诉我们:可以直接访问到a
2.受保护的属性
class Animal:
_x=10
def test(self):
print(Animal._x)
print(self._x)
pass
class Dog(Animal):
def test2(self):
print(Dog._x)
print(self._x)
pass
#测试代码
a=Animal()
a.test()
#可以得到10,即在类的内部可以访问到这个受保护的属性
d=Dog()
d.test2()
#可以得到10,即在类的外部可以访问到这个受保护的属性
print(Animal._x)
print(Dog._x)
print(a._x)
print(d._x)
#这样也都可以访问到x,但是会有警报(黄色波浪线)
可以访问,但是会有警报,建议不要访问
what about跨模块访问受保护的属性?
# file1.py
_a=666
# file2.py
import file1
print(file1._a) #666
#可以访问但是有警报
# file3.py
from file1 import *
print(_a)
# 无法访问 直接报错
- 只可以用import的形式访问,不可以from...import...
- 但是如果file1里加入以下代码的话就可以正常访问这个受保护的属性
__all__=['_a']
3.私有属性
class Animal:
__x=10
def test(self):
print(Animal.__x)
print(self.__x)
pass
class Dog(Animal):
def test2(self):
print(Dog.__x)
print(self.__x)
pass
#测试代码
a=Animal()
a.test()
#可以得到10,即在类的内部可以访问到这个私有属性
d=Dog()
d.test2()
#报错,不可以得到10,即在类的外部不可以访问到这个私有属性
print(Animal.__x)
print(Dog.__x)
print(a.__x)
print(d.__x)
#4条都会报错,在外部不可以访问私有属性
结论:私有属性在本模块的其他位置都不可以访问,不管通过类、子类、类或子类的实例,都不可以访问到。
只可以在类的内部访问到。
可以访问,但是会有警报,建议不要访问
what about跨模块访问?
——情况和一个下划线的一致。