python 成员变量不初始化_Python类的常见问题

一、class

Python中的class包含以下两点:

类的属性:类中所涉及的变量 类的方法:类中函数

如果类定义是这样的:

class MyClass:

"""A simple example class"""

i = 12345

def f(self):

return 'hello world'

那么 i就是类的属性 和 f 就是类的方法。 __doc__ 也是一个有效的属性,将返回所属类的文档字符串: "Asimple example class"。

类的 实例化 是使用函数表示法。 可以相像类对象就是会返回一个新的类实例的不带参数的函数。 举例来说(假设使用上述的类):

x = MyClass()

二、init函数(方法)

在python中创建一个新式类时,一般都会定义一个 __init__ 方法,用来对类的实例进行初始化。但是 __init__ 方法并不是类的构造方法 .(或者说在python3以后 __init__不是类的构造方法,只是类的初始化方法,python3类的构造方法变成了__new)不用init()方法定义类

定义一个矩形的类,目的是求周长和面积。

class Rectangle():

def getPeri(self,a,b):

return (a + b)*2

def getArea(self,a,b):

return a*b

rect = Rectangle()

print(rect.getPeri(3,4))

print(rect.getArea(3,4))

print(rect.__dict__)

得到结果:14 12 {}

从上例中可以看到,我们在类中并没有定义init()方法,但是也能够得到类似的要求,结果返回了矩形实例rect的周长及面积。 但是,我们通过print(rect.dict)来看这个实例的属性,竟然是空的,我定义了一个矩形,按理来说它的属性应该是它的长、宽。但是它竟然没有。这就是没有定义init()的原因了。 并且,在实例化对象的时候,rect = Rectangle()参数为空,没有指定a、b的值,只有在调用函数的时候才指定了。且类中定义的每个方法的参数都有a、b,这显然浪费感情,在类中直接指定方法就可以了。 因此吧,需要在类中定义init()方法,方便创建实例的时候,需要给实例绑定上属性,也方便类中的方法(函数)的定义。

2、用init()方法定义类

init函数(方法)的第一个参数必须是 self(self为习惯用法,也可以用别的名字),后续参数则可 以自由指定,和定义函数没有任何区别

class Rectangle():

def __init__(self,a,b):

self.a = a

self.b = b

def getPeri(self):

return (self.a + self.b)*2

def getArea(self):

return self.a * self.b

rect = Rectangle(3,4)

print(rect.getPeri())

print(rect.getArea())

print(rect.__dict__)

结果

14 12 {'a': 3, 'b': 4}

上述同样的例子,采用init()方法定义类,如下:

定义完init()后,创建的每个实例都有自己的属性,也方便直接调用类中的函数。

三、私有成员变量

Python的类并不使用关键字区分是私有成员和共有成员,但是为啥私有成员变量外面还是访问不到呢?

首先说一下,带有两个下划线开头的函数是声明该属性为私有,不能在类地外部被使用或直接访问。

class Students:

def __init__(self,sex,name,age,scores):

self.__sex = sex

self.age = age

self.name =name

self.scores = scores

def get_data(self):

return self.name,self.age,self.scores,self.__sex

stu = Students('男','taon','23','90')

print(stu.__sex,stu.__dict__)

运行结果:

AttributeError: 'Students' object has no attribute '__sex'

其实还是可以被外部访问到的,只不过换了名字罢了。Python会在类的内部自动的把你定义的spam变量的名字替换成为 _classname__spam(注意,classname前面是一个下划线,spam前是两个下划线),Python把这种技术叫做“name mangling”。因此,用户在外部访问spam的时候就会提示找不到相应的变量。 )

于是将上面的代码改为:

class Students:

def __init__(self,sex,name,age,scores):

self.__sex = sex

self.age = age

self.name =name

self.scores = scores

def get_data(self):

return self.name,self.age,self.scores,self.__sex

stu = Students('男','tao','23','90')

print(stu._Students__sex,stu.__dict__)

运行结果:

男 {'name': 'tao', '_Students__sex': '男', 'age': '23', 'scores': '90'}

看上面实例的属性也知道,这不过sex的名字被换了而已。这样就变成私有了,哈哈哈哈。

四、新式类、经典类

由于自己是从Python3入门学习的,所以在类的声明时并未留意到基类object的书写与否 是否会对程序结果造成影响(事实上,并不会有所影响),但 是,在Python2中,基类object书写与否 会对结果造成影响。

在Python 3.x中取消了经典类,默认都是新式类,并且不必显式的继承object,也就是说

class Person(object):pass

class Person():pass

class Person:pass

三种写法并无区别

但是在Python2.x中,默认都是经典类,只有显式继承了object才是新式类,即:

class Person(object):pass 新式类写法

class Person():pass 经典类写法

class Person:pass 经典类写法

他们最明显的区别在于继承搜索的顺序发生了改变

经典类的MRO(method resolution order 基类搜索顺序)算法是采用深度优先搜索 : 先深入继承树左侧查找,然后再返回,开始查找右侧

新式类的MRO算法采用C3算法广度优先搜索 : 先在水平方向查找,然后再向上查找

### Python 初始化方法 `__init__` 和私有变量 在 Python 中,初始化方法通过定义特殊的方法 `__init__` 来实现。此方法会在每次创建新实例时自动调用[^2]。 #### 私有变量的定义与使用 为了定义私有变量,在变量名称前加上两个下划线 (`__`) 即可。这些变量仅能在内部访问,外部无法直接读取或修改: ```python class ExampleClass: def __init__(self, value): self.__private_var = value # 定义了一个名为 private_var 的私有属性 def get_private(self): return self.__private_var # 访问私有属性的方式之一 def set_private(self, new_value): self.__private_var = new_value # 修改私有属性值的一种方式 ``` 当尝试从外直接访问此成员时会发生错误,因为它们被设计成可见于外界: ```python obj = ExampleClass(10) print(obj.get_private()) # 输出: 10 # 下面这条语句会引发 AttributeError 错误 # print(obj.__private_var) ``` 需要注意的是,虽然这种命名约定使得变量看起来像是真正的“私有的”,但实际上只是进行了简单的重命名处理(称为 name mangling),从而增加了间接性和保护程度[^3]。 对于复杂的应用场景来说,建议尽可能地在 `__init__` 函数中完成所有必要的初始化操作,包括但限于设置初始状态、分配资源以及执行任何必需的一次性配置任务。这样做仅有助于保持代码清晰易懂,而且可以减少潜在的逻辑错误风险[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值