Python知识点收集

带下划线的变量和函数的意义

  • 变量(函数类似)
- 前带单下划线'_'的变量,是一个'私有变量'(语义化),只用于类内部使用,实例还是可以访问到这个变量

- 前带双下划线'__'的变量,是一个'私有变量'(真正的),只用于类内部使用,实例不可以访问到这个变量
    - 其实如果想强行访问,也是可以的...

- '__xxx__':属于python底层代码,一般无需理会

- 测试

class Demo(object):
    # 定义两个私有属性
    _test = '123'
    __number = 456

d = Demo()
print(d._test) # 正常访问
print(d.__number) # 报错

你的说法基本正确,但有一些细节需要补充和修正。让我详细解释一下:

单下划线 _variable(保护成员)

class MyClass:
    def __init__(self):
        self.public_var = "public"      # 公共变量
        self._protected_var = "protected"  # 保护变量
    
    def _protected_method(self):
        return "这是一个保护方法"

obj = MyClass()
print(obj.public_var)        # ✅ 可以访问
print(obj._protected_var)    # ✅ 可以访问(但不建议)
print(obj._protected_method()) # ✅ 可以访问(但不建议)

特点:

  • 只是约定俗成的"保护"成员
  • 实例确实可以直接访问
  • 主要用于提示开发者"这是内部使用,不建议外部直接访问"

双下划线 __variable(名称修饰)

class MyClass:
    def __init__(self):
        self.__private_var = "private"  # 私有变量
        self.public_var = "public"
    
    def __private_method(self):
        return "这是一个私有方法"
    
    def get_private_var(self):
        return self.__private_var  # 类内部可以正常访问

obj = MyClass()

# 直接访问会报错
print(obj.public_var)        # ✅ 可以访问
# print(obj.__private_var)   # ❌ AttributeError
# print(obj.__private_method()) # ❌ AttributeError

# 通过类内部方法访问
print(obj.get_private_var()) # ✅ "private"

# 强行访问(名称修饰后的名字)
print(obj._MyClass__private_var)    # ✅ "private"
print(obj._MyClass__private_method()) # ✅ "这是一个私有方法"

名称修饰规则:

  • __variable 会被Python自动重命名为 _类名__variable
  • 这就是"强行访问"的原理

更完整的例子

class BankAccount:
    def __init__(self, balance):
        self.__balance = balance  # 真正的私有变量
        self._account_type = "savings"  # 保护变量
    
    def deposit(self, amount):
        self.__balance += amount
    
    def get_balance(self):
        return self.__balance
    
    def __validate_amount(self, amount):
        return amount > 0

account = BankAccount(1000)

# 推荐方式
print(account.get_balance())  # ✅ 1000
account.deposit(500)
print(account.get_balance())  # ✅ 1500

# 不推荐但可行
print(account._account_type)  # ✅ "savings"(保护成员)

# 直接访问私有成员会失败
# print(account.__balance)    # ❌ 错误

# 强行访问(不推荐在生产代码中使用)
print(account._BankAccount__balance)  # ✅ 1500

总结

你的理解基本正确:

  • _variable - 保护成员,实例可访问但不建议
  • __variable - 私有成员,实例不能直接访问
  • ✅ 可以通过名称修饰后的名字强行访问
  • ❌ 但"真正的私有变量"这个说法不完全准确,因为Python中没有真正的私有,只是通过名称修饰实现了类似效果

最佳实践:

  • 使用单下划线表示"保护成员"
  • 使用双下划线表示"私有成员"
  • 通过公共方法访问和修改私有数据
  • 避免直接使用名称修饰后的名字访问

python 另类写法

  • obj.dict: 把 init()中的赋值,打包成dict
class MyResponse():
    
    def __init__(self):
        self.status = 200
        self.msg = None

    @property
    def get_dict(self):
        return self.__dict__

res = MyResponse()
print(res.get_dict) # {'status': 200, 'msg': None}

py解释器阅读的顺序自上而下

- 例子1,不会报错,因为bar已经被加载了

def foo():
    print('from foo')
    bar()

def bar(): # 已经被解释器自上而下,加载到内存
    print('from bar')

foo()  # 不会报错

- 例子2,会报错,因为bar还没加载到内存

def foo():
    print('from foo')
    bar()

foo()  # 报错

def bar():
    print('from bar')

nonlocal 关键字

  • 在嵌套函数中,修改上层函数的变量值

    • 在函数内部定义的变量,默认只在当前函数内部生效
      而无法影响外层函数的变量

    • 使用 nonlocal 关键字,就可以修改外层函数的变量

def myfunc1():
  x = "Bill"
  def myfunc2():
    # nonlocal x
    x = "hello"
  myfunc2()
  return x

print(myfunc1()) # Bill(内层函数变量此时无法修改外层)

def myfunc1():
  x = "Bill"
  def myfunc2():
    nonlocal x
    x = "hello"
  myfunc2()
  return x

print(myfunc1()) # hello(外层函数的变量值被修改了)

什么是闭包函数

- 闭 : 指的是定义在函数内部的函数
- 包 : 闭函数引用了一个来自外层函数的变量
- '总结一句话来说' : 定义在函数内部的函数, 并且该函数包含对外部函数作用域中名字的引用,该函数就称为闭包函数
def outter():
     name='egon'
     def inner():
         print('my name is %s' %name)
     return inner  #注意不能加括号

f=outter() # 返回inner对象
# 注意 : 作用域在函数定义阶段就规定死了, 与调用的位置无关
  • 闭包函数内部,变量的查找顺序
- 先从闭包函数内部找,没有就从外部函数找,最后在函数外面找
- 分别注释x,测试效果

x = 100
def outter():
    x = 2
    def inner():
        x=1
        print('from inner', x)

    return inner

demo = outter()
demo()
  • 功能-获取网页源码演示
### 普通写法: 将"url"以参数的形式传入(也是最常用)
import requests

def get(url):
    response=requests.get(url)下载
    if response.status_code == 200:
        print(response.text)

get('https://www.baidu.com')
get('https://www.python.org')


### 闭包写法
import requests    

def outter(url):
    def get(): # 内层函数引用外层函数的参数,该参数就称为'包'
        response=requests.get(url)
        if response.status_code == 200:
            print(response.text)
    return get
    
baidu = outter('https://www.baidu.com')
baidu()


  • 闭包的用途: 为装饰器作'预备',即不影响原函数的逻辑的前提下,再添加新的功能
import requests    

def outter(url):
    def get(): # 内层函数引用外层函数的参数,该参数就称为'包'
        response=requests.get(url)
        if response.status_code == 200:
            print(response.text)
    '''
    这里可以添加判断,比如url若不符合url正则表达式,就抛异常,从而不再返回 get函数对象
    达到阻止执行get()的逻辑
    '''
    return get
    
baidu = outter('https://www.baidu.com')
baidu()

什么是装饰器

- 器 : 就是工具
- 装饰 : 就是添加新功能
- '总结一句话来说' : 就是定义一个函数, 用该函数去为其他函数添加新功能

- 应用场景: 不修改原函数的源码,不修改原函数的调用方式
  在此基础上,给该函数增加新功能

- 它是闭包函数的升级版...
  • 无参数装饰器写法(在闭包里面,return func函数的计算结果)

def outter(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper

@outter  # 把 test函数对象当参数,传入
def test():
    print('我是test方法里面的内容')
    return '我是test方法最终返回的内容'

wrapper_func_obj = outter(test) # 返回内层函数对象
print(wrapper_func_obj()) # 执行内层函数逻辑: 我是test方法里面的内容 我是test方法最终返回的内容
  • 计算程序执行时间示例
import time
def timmer(func):
    print('装饰器正在执行')
    def wrapper(*args,**kwargs):
        start_time=time.time()        #开始时间
        res=func(*args,**kwargs)
        stop_time=time.time()         #结束时间
        print(stop_time-start_time)   #使用时间
        return res
    return wrapper

@timmer
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122

index()       # 调用该怎么调还是怎么调

'''
- 执行结果:
	装饰器正在执行
    welcome to index page
    1.0059232711791992

'''

继承需注意的Meta问题

  • 子类继承的时候,如果重写Meta配置项,所有的配置项都会被刷新,没写的项并不会继承父类

    意思就是,该项就没有掉了,程序不会再从父类去找

class Foo(object):
    class Meta:
        xxx = 123
        yyy = 456

class Bar(Foo): # 继承
    class Meta:
        xxx = 100

f = Foo() # f 有 xxx,yyy两个配置项,值分别为 123 和 456
b = Bar() # b 只有 xxx配置项,值为 100;'yyy'配置项是不存在的

print('程序运行结束!')

assert 的用法

  • 通俗理解: 把assert看成if,若条件成立,则正常执行后续代码;否则触发AssertionError异常(可以自定义异常消息)
def test_case(x):
	# 如果条件成立,则执行正常执行后续的语句,不会触发异常
    assert x > 0, "x is not greater than 0"
    return x * 2
    
print(test_case(6)) # 12


def test_case(x):
	# 如果条件不成立,触发异常
    assert x > 0, "x is not greater than 0"
    return x * 2
    
print(test_case(-1)) # AssertionError: x is not greater than 0
posted @ 2022-12-27 13:40  清安宁  阅读(27)  评论(0)    收藏  举报