Python录屏学习
类
- 定义类
class() - 类的属性
self.属性名 是实例属性 - 类的方法
- 创建实例
- 类本身就是一个实例,可以对其进行操作
- 再类里直接定义的属性,称为类属性,类属性由所有对象共享.
可以创建类的属性,然后作为一个共享的属性
class C:
num=0
def __init__(self):
self.name="ss"
C.num+=1
print(C.num)
def print_num(self):
print(C.num)
c0=C()
c1=C()
c2=C()
C.num+=1
c2.print_num()
#1
#2
#3
#4
- 属性私有化
- 两个下划线开头
__name
为什么双下划线不能访问
在 实例.dict 中,保存着实例的一些属性,当用双下划线命名时,后台将名字更改了,原来dict里面装的实例的属性,双下划线开头的属性,会被转换为:_类名+属性名。比如原来的“_name”,被后台改为了“类名__name”。实际上如果了解了更改的规则的话,还是能更改的。
- 单下划线开头,约定的,不能真正的无法更改
_name
- 属性的更改及检查有效性
通常直接给属性赋值时,无法检查赋值的有效性,因此常属性前面加两个下滑线,使之变为不可改变的属性,之后创建更改属性的方法,并在方法里加入检查赋值有效性的语句.这样既能让属性可以修改,同时也保证了对赋值有效性的检查.
class Student:
def __init__(self,name,age):
self.__name=name
self.__age=age
def set_name(self,name):
if not len(name)<3:
self.name=name
def get_name(self):
return self.__name
这种使用 get/set 方法来封装对一个属性的访问在许多面向对象编程的语言中都很常见。
但是写 s.get_score() 和 s.set_score() 没有直接写 s.score 来得直接。
有没有两全其美的方法?----有。
@property 装饰器 和@属性名.setter
因为Python支持高阶函数,在函数式编程中我们介绍了装饰器函数,可以用装饰器函数把 get/set 方法“装饰”成属性调用:
class Student(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
看上面代码可知,把get方法变为属性只需要加上@property装饰器即可,此时@property本身又会创建另外一个装饰器@score.setter,负责把set方法变成给属性赋值,这么做完后,我们调用起来既可控又方便
注意: 第一个score(self)是get方法,用@property装饰,第二个score(self, score)是set方法,用@score.setter装饰,@score.setter是前一个@property装饰后的副产品。
现在,就可以像使用属性一样设置score了:
>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
...
ValueError: invalid score
说明对 score 赋值实际调用的是 set方法。
@staticmethod和@classmethod的用法
不用实例化就直接调用类的方法.
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。
而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。
既然@staticmethod和@classmethod都可以直接类名.方法名()来调用,那他们有什么区别呢
从它们的使用上来看,
@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。
下面上代码。
class A(object):
bar = 1
def foo(self):
print 'foo'
@staticmethod
def static_foo():
print 'static_foo'
print A.bar
@classmethod
def class_foo(cls):
print 'class_foo'
print cls.bar
cls().foo()
###执行
A.static_foo()
A.class_foo()
输出
static_foo
1
class_foo
1
foo
继承
继承父项的属性
class A:
def __init__(self):
self.name="A"
class B:
def __init__(self):
self.name="B"
class C(A):
pass
c=C()
print(c.name)
#A
super().init() 若有自己的属性,又想继承父项属性
要在自己的init中加入super().init()
没写super().init() 的情况
#没写super().__init__() 的情况
class A:
def __init__(self):
self.name="A"
class B:
def __init__(self):
self.name="B"
class C(A):
def __init__(self):
self.age=12
c=C()
print(c.name)
#AttributeError: 'C' object has no attribute 'name'
写了super().init() 的情况
class A:
def __init__(self):
self.name="A"
class B:
def __init__(self):
self.name="B"
class C(A):
def __init__(self):
super().__init__()
self.age=12
c=C()
print(c.name)
#A
多继承
多继承会导致程序混乱,尽量不要使用
所有类都会默认继承subject类
如果继承的两个父项中有相同的内容,则按顺序优先
class A:
def __init__(self):
self.name="A"
class B:
def __init__(self):
self.name="B"
class C(A,B):
def __init__(self):
super().__init__()
self.age=12
c=C()
print(c.name)
#A
- C.mro 查看继承顺序
class A:
def __init__(self):
self.name="A"
class B:
def __init__(self):
self.name="B"
class C(A,B):
def __init__(self):
super().__init__()
self.age=12
c=C()
print(C.__mro__)
#(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
- 如果是类的类成员,排序在父项之后
class A:
def __init__(self):
self.name="A"
class B:
def __init__(self):
self.name="B"
class C(A,B):
name="C"
def __init__(self):
super().__init__()
self.age=12
c=C()
print(c.name)
#A
对父项方法的调用
class A:
def __init__(self):
self.name="A"
def print_a(self):
print("aaaaa")
class B:
def __init__(self):
self.name="B"
class C(A,B):
name="C"
def __init__(self):
super().__init__()
self.age=12
c=C()
c.print_a()
#aaaaa
- 对父项方法的调用并加上自己的改造
class A:
def __init__(self):
self.name="A"
def print_a(self):
print("aaaaa")
class B:
def __init__(self):
self.name="B"
class C(A,B):
name="C"
def __init__(self):
super().__init__()
self.age=12
def print_a(self):
super().print_a()
print("a-a-a")
c=C()
c.print_a()
#aaaaa
#a-a-a
用组合实现继承的功能
程序中除非对继承很清楚,最好用组合来替代
class A:
def __init__(self):
self.name="A"
def print_a(self):
print("aaaaa")
class B:
def __init__(self):
self.name="B"
class C(A,B):
name="C"
def __init__(self):
super().__init__()
self.age=12
def print_a(self):
print("a-a-a")
class D:
def __init__(self):
self.a=A()
def print_a(self):
self.a.print_a()
print('d_a_a')
d=D()
d.print_a()
#aaaaa
#d_a_a
isinstance(c,C)判断是不是某个类的实例
这对自己的类,和父项,都输出True
issubclass(C,A)判断是不是子类
语法糖
https://blog.csdn.net/five3/article/details/83474633
语法糖(Syntactic sugar):
计算机语言中特殊的某种语法
这种语法对语言的功能并没有影响
对于程序员有更好的易用性
能够增加程序的可读性