class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def myfunc(self):
print("Hello my name is " + self.name)
p1 = Person("Bill", 63)
p1.myfunc()
class Person:
name = "person"
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("Bill", 63)
print(Person.name)
print(p1.name)
结果
person
Bill
class User:
def __getattribute__(self, item):
if (item == "age"):
return 0
def __getattr__(self, item):
if (item == "age"):
return 99
class Person:
def __init__(self, name, age):
self.__name = name
self.age = age
def getName(self):
return self.__name
p1 = Person("Bill", 63)
print(p1.age)
print(p1.getName()) # 可以通过方法访问
print(p1._Person__name) # 这种方式依旧可以访问
print(p1.__name) # 这种方式是访问不了的
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@property
def sex(self):
return "男"
p1 = Person("小明", 63)
print(p1.name)
print(p1.sex)
结果
小明
男
可以看出
动态属性就和vue的计算属性一样,可以像访问属性一样访问方法。
import numbers
# 数据描述符
class IntField:
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
if not isinstance(value, numbers.Integral):
raise ValueError("need int value")
self.value = value
def __delete__(self, instance):
pass
# 非数据描述符
class NoDataField:
def __get__(self, instance, owner):
return 4
class User:
age = IntField()
if __name__ == "__main__":
u = User()
u.age = 10
这样如果赋值的时候不是数字,就会报错
这样就可以限制参数的类型了。
获取属性的两种方式
u = User()
u.age
# 等效于
getattr(u, "age")
获取属性的优先级顺序
类
的__getattribute__
类或者基类
中定义的数据描述符
实例
中的属性 user.__dict__["age"]
类
中的非数据描述符
类或基类
的属性 User.__dict__["age"]
类
中的__getattr__
方法
AttributeError
class User:
def __init__(self, name, age):
self.__name = name
self.age = age
u = User("小明", 16)
print(u.__dict__) # 查看实例的属性
print(dir(u)) # 只能看属性的名称,不能看值,但是看到的属性比较全
print(User.__dict__) # 查看类的属性
print(dir(User)) # 查看类的属性
结果
{'_User__name': '小明', 'age': 16}
['_User__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age']
{'__module__': '__main__', '__init__': <function User.__init__ at 0x017BD100>, '__dict__': <attribute '__dict__' of 'User' objects>, '__weakref__': <attribute '__weakref__' of 'User' objects>, '__doc__': None}
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
class User:
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
def __init__(self, name, age):
self.__name = name
self.age = age
u = User("小明", 16)
print(getattr(u, "age"))
注意
__new__
是用来把类生成对象,实在创建对象之前调用,如果没有返回,则__init__
不会调用。__init__
是用来给对象初始化属性的。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def get_age(self):
return self.age
p1 = Person("小明", 63)
print(p1.get_age())
class Person:
def __init__(self, name, age):
self.__name = name
self.age = age
@staticmethod
def getName():
return "123"
print(Person.getName()) # 可以通过方法访问
p1 = Person("Bill", 63)
print(p1.getName()) # 可以通过方法访问
注意
静态方法可以用类调用,也可以用示例调用。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def getPerson(cls, name, age):
return cls(name, age)
p1 = Person.getPerson("小明", 63)
print(p1.name)
注意
类方法的主要好处在于生成类的实例的时候不用写类名,这样一旦类名发生变化,类方法中不用修改代码。
if (p1 is None):
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("小明", 63)
print(isinstance(p1, Person))
a = object()
b = a
del a
print(b)
print(a)
结果
<object object at 0x017265B0>
Traceback (most recent call last):
File "main.py", line 5, in <module>
print(a)
NameError: name 'a' is not defined
我们会发现a被删除后,b依旧没有被销毁,这是因为对应每次被引用都会计数器+1,只有计数器为0,才会销毁。
class Student(Person):
Python的类是可以多继承的
class C(A,B):
注意
开发时尽量不要用多继承
class A:
def __init__(self) -> None:
print("A")
class B(A):
def __init__(self) -> None:
super().__init__()
print("B")
if __name__ == "__main__":
b = B()
结果
A
B
class A:
def __init__(self) -> None:
print("A")
super().__init__()
class B(A):
def __init__(self) -> None:
print("B")
super().__init__()
class C(A):
def __init__(self) -> None:
print("C")
super().__init__()
class D(B, C):
def __init__(self) -> None:
print("D")
super().__init__()
print(D.__mro__)
d = D()
结果
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
D
B
C
A
可以看出
调用顺序是按照MRO的算法来调用的 使用
类.__mro__
可以查看调用顺序 属性和方法都是这个规则
import abc
class A(metaclass=abc.ABCMeta):
@abc.abstractmethod
def say(self):
pass
class B(A):
def __init__(self):
pass
def say(self):
pass
if __name__ == "__main__":
b = B()
注意
如果B不实现A的抽象方法就会报错。
def create_class01(ctype):
if (ctype == "user"):
class User:
name = "小明"
def say(self):
print(f"{self.name} say")
return User
def create_class02(ctype):
def say(self):
print(f"{self.name} say")
if (ctype == "user"):
User = type("User", (), {"name": "小明", "say": say})
return User
if __name__ == "__main__":
User = create_class02("user")
u = User()
print(u.name)
u.say()
结果
小明
小明 say