1. 访问权限设置规则
与 C++、C#、Java 等语言相似,Python 支持将类的属性和方法设置成特定的访问权限,但不是通过关键字区分,而是通过下划线来区别的:下划线具有五大作用
- 单前导下划线:告知变量或者方法是用于类的内部使用的,但不是强制性的(在类的外部使用通常是不会报错),但是也有例外:
(如果使用通配符从模块中导入所有名称,则Python不会导入带有前导下划线的名称)
# This is my_module.py:def external_func():return 23def _internal_func():return 42>>> from my_module import *>>> external_func()23>>> _internal_func()NameError: "name '_internal_func' is not defined"
- 双前导下划线:变量和方法只能在类的内部被调用,不能在类的外部被调用,而且子类不能继承。原理:解释器执行到的时候,会更改变量或者方法的名称,为了在类被扩展的时候产生冲突。
```python
class Test:
def init(self):
self.foo = 11self._bar = 23self.__baz = 23
t = Test() dir(t) [‘Testbaz’, ‘class‘, ‘delattr‘, ‘dict‘, ‘dir‘, ‘doc‘, ‘eq‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘gt‘, ‘hash‘, ‘init‘, ‘le‘, ‘lt‘, ‘module‘, ‘ne‘, ‘new‘, ‘reduce‘, ‘reduceex‘, ‘repr‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘subclasshook‘, ‘weakref‘, ‘_bar’, ‘foo’]
此时,baz在内部的名称是_Testbaz。
<a name="WzsN8"></a># 2. 变量/属性<a name="VQgXk"></a>## 2.1 变量的创建python变量不需要声明数据类型,在首次赋值的时候创建变量。<a name="ejFC0"></a>## 2.2 变量的分类类中的变量有类变量、实例变量,同时为了更好的理解,本节将全局变量,局部变量一起讲解。| | 位置 | 调用 || --- | --- | --- || 全局变量 | 模块内,所有函数外,所有类外 | 类、函数中需要使用全局变量时,需要在类/函数中定义global || 局部变量 | 函数内、class的方法(类方法、静态方法、实例方法)内,且变量前面没有修饰 | || 类变量 | class内,不在class的任何方法内 | `**类名.变量名**` || 实例变量 | class的方法内,使用self修饰 | `**self.变量名**` |实例变量与类变量的相关问题:1. `**实例变量.变量名、self.变量名**` 既可以调用类变量也可以调用实例变量,但是当类变量与实例变量同名时,则调用的是实例变量,此时需要调用类属性则必须使用`**类名.类属性**`1. 其实在实例方法中调用类方法还可以通过`**global**`关键字,不会报错。```pythonclass Student:a = 1name = "wnagzhiwei"age = 23def __init__(self,name,age):self.name = nameself.age = age@classmethoddef writework(cls):global aa = 10print(cls.age)print(cls.name)print(a)s1 = cls("Tom",18)print(s1.name,s1.age)def eat(self):print(Student.name+"在吃饭")global aa = 20print(a)passs = Student("jack",20)s.writework()s.eat()23wnagzhiwei10Tom 18wnagzhiwei在吃饭20
3. 类中的方法
其实我们学习面向对象的时候,可以与java面向对象进行对比,这样能够学习的更加高效。
在调用方法的时候,一般都是用对象.方法
3.1 构造方法
python中的构造方法**__init__()**随着实例对象的创建而调用(在面试时拿来和**__new__()**,详情请点击)。构造方法特点有:
- 一个类中只能有一个
**__init__()**,创建多个的话,不会报错,但是只会执行最后一个。 - 构造方法一般用来初始化实例变量,最好使用
**self.变量名**来创建实例变量。 ```python class Student(): sum1 = 0 name = “ “ age = 0 def init(self):
def init(self,name1,age1):print("你好,python")
self.name = name1self.age = age1
def work(self): pass
在实例化Student的时候会执行最后一个init()。即实例化时,s = Student()会报错,显示没有传入参数。
java类中创建多个构造方法,调用时会进行方法的重载,那么python能否创建多个构造方法实现重载呢?<br />其实也是可以的,但是一般使用类方法进行<a name="oUcWm"></a>## 3.2 实例方法实例方法中的第一个参数代表类的实例对象,默认命名为self(其他名字也可以),方法内部可以使用类变量和类方法:`**类名.类属性、类名.类方法**`**。**在调用实例方法时,推荐使用`**对象.实例方法**`,不推荐使用`**类.实例方法**`。```pythonclass Student:a = 1name = "wnagzhiwei"age = 23def __init__(self,name,age):self.name = nameself.age = agedef eat(self):print(self.name+"在吃饭")passs = Student("jack",20)# Student.eat()会报错Student.eat(s) # 传入对象就不会报错。在类的内部调用时,直接Student.ea(self)s.eat()
3.3 类方法
被装饰器**@classmethod**修饰,第一个参数为类的名字,默认命名为**cls**(起其他名字也可以),方法内部不能使用实例属性和实例方法。**self**则代表类的一个实例对象,**cls**代表类本身,在类的方法中可以通过**cls**创建一个实例化对象,进行实例属性的调用。
使用场景:类方法用于模拟java定义多个构造函数的情况。
调用方式:
**类名.类方法名()****实例对象.类方法名()**class Student:a = 1name = "wnagzhiwei"age = 23def __init__(self):pass@classmethoddef override(cls,name,age):s = cls()s.name = names.age = agereturn sdef eat(self):print(self.name + "在吃饭")s1 = Student.override("Tom",18)s1.eat()s2 = Student()print(s2.name)
3.4 静态方法
静态方法被装饰器**@staticmethod**修饰,第一个参数既不代表实例对象本身,也不代表类本身。静态方法的调用可以是**类名.静态方法名、对象名.静态方法名**3.5 抽象方法
抽象方法不能单独的使用**@abstractmethod**,必须先导入abc模块,因为**abstractmethod类装饰器**不在builtin模块中(抽象方法是在后面添加的特性)。abc模块是**abstract base classes**,里面有许多装饰器,但是3.3开始只保留了abstractmethod装饰器函数。
3.6 Property属性方法
属性方法被装饰器**@property**修饰,将类的方法变为属性,调用时,会被视为属性。新式类与旧式类的用法会不同。
3.7 类的其他魔法方法
3.8 新式类与旧式类
python2.3之前的类都是旧式类,之后有了新式类,继承了object的都是新式类,没有继承的就是旧式类
python3.x之后,所有的类默认继承了object类,所以都是新式类
