python高阶用法(持续更新)

1. 装饰器

用户验证

from functools import wraps
 
def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            authenticate()
        return f(*args, **kwargs)
    return decorated

@requires_auth
def addition_func(x):
   """Do some math."""
   return x + x

其中@wraps(f) 是因为 这里的函数被decorated替代了。它重写了我们函数的名字和注释文档(docstring)。

@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

带参数的装饰器
记录log

from functools import wraps
 
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as opened_file:
                # 现在将日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator
 
@logit()
def myfunc1():
    pass

2. super继承

描述
super() 函数是用于调用 父类(超类) 的一个方法。

super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

代码一:

class A:
  def __init__(self):
    print("Enter A")
    print("Leave A")
class B(A):
  def __init__(self):
    print("Enter B")
    A.__init__(self)
    print("Leave B")
class C(A):
  def __init__(self):
    print("Enter C")
    A.__init__(self)
    print("Leave C")
class D(A):
  def __init__(self):
    print("Enter D")
    A.__init__(self)
    print("Leave D")
class E(B, C, D):
  def __init__(self):
    print("Enter E")
    B.__init__(self)
    C.__init__(self)
    D.__init__(self)
    print("Leave E")

E()

结果为:

Enter E
Enter B
Enter A
Leave A
Leave B
Enter C
Enter A
Leave A
Leave C
Enter D
Enter A
Leave A
Leave D
Leave E
其中父类的中的 Enter A和Leave A 被调用了3遍。
class A:
  def __init__(self):
    print("Enter A")
    print("Leave A")
class B(A):
  def __init__(self):
    print("Enter B")
    super(B, self).__init__()
    print("Leave B")
class C(A):
  def __init__(self):
    print("Enter C")
    super(C, self).__init__()
    print("Leave C")
class D(A):
  def __init__(self):
    print("Enter D")
    super(D, self).__init__()
    print("Leave D")
class E(B, C, D):
  def __init__(self):
    print("Enter E")
    super(E, self).__init__()
    print("Leave E")
E()

结果为:

Enter E
Enter B
Enter C
Enter D
Enter A
Leave A
Leave D
Leave C
Leave B
Leave E
其中父类的中的 Enter A和Leave A 只被调用了一遍。
所以 在super机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照MRO(Method Resolution Order):方法解析顺序 进行的。

3. @property装饰器

Python内置的@property装饰器就是负责把一个方法变成属性的

装饰器(decorator)可以给函数动态加上功能,对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的。

利用@property还可以只定义 只读 属性,既只定义getter方法;

setter方法可以认为是 可写 属性

class Person(object):

    def __init__(self, name, age):
        self.__name = name
        self._age = age

    # 访问器 - getter方法
    @property
    def name(self):
        return self.__name

    # 访问器 - getter方法
    @property
    def age(self):
        return self._age

    # 修改器 - setter方法
    @age.setter
    def age(self, age):
        self._age = age

    # 修改器 - setter方法
    @name.setter
    def name(self, name):
        self.__name = name



def main():
    person = Person('王大锤', 12)
    print(person.name)
    print(person.age)

    person.name = 'zzk'
    person.age = '25'
    print(person.name)
    print(person.age)
D:\PycharmProjects\untitled\venv\Scripts\python.exe D:/PycharmProjects/untitled/test.py
王大锤
12
zzk
25

在别的语言中的理解

定义一个property,在编译期间,编译器会生成实例变量,getter方法、setter方法,这些方法是通过自动合成(autosynthesize)的方式生成并添加到类中。
实际上,一个类经过编译后,会生成变量列表ivar_list,方法列表,method_list。每添加一个属性,在变量列表ivar_list会添加对应的变量,如_name,在方法列表method_list中会添加对应的setter和getter方法。

4. slots 方法(魔法)

首先,我们先理解一下动态语言与静态语言的一个不同:

动态语言:可以在运行的过程中,修改代码
静态语言:编译时已经确定好代码,运行过程中不能修改

python是一个动态语言。如果我们想要限制class运行后的实例属性,就需要__slots__方法

class Slots(object):
    __slots__ = ("name", "gilrfirend")

    def __init__(self):
        self.name = 'zzk'


slote = Slots()
print(slote.name)
slote.gilrfirend = "lyw"
print(slote.gilrfirend)
slote.age =25
print(slote.age)

没有在__slote__中的属性会报错 如:

/usr/local/bin/python3.6 /home/dysec/zzk-word/test.py
zzk
lyw
Traceback (most recent call last):
  File "/home/dysec/zzk-word/test.py", line 13, in <module>
    slote.age =25
AttributeError: 'Slots' object has no attribute 'age'

注意(slots 方法不能继承):

使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

class Slots(object):
    __slots__ = ("name", "gilrfirend")

    def __init__(self):
        self.name = 'zzk'


class TestSlote(Slots):
    def __init__(self):
        pass


a = TestSlote()
a.age = 'zzk'
print(a.age)

#结果
/usr/local/bin/python3.6 /home/dysec/zzk-word/test-zzk/day002.py
zzk

Process finished with exit code 0

如果父类存在__dict__属性,则其子类将继承__dict__;此时,即使该子类包含了__slots__属性,该子类的实例依然可以任意添加变量。


class Slots(object):
    def __init__(self):
        self.name = None

class TestSlote(Slots):
    __slots__ = ("age", "gilrfirend")
    def __init__(self):
        pass

a = TestSlote()
a.age = '25'
print(a.age)
a.name = 'zzk'
print(a.name)

#结果
/usr/local/bin/python3.6 /home/dysec/zzk-word/test-zzk/day002.py
25
zzk

Process finished with exit code 0


你可能感兴趣的:(python高阶用法(持续更新))