文章目录
类与对象
“类"就像是工厂里模具,以它为模板,选出来成千上万的产品,才是被我们消费购买使用的东西。这些产品就像是"实例对象”。
从模具变成产品,也就是从"类"变成"实例对象"的过程,就叫做实例化。
类方法与类属性
类是一个函数包,可以放置函数和变量,然后类中的函数可以很方便的使用类中的变量。
语法:class语句来定义一个类。def自定义一个函数。
类方法
定义:在类中被定义的函数被称为类的方法, 描述的是这个类能做什么。
调用类的方法:类名.函数名()
#创建一个名为“ClassName”的类,类名一般首字母要大写,(): 不能丢
class ClassName():
#假如定义一个名为“你好”的类,可以写成class Hello():
def function1():
# 定义类中的函数1
class ClassA():
def func1():
print("我是ClassA的第一个方法!")
def func2():
print("我是ClassA的第二个方法!")
def func3():
print("我是ClassA的第三个方法!")
ClassA.func1()
ClassA.func2()
ClassA.func3()
类的属性
定义:在类中被定义的变量被称为类的属性。
调用类的属性:类名.属性名
class ClassA():
var1 = 100
var2 = 200
var3 = '你好'
print(ClassA.var1)
print(ClassA.var2)
print(ClassA.var3)
增加/修改类的属性:可以使用类名.变量名在类的外面进行操作。
class ClassA():
var1 = 100
var2 = 200
var3 = '你好'
ClassA.var1 = 99
ClassA.var4 = 'add a var'
print(ClassA.var1)
print(ClassA.var4)
类方法与类的属性结合使用
方法一:调用类方法与类的属性的结合。
class Robot():
macaron = 20
cannele = 15
cheese_bread = 23
#以上为类的属性
def welcome_supermarket():
print("你好,欢迎来到超市的面包区!")
def pick_one():
print("我们热销有三款面包哦,欢迎选购~")
def payment():
print("收银台在这里,欢迎下次光临~")
#以上为类的方法
#打印类的属性
print(Robot.macaron)
print(Robot.cannele)
print(Robot.cheese_bread)
#调用类的方法
Robot.welcome_supermarket()
Robot.pick_one()
Robot.payment()
方法二:注意 如果类中的函数不需要类中的变量时,就不要用@classmethod、cls、cls. 三处格式,否则也会报错。
class ClassA():
var1 = 100
var2 = 200
@classmethod #类方法,@classmethod声明了func1是类方法,这样子才允许func1使用类属性中的数据。
def func1(cls): # class的缩写,如果func1想使用类的属性,就要写上cls作为func1的第一个参数,也就是把这个类作为参数传给自己,这样就能被允许使用类中的数据。
print(cls.var1)
print(cls.var2)
ClassA.func1()
类方法传参数
方法一:将参数放在类的内部,然后类的方法从内部获取参数。
class ClassA():
num = 1
@classmethod
def add_100(cls):
sum = cls.num + 100
print("计算结果如下:")
print(sum)
ClassA.add_100()
方法二:直接 参数=xx。
class ClassA():
def add_100(num):
sum = num + 100
print("计算结果如下:")
print(sum)
num = 1
ClassA.add_100(num)
方法三:同时使用内部和外部的参数。
举例1:
class ClassA():
num = 1
@classmethod
def add_100(cls,para):
sum = cls.num + 100 + para
print("计算结果如下:")
print(sum)
para= 10
ClassA.add_100(para)
举例2:当类方法要使用多个外部参数,我们要预设几个参数位置。
class ClassA():
num = 1
@classmethod
def add_100(cls,para1,para2,para3):
sum = cls.num + 100 + para1 + para2 + para3
print("计算结果如下:")
print(sum)
para1 = 10
para2 = 20
para3 = 30
ClassA.add_100(para1,para2,para3)
类属性:增加/修改类属性
方法一:用 类.变量=xx 直接增加、修改类属性。
class ClassA():
@classmethod
def add_class_var(cls):
print("打印新增的类的属性:" + str(cls.var1))
ClassA.var1=100
ClassA.add_class_var()
方法二:用类方法去增加、修改。
class ClassA():
@classmethod
def add_class_var(cls):
cls.var1 = "hello"
ClassA.add_class_var()
print("打印新增的类的属性:" + ClassA.var1)
类的实例化
实例化基本格式:实例名=类() 为类创建一个实例,然后再使用 实例名.函数() 调用对应的方法。
注意:与直接调用类格式不一样。
class ClassA():
var1 = 'abc'
def func(self): #self代表“实例”的意思,编码规范,不是强求。
print('已经完成了实例化。')
print('类属性的值是:'+ self.var1)
a=ClassA()
a.func()
class Robot():
macaron = 20
cannele = 15
cheese_bread = 23
#以上为类的属性
def pick_one(self):
print("我们热销有三款面包哦,欢迎选购~")
print('马卡龙:' + str(self.macaron))
print('可丽露:' + str(self.cannele))
print('芝士面包:' + str(self.cheese_bread))
a=Robot()
a.pick_one()
注意:
1、实例化后,只要你类中使用了def语句那必须在其后的括号里把第一个位置留给self。
2、当支持实例化时,就不能再直接使用类方法。
实例方法与类方法
重写类方法:类.原始函数=新函数
第一步:在类的外部写一个函数
第二步:把这个新函数的函数赋值给类的原始函数。
class ClassA():
def func1(self):
print('我是原始函数')
def func2(self):
print('我是重写后的新函数')
a = ClassA()
a.func1()
ClassA.func1=func2
a.func1()
class Lucky():
def lucky_double(self):
print('好的,我把你的幸运数字记住了哦,并翻倍66倍还给你' + str(self.lucky_number*66))
def lucky_new_double(self):
print('好的,我把你的幸运数字记住了哦,并翻倍88倍还给你' + str(self.lucky_number*88))
Lucky.lucky_number = int(input('请输入你的幸运数字'))
a = Lucky()
a.lucky_double()
Lucky.lucky_double=lucky_new_double
a.lucky_double()
a.lucky_double=lucky_new_double # 尝试重写实例方法,将会报错
a.lucky_double()
注意:重写类方法,让实例方法发生变化,但我们不能重写实例方法。
实例属性和类属性
实例属性和类属性:实例后获得类属性,所以实例属性和类属性完全相等。
class ClassA():
var1 = 100
a = ClassA() #实例化,得到实例对象a
b = ClassA() #实例化,得到实例对象b
print(a.var1)
print(b.var1)
举例:修改实例属性
class ClassA():
var1=100
a=ClassA()
b=ClassA()
print('原始属性值')
print(a.var1)
print(b.var1)
ClassA.var1='abc' # 修改类属性
print('修改后属性值')
print(a.var1) # 实例属性同步变化
print(b.var1)
初始化函数
初始化函数作用:当你创建一个实例的时候,这个函数就会被调用,初始化当前对象的相关属性,无返回值。上面的代码在执行的实例=类()时,就自动调用__init__(self)函数。
class ClassA():
def __init__(self):
print('实例化成功!')
a = ClassA() #创建对象,调用__init__()初始属性。
class ClassA():
def __init__(self,para1,para2):
self.var1 = para1 #实例属性
self.var2 = para2
def print_var(self):
print('变量1的值是:' + str(self.var1))
print('变量2的值是:' + str(self.var2))
class ClassB(ClassA):
def sum_var(self):
var_sum = str(self.var1 + self.var2)
print('所有变量的和是:' + var_sum)
b = ClassB(100,200)
b.print_var()
b.sum_var()
在一个A类中调用B类,自动调用B类下面的 init(self) 函数。
class A():
def func_A(self,name1='lily',name2='Jack'):
names = B(name1,name2)
return names
class B():
def __init__(self,para1,para2):
self.var1 = para1
self.var2 = para2
print(self.var1)
print(self.var2)
def func_B(self,para3,para4):
print("在类A中直接调用B类,只会运行__init__初始函数下面的代码,不影响A类中其他函数。")
a = A()
result=a.func_A()
另一种写法:
class A():
def func_A(self,name1='lily',name2='Jack'):
names = B(name1,name2)
return names
class B():
def __init__(self,para1,para2):
self.var1 = para1
self.var2 = para2
def func_B(self):
return self.var1
def func_C(self):
return self.var2
a=A()
result=a.func_A()
result.func_B()
result.func_C()
类的继承
如果新写的类,有许多的代码和旧类相同,又有一部分不同的话 ,可以用继承的方式避免重复写代码。
在python里,我们统一把旧的类称为父类,新写的类称为子类,子类可以在父类基础上改造类方法,所以我们可以说子类继承了父类。
class ClassA():
def __init__(self,para1,para2):
self.var1 = para1
self.var2 = para2
def print_var(self):
print('变量1的值是:' + str(self.var1))
print('变量2的值是:' + str(self.var2))
class ClassB(ClassA):
def sum_var(self):
var_sum = str(self.var1 + self.var2)
print('所有变量的和是:' + var_sum)
b=ClassB(100,200)
b.print_var()
b.sum_var()
类的重写: str()方法
作用:用于返回一个“对象的描述”,对于内置函数str()经常用于print()方法查看对象的信息。
class A():
def __init__(self,name,age):
self.name=name
self.__age=age
p=A('lily',18)
p
# 输出:
# <__main__.A at 0x2b2f3c81640>
重写__str__()方法
class A():
def __init__(self,name,age):
self.name=name
self.__age=age
def __str__(self):
'''将对象转化成一个字符串'''
return "名字是:{0},年龄是{1}".format(self.name,self.__age)
p=A('lily',18)
print(p)
# 输出:
# 名字是:lily,年龄是18
@property
@property作用:python的一种装饰器,用来修饰方法的。
- 修饰方法,会将方法转换为相同名称的只读属性。
class A():
@property
def funcA_with_property(self):
return 14
def funcA_without_property(self):
return 13
a=A()
a.funcA_with_property # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。
# 输出:
# 14
a.funcA_without_property() #没有加@property , 必须使用正常的调用方法的形式,即在后面加()
# 输出:
# 13
注意: 使用@property进行修饰后,又在调用的时候,方法后面添加了(),那么就会显示错误的信息:TypeError: ‘int’ object is not callable,原因是使用@property后,方法变成了一个属性,如果后面加入(),就是当作函数来调用,而它不是callable(可调用)的。
class A():
@property
def funcA_with_property(self):
return 14
a=A()
a.funcA_with_property()
- 与所定义的属性配合使用,可以防止属性被修改。
class A():
def __init__(self):
self.name1='lily'
self.name2='Jack'
@property
def print_name1(self):
return self.name1
@property
def print_name2(self):
return self.name2
a=A()
a.print_name1
# 输出:
# 'lily'
a.print_name2
# 输出:
# 'Jack'
下面的方法可以参考的使用场景:在A类中调用B类,但是与B类中需要输出的属性配合使用,直接输出某些属性值,如下例,直接输出属性var1,var2。
class A():
def func_A(self,name1='lily',name2='Jack'):
names = B(name1,name2)
return names
class B():
def __init__(self,para1,para2):
self.var1 = para1
self.var2 = para2
@property
def func_B(self):
return self.var1
@property
def func_C(self):
return self.var2
a=A()
result=a.func_A() #result其实是属于B类,打印result出来可以看到"<__main__.B at 0x2b2f3c49910>"
result.func_B
# 输出:
# 'lily' 一直没理解这种方法为什么可以调用出
result.func_C
# 输出:
# 'Jack'
示例:
参考文章:
https://zhuanlan.zhihu.com/p/64487092
上面的例子参考《四、实际应用-实例二-收取邮件的代码封装》
私有属性、私有方法
私有属性与私有方法:通常约定两个下划线开头的属性(方法)是私有的,其他为公共的。
- 类内部可以访问,类外部不可以访问。
- 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)。
class A():
def __init__(self,name,age):
self.name=name #实例属性
self.__age=age #私有实例属性
def funcA(self):
print("实例属性:",self.name)
print("私有实例属性:",self.__age)
def __funB(self):
print("私有方法")
p1=A("lily","18")
print(p1.name)
p1.funcA()
# 输出:
# lily
# 实例属性: lily
# 私有实例属性: 18
print(p1.__age) #直接访问私有属性,报错
p1.__funB() #直接访问私有方法,报错
print(dir(p1)) # ['_A__age', '_A__funB', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'funcA', 'name']
从上面内建函数dir()可以看到其中一些原由,“__age”属性在运行时,属性名被改为了“_A__age”,所以通过“_类名__私有属性(方法)名”访问私有属性,如下面:
print(p1._A__age) #通过这种方式可以直接访问到私有属性。通过dir 可以查到属性:_A__age
另一个通过“_类名__私有属性(方法)名”访问私有属性示例:
class A(object):
def __init__(self):
self.__private()
self.public()
def __private(self):
print('A.__private()')
def public(self):
print('A.public()')
class B(A):
def __private(self):
print('B.__private()')
def public(self):
print('B.public()')
b = B()
# 输出:
# A.__private()
# B.public()
dir(A)
# 输出:
# _A__private
# __init__
# public
我们可以看到A类中的__private消失了,变成_A__private,因此实际A类变成如下:
class A(object):
def __init__(self):
self.__private() # 变成 self._A__private
self.public()
def __private(self): # 变成 _A__private
print('A.__private()')
def public(self):
print('A.public()')
class B(A):
```
#继承A类中初始化函数,因此实际继承的如下,所以,输出A.__private()
#def __init__(self):
# self._A__private
# self.public()
```
def __private(self):
print('B.__private()')
def public(self):
print('B.public()')
参考文章:
https://blog.csdn.net/u013250861/article/details/109230731
https://www.cnblogs.com/fengff/p/9290910.html