1. 访问权限设置规则
与 C++、C#、Java 等语言相似,Python 支持将类的属性和方法设置成特定的访问权限,但不是通过关键字区分,而是通过下划线来区别的:下划线具有五大作用
- 单前导下划线:告知变量或者方法是用于类的内部使用的,但不是强制性的(在类的外部使用通常是不会报错),但是也有例外:
(如果使用通配符从模块中导入所有名称,则Python不会导入带有前导下划线的名称)
# This is my_module.py:
def external_func():
return 23
def _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 = 11
self._bar = 23
self.__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**`关键字,不会报错。
```python
class Student:
a = 1
name = "wnagzhiwei"
age = 23
def __init__(self,name,age):
self.name = name
self.age = age
@classmethod
def writework(cls):
global a
a = 10
print(cls.age)
print(cls.name)
print(a)
s1 = cls("Tom",18)
print(s1.name,s1.age)
def eat(self):
print(Student.name+"在吃饭")
global a
a = 20
print(a)
pass
s = Student("jack",20)
s.writework()
s.eat()
23
wnagzhiwei
10
Tom 18
wnagzhiwei在吃饭
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 = name1
self.age = age1
def work(self): pass
在实例化Student的时候会执行最后一个init()。即实例化时,s = Student()会报错,显示没有传入参数。
java类中创建多个构造方法,调用时会进行方法的重载,那么python能否创建多个构造方法实现重载呢?<br />其实也是可以的,但是一般使用类方法进行
<a name="oUcWm"></a>
## 3.2 实例方法
实例方法中的第一个参数代表类的实例对象,默认命名为self(其他名字也可以),方法内部可以使用类变量和类方法:`**类名.类属性、类名.类方法**`**。**在调用实例方法时,推荐使用`**对象.实例方法**`,不推荐使用`**类.实例方法**`。
```python
class Student:
a = 1
name = "wnagzhiwei"
age = 23
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print(self.name+"在吃饭")
pass
s = Student("jack",20)
# Student.eat()会报错
Student.eat(s) # 传入对象就不会报错。在类的内部调用时,直接Student.ea(self)
s.eat()
3.3 类方法
被装饰器**@classmethod**
修饰,第一个参数为类的名字,默认命名为**cls**
(起其他名字也可以),方法内部不能使用实例属性和实例方法。**self**
则代表类的一个实例对象,**cls**
代表类本身,在类的方法中可以通过**cls**
创建一个实例化对象,进行实例属性的调用。
使用场景:类方法用于模拟java定义多个构造函数的情况。
调用方式:
**类名.类方法名()**
**实例对象.类方法名()**
class Student:
a = 1
name = "wnagzhiwei"
age = 23
def __init__(self):
pass
@classmethod
def override(cls,name,age):
s = cls()
s.name = name
s.age = age
return s
def 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类,所以都是新式类