如果有一个对象,当需要对其进行修改属性时,有2种方法
为了更好的保存属性安全,即不能随意修改,一般的处理方式为
1 class People(object):
2
3 def __init__(self, name):
4 self.__name = name
5
6 def getName(self):
7 return self.__name
8
9 def setName(self, newName):
10 if len(newName) >= 5:
11 self.__name = newName
12 else:
13 print("error:名字长度需要大于或者等于5")
14
15 man = People("jiangzi")
16 print(man.__name)
结果:
Traceback (most recent call last):
File "F:/plane/test.py", line 16, in <module>
print(man.__name)
AttributeError: 'People' object has no attribute '__name'
改:
1 class People(object):
2
3 def __init__(self, name):
4 self.__name = name
5
6 def getName(self):
7 return self.__name
8
9 def setName(self, newName):
10 if len(newName) >= 5:
11 self.__name = newName
12 else:
13 print("error:名字长度需要大于或者等于5")
14
15 man = People("jiangzi")
16 print(man.getName())
17
18 man.setName("hello")
19 print(man.getName())
20
21 man.setName("an")
22 print(man.getName())
结果:
jiangzi
hello
error:名字长度需要大于或者等于5
hello
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
lib/aa.py
index.py
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
View Code
结果:
View Code
5. __call__ 对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
用于索引操作,如字典。以上分别表示获取、设置、删除数据
1 # 定义一个父类,如下:
2 class Cat(object):
3
4 def __init__(self, name, color="白色"):
5 self.name = name
6 self.color = color
7
8 def run(self):
9 print("%s--在跑"%self.name)
10
11
12 # 定义一个子类,继承Cat类如下:
13 class SubCat(Cat):
14
15 def setNewName(self, newName):
16 self.name = newName
17
18 def eat(self):
19 print("%s--在吃"%self.name)
20
21
22 cat = SubCat("印度猫")
23 print('cat的名字为:%s' % cat.name)
24 print('cat的颜色为:%s' % cat.color)
25 cat.eat()
26 cat.setNewName('波斯猫')
27 cat.run()
结果:
cat的名字为:印度猫
cat的颜色为:白色
印度猫--在吃
波斯猫--在跑
__init__
方法,但是父类有,所以在子类继承父类的时候这个方法就被继承了,所以只要创建Bosi的对象,就默认执行了那个继承过来的__init__
方法 1 class Animal(object):
2
3 def __init__(self, name='动物', color='白色'):
4 self.__name = name
5 self.color = color
6
7 def __test(self):
8 print(self.__name)
9 print(self.color)
10
11 def test(self):
12 print(self.__name)
13 print(self.color)
14
15
16
17 class Dog(Animal):
18 def dogTest1(self):
19 #print(self.__name) #不能访问到父类的私有属性
20 print(self.color)
21
22
23 def dogTest2(self):
24 #self.__test() #不能访问父类中的私有方法
25 self.test()
26
27
28 A = Animal()
29 #print(A.__name) #程序出现异常,不能访问私有属性
30 print(A.color)
31 #A.__test() #程序出现异常,不能访问私有方法
32 A.test()
33
34 print("------分割线-----")
35
36 D = Dog(name = "小花狗", color = "黄色")
37 D.dogTest1()
38 D.dogTest2()
结果:
白色
动物
白色
------分割线-----
黄色
小花狗
黄色
简单示例:
# 定义一个父类
class A:
def printA(self):
print('----A----')
# 定义一个父类
class B:
def printB(self):
print('----B----')
# 定义一个子类,继承自A、B
class C(A,B):
def printC(self):
print('----C----')
obj_C = C()
obj_C.printA()
obj_C.printB()
----A----
----B----
如果在上面的多继承例子中,如果父类A和父类B中,有一个同名的方法,那么通过子类去调用的时候,调用哪个?继承顺序是怎么样的?
1 #coding=utf-8
2 class base(object):
3 def test(self):
4 print('----base test----')
5 class A(base):
6 def test(self):
7 print('----A test----')
8
9 # 定义一个父类
10 class B(base):
11 def test(self):
12 print('----B test----')
13
14 # 定义一个子类,继承自A、B
15 class C(A,B):
16 pass
17
18
19 obj_C = C()
20 obj_C.test()
21
22 print(C.__mro__) #可以查看C类的对象搜索方法时的先后顺序
----A test----
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.base'>, <class 'object'>)
所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
调用父类的__init__方法1(python2)
父类.__init__(self,name)
调用父类的__init__方法2
super(子类,self).__init__(name)
调用父类的__init__方法3
super().__init__(name)
1 class People(object):
2 name = 'Tom' #公有的类属性
3 __age = 12 #私有的类属性
4
5 p = People()
6
7 print(p.name) #正确
8 print(People.name) #正确
9 print(p.__age) #错误,不能在类外通过实例对象访问私有的类属性
10 print(People.__age) #错误,不能在类外通过类对象访问私有的类属性
1 class People(object):
2 address = '山东' #类属性
3 def __init__(self):
4 self.name = 'xiaowang' #实例属性
5 self.age = 20 #实例属性
6
7 p = People()
8 p.age =12 #实例属性
9 print(p.address) #正确
10 print(p.name) #正确
11 print(p.age) #正确
12
13 print(People.address) #正确
14 print(People.name) #错误
15 print(People.age) #错误
如果需要在类外修改类属性
,必须通过类对象
去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性
,这种方式修改的是实例属性
,不会影响到类属性
,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性
,除非删除了该实例属性
。
通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法
class Dog(object):
def __init__(self,name):
self.name = name
@staticmethod #把eat方法变为静态方法
def eat(self):
print("%s is eating" % self.name)
d = Dog("ChenRonghua")
d.eat()
上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。
Traceback (most recent call last):
File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/静态方法.py", line 17, in <module>
d.eat()
TypeError: eat() missing 1 required positional argument: 'self'
想让上面的代码可以正常工作有两种办法
1. 调用时主动传递实例本身给eat方法,即d.eat(d)
2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了
1 class Dog(object):
2
3 def __init__(self,name):
4 self.name = name
5
6 @staticmethod
7 def eat():
8 print(" is eating")
9
10
11
12 d = Dog("ChenRonghua")
13 d.eat()
类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量
class Dog(object):
def __init__(self,name):
self.name = name
@classmethod
def eat(self):
print("%s is eating" % self.name)
d = Dog("ChenRonghua")
d.eat()
执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的
Traceback (most recent call last):
File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py", line 16, in <module>
d.eat()
File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py", line 11, in eat
print("%s is eating" % self.name)
AttributeError: type object 'Dog' has no attribute 'name'
此时可以定义一个类变量,也叫name,看下执行效果
class Dog(object):
name = "我是类变量"
def __init__(self,name):
self.name = name
@classmethod
def eat(self):
print("%s is eating" % self.name)
d = Dog("ChenRonghua")
d.eat()
#执行结果
我是类变量 is eating
属性方法的作用就是通过@property把一个方法变成一个静态属性
1 class Dog(object):
2
3 def __init__(self,name):
4 self.name = name
5
6 @property
7 def eat(self):
8 print(" %s is eating" %self.name)
9
10
11 d = Dog("ChenRonghua")
12 d.eat()
调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了
Traceback (most recent call last):
ChenRonghua is eating
File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py", line 16, in <module>
d.eat()
TypeError: 'NoneType' object is not callable
正常调用如下
d = Dog("ChenRonghua")
d.eat
输出
ChenRonghua is eating
通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法
def getattr(object, name, default=None): # known special case of getattr
"""
getattr(object, name[, default]) -> value
Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
"""
pass
hassattr 判断object中有没有一个name字符串对应的方法或属性
def setattr(x, y, v): # real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value.
setattr(x, 'y', v) is equivalent to ``x.y = v''
def delattr(x, y): # real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
"""
示例:
1 class Foo(object):
2
3 def __init__(self):
4 self.name = 'wupeiqi'
5
6 def func(self):
7 return 'func'
8
9 obj = Foo()
10
11 # #### 检查是否含有成员 ####
12 hasattr(obj, 'name')
13 hasattr(obj, 'func')
14
15 # #### 获取成员 ####
16 getattr(obj, 'name')
17 getattr(obj, 'func')
18
19 # #### 设置成员 ####
20 setattr(obj, 'age', 18)
21 setattr(obj, 'show', lambda num: num + 1)
22
23 # #### 删除成员 ####
24 delattr(obj, 'name')
25 delattr(obj, 'func')