一、绑定方法
1、绑定给类的方法(@classmethod)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Oracle(): def __init__( self , ip, port): self .ip = ip self .port = port @classmethod # 该方法已经变成了绑定给类的方法,而不是绑定给对象了 def from_func( cls ): print ( "from func" ) return cls ( '127.0.0.1' , '3306' ) obj = Oracle( '127.0.0.1' , 3306 ) res = obj.from_func() print (res) ## 结果 # from func # <__main__.Oracle object at 0x7f7c78025668> res = Oracle.from_func() # from func 绑定给类的方法就有类来调用,特殊之处就是:会把类名当成第一个参数传给方法的第一个形参 print (res) |
注:
from_func
方法使用了@classmethod
装饰器,将其转变为类方法。类方法绑定给类而不是对象,意味着你可以直接通过类来调用该方法,而不需要先创建对象。
可以通过Oracle.from_func()
来调用from_func
方法,而不需要创建Oracle
的实例。这将输出"from func"并返回一个新创建的Oracle
对象。
即使将方法转换为类方法,仍然可以通过对象来调用该方法,但此时对象将被忽略,类方法将使用类本身作为参数。因此,在你的代码中,obj.from_func()
仍然可以正常执行,但是它将返回一个新的Oracle
对象,而不是将其赋值给res
。
综上所述,即使方法绑定给类,对象仍然可以调用该方法,但是类方法将忽略对象本身并使用类作为参数进行操作。
2、绑定给对象的方法(self 关键字进行的绑定)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Student(): school = 'sh' def __init__( self , name, age, gender): self .name = name self .age = age self .gender = gender def tell_info( self ): print ( 'name:%s age:%s gender:%s' % ( self .name, self .age, self .gender)) stu = Student( 'kevin' , 18 , 'male' ) # Student.tell_info(stu) print (stu.tell_info()) |
二、非绑定方法
1、不绑定给类使用,也不绑定给对象使用
@staticmethod # 该方法已经谁都不绑定,谁都能来调用,类和对象都可以直接来调用,其实就是个普通方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class Student: def __init__( self , name, age, gender): self .name = name self .age = age self .gender = gender self . id = self .get_code( 5 ) self .shengfenid = self .create_id() @staticmethod # 该方法已经谁都不绑定,谁都能来调用,类和对象都可以直接来调用,其实就是个普通方法 def create_id(): import uuid return uuid.uuid4() """什么时候使用静态方法:一般就是方法里面既不用对象,也不用类的时候就使用静态方法""" @staticmethod def get_code(n): code = '' import random for i in range (n): random_int = str (random.randint( 0 , 9 )) random_upper = chr (random.randint( 65 , 90 )) random_lower = chr (random.randint( 97 , 122 )) temp = random.choice([random_int, random_upper, random_lower]) code + = temp return code # 实例化一个对象,调用id和shengfenid stu = Student( 'kevin' , 19 , 'female' ) print (stu. id ) print (stu.shengfenid) # 类在外部调用方法 print (Student.create_id()) print (Student.get_code( 5 )) |
2、如果说方法里面既用到了对象,又用到了类,方法绑定给对象更合适
1
2
3
4
5
6
7
8
9
10
11
|
# 绑定给对象 def func( self ): print ( self ) print ( self .__class__) print ( self .__class__.__name__) stu = Student( 'kevin' , 19 , 'female' ) stu.func() # <__main__.Student object at 0x7f7a680ed438> # <class '__main__.Student'> # Student |
三、掩藏属性
1、为什么隐藏
在Python类中,属性可以被隐藏或封装起来,这意味着属性在类外部是不可直接访问的。
隐藏属性的目的是为了封装类的内部实现细节,提供对外部代码的界面,并增加类的灵活性和安全性。以下是隐藏属性的几个主要原因:
- 封装实现细节:
隐藏属性允许类隐藏其内部数据和实现细节,将其视为类的私有信息。这样,类的用户只能通过提供的公共方法来与类进行交互,而不需要了解类的内部实现。隐藏属性帮助实现了类的封装特性,将数据和方法进行组织和封装。
- 访问控制:
隐藏属性可以限制属性的访问范围,防止直接对属性进行修改或读取。通过定义公共方法(例如getter和setter方法),可以控制对属性的访问和修改方式。这提供了更精确的控制,防止无效或意外的访问,确保属性的合法操作和一致性。
- 类的演变和维护:
隐藏属性提供了类的灵活性,允许在不破坏外部代码的情况下修改类的内部实现。如果类的内部实现发生了变化,例如属性名称或数据结构的改变,隐藏属性可以使这些变化局限在类内部,而不影响外部代码。这种封装性有助于保持类的稳定性和可维护性。
- 安全性:
隐藏属性可以增加类的安全性,防止对属性的未经授权的修改或读取。通过将属性限制为私有,外部代码无法直接访问和修改属性,只能通过类提供的公共方法来进行操作。这提供了一种控制和保护类数据的机制,减少了意外错误和滥用的风险。
⚠️:
1. 隐藏属性在类的定义阶段,发生了变形,_类名__属性名
2. 不但可以隐藏类属性、方法、对象的属性都可以隐藏
3. 隐藏属性对外不对内,对类的外部是隐藏的,而对类的内部是开放的
2、通过➕ '__' 进行掩藏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class Student(): # '_Student__school': 'SH' _类名__属性名: 'SH' # school = 'SH' # 把school属性已经隐藏了,隐藏的意思是,在类外部不能使用了 __country = 'China' def __init__( self , name, age, gender): self .__name = name # _Student__name self .age = age self .gender = gender def __func( self ): # _Student__func _类名__函数名 print ( 'from func' ) def get_country( self ): return self .__country def set_country( self , v): if type (v) is not str : return Student.__country = v stu = Student( 'kevin' , 19 , 'male' ) |
通过查看类的名称空间可以发现掩藏后的属性、方法改为 _类名__属性名的形式
1
2
|
# 查看类的名称空间 print (Student.__dict__) |
由于隐藏属性是对外不对内的,所以,我们要想在类的外部使用,就需要在类的内部开放一个接口,返回隐藏属性的值,以便更好的对外做限制
如下:
1
2
3
4
5
6
7
|
def get_country( self ): return self .__country def set_country( self , v): if type (v) is not str : return Student.__country = v |
四、
作用:就是把方法伪装成属性来使用!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
class Student: __country = 'China' __city = 'shanghai' def __init__( self , name, age, gender): self .__name = name # _Student__name self .age = age self .gender = gender @property # 装饰器将方法伪装成属性 def country( self ): return self .__country @country .setter # 修改功能装饰器,.setter前的名字要与property下的函数同名 def country( self , v): if type (v) is not str : # 类型判断 return Student.__country = v @country .deleter # 删除功能装饰器,.deleter前的名字要与property下的函数同名 def country( self ): print ( "可以删除了" ) del Student.__country @property def city( self ): return self .__city @city .setter def city( self , v): Student.__city = v @city .deleter def city( self ): print ( "可以删除了" ) del Student.__city stu = Student( "kevin" , 20 , 'female' ) # print(stu.get_country()) print (stu.country) # 使用装饰器后,直接像调用属性一样调用方法 # stu.set_country('Japan') stu.country = '澳大利亚' print (stu.country) # del Student.country # del stu.country |
另一种写法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
class Student(): __country = 'China' __city = 'shanghai' def __init__( self , name, age, gender): self .__name = name # _Student__name self .age = age self .gender = gender def get_country( self ): return self .__country def set_country( self , v): if type (v) is not str : return Student.__country = v def del_country( self ): print ( "可以删除了" ) del Student.__country """这种方式,是有顺序要求的""" country = property (get_country, set_country, del_country) stu = Student( "kevin" , 19 , 'male' ) print (stu.country) # stu.country = 'Japan' # print(stu.a) # del stu.country |
小应用:求bmi指数
1
2
3
4
5
6
7
8
9
10
11
|
class Bmi(): def __init__( self , weight, height): self .weight = weight self .height = height @property # 装饰器伪装以后,函数可当作属性调用 def bmi( self ): return self .weight / ( self .height * * 2 ) my_bmi = Bmi( 70 , 1.82 ) print (my_bmi.bmi) |